Я пытаюсь найти всех пользователей с идентификатором более 200, но у меня возникают некоторые проблемы с конкретным синтаксисом.
User.where(:id > 200)
и
User.where("? > 200", :id)
оба отказались.
Любые предложения?
Я пытаюсь найти всех пользователей с идентификатором более 200, но у меня возникают некоторые проблемы с конкретным синтаксисом.
User.where(:id > 200)
и
User.where("? > 200", :id)
оба отказались.
Любые предложения?
Попробуйте это
User.where("id > ?", 200)
Я только протестировал это в 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..
Больше информации в этом посте.
Лучшее использование - создать область в пользовательской модели where(arel_table[:id].gt(id))
Если вы хотите более интуитивно понятное письмо, в нем есть драгоценный камень, называемый squeel, который позволит вам написать свою инструкцию следующим образом:
User.where{id > 200}
Обратите внимание, что символы "скобки" {} и id
являются просто текстом.
Все, что вам нужно сделать, это добавить squeel в ваш Gemfile:
gem "squeel"
Это может облегчить вашу жизнь при написании сложного оператора SQL в Ruby.
Арель твой друг.
User.where(User.arel_table [: ID].gt(200))
У меня часто возникает эта проблема с полями даты (где операторы сравнения очень распространены).
Более подробно остановимся на ответе Михая, который, я считаю, является надежным подходом.
К моделям вы можете добавить такие области:
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 будет обрабатывать эту часть генерации запроса.
Еще одна причудливая возможность...
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)
Короче:
User.where("id > 200")