Rails: использование большего или меньшего, чем с предложением where

Я пытаюсь найти всех пользователей с идентификатором более 200, но у меня возникают некоторые проблемы с конкретным синтаксисом.

User.where(:id > 200) 

и

User.where("? > 200", :id) 

оба отказались.

Любые предложения?

Ответ 1

Попробуйте это

User.where("id > ?", 200) 

Ответ 2

Я только протестировал это в Rails 4, но есть интересный способ использовать диапазон с хешем where для получения такого поведения.

User.where(id: 201..Float::INFINITY)

сгенерирует SQL

SELECT 'users'.* FROM 'users'  WHERE ('users'.'id' >= 201)

То же самое можно сделать для менее чем с -Float::INFINITY.

Я только что опубликовал аналогичный вопрос с просьбой сделать это с датами здесь на SO.

>= против >

Чтобы люди не копались и не следили за комментариями, вот основные моменты.

Метод выше генерирует только запрос >= а не >. Есть много способов справиться с этой альтернативой.

Для дискретных чисел

Вы можете использовать стратегию number_you_want + 1, как описано выше, где меня интересуют пользователи с id > 200 но на самом деле ищут id >= 201. Это хорошо для целых чисел и чисел, где вы можете увеличить на единицу интереса.

Если у вас есть число, извлеченное в хорошо названную константу, это может быть проще всего прочитать и понять с первого взгляда.

Перевернутая логика

Мы можем использовать тот факт, что x > y == !(x <= y) и использовать цепочку where not.

User.where.not(id: -Float::INFINITY..200)

который генерирует SQL

SELECT 'users'.* FROM 'users' WHERE (NOT ('users'.'id' <= 200))

Это займет дополнительную секунду, чтобы прочитать и обдумать, но будет работать для недискретных значений или столбцов, где вы не можете использовать стратегию + 1.

Арель стол

Если вы хотите стать модным, вы можете использовать Arel::Table.

User.where(User.arel_table[:id].gt(200))

сгенерирует SQL

"SELECT 'users'.* FROM 'users' WHERE ('users'.'id' > 200)"

Особенности следующие:

User.arel_table              #=> an Arel::Table instance for the User model / users table
User.arel_table[:id]         #=> an Arel::Attributes::Attribute for the id column
User.arel_table[:id].gt(200) #=> an Arel::Nodes::GreaterThan which can be passed to 'where'

Этот подход поможет вам получить именно тот SQL, который вам интересен, однако не многие люди используют таблицу Arel напрямую и могут посчитать ее запутанной и/или запутанной. Вы и ваша команда будете знать, что лучше для вас.

бонус

Начиная с Rails 5, вы также можете делать это с датами!

User.where(created_at: 3.days.ago..DateTime::Infinity.new)

сгенерирует SQL

SELECT 'users'.* FROM 'users' WHERE ('users'.'created_at' >= '2018-07-07 17:00:51')

Двойной Бонус

После выхода Ruby 2.6 (25 декабря 2018 года) вы сможете использовать новый синтаксис бесконечного диапазона! Вместо 201..Float::INFINITY вы можете просто написать 201.. Больше информации в этом посте.

Ответ 3

Лучшее использование - создать область в пользовательской модели where(arel_table[:id].gt(id))

Ответ 4

Если вы хотите более интуитивно понятное письмо, в нем есть драгоценный камень, называемый squeel, который позволит вам написать свою инструкцию следующим образом:

User.where{id > 200}

Обратите внимание, что символы "скобки" {} и id являются просто текстом.

Все, что вам нужно сделать, это добавить squeel в ваш Gemfile:

gem "squeel"

Это может облегчить вашу жизнь при написании сложного оператора SQL в Ruby.

Ответ 5

Арель твой друг.

User.where(User.arel_table [: ID].gt(200))

Ответ 6

У меня часто возникает эта проблема с полями даты (где операторы сравнения очень распространены).

Более подробно остановимся на ответе Михая, который, я считаю, является надежным подходом.

К моделям вы можете добавить такие области:

scope :updated_at_less_than, -> (date_param) { 
  where(arel_table[:updated_at].lt(date_param)) }

... а затем в вашем контроллере, или где вы используете свою модель:

result = MyModel.updated_at_less_than('01/01/2017')

... более сложный пример с соединениями выглядит так:

result = MyParentModel.joins(:my_model).
  merge(MyModel.updated_at_less_than('01/01/2017'))

Огромное преимущество этого подхода состоит в том, что (а) он позволяет вам составлять запросы из разных областей и (б) избегать коллизий псевдонимов, когда вы дважды присоединяетесь к одной и той же таблице, поскольку arel_table будет обрабатывать эту часть генерации запроса.

Ответ 7

Еще одна причудливая возможность...

User.where("id > :id", id: 100)

Эта функция позволяет создавать более понятные запросы, если вы хотите заменить в нескольких местах, например...

User.where("id > :id OR number > :number AND employee_id = :employee", id: 100, number: 102, employee: 1205)

Это имеет большее значение, чем иметь много ? по запросу...

User.where("id > ? OR number > ? AND employee_id = ?", 100, 102, 1205)

Ответ 8

Короче:

User.where("id > 200")