Я пытаюсь найти всех пользователей с идентификатором больше 200, но у меня проблемы с конкретным синтаксисом.
User.where(:id > 200)
а также
User.where("? > 200", :id)
оба потерпели неудачу.
Какие-либо предложения?
Я пытаюсь найти всех пользователей с идентификатором больше 200, но у меня проблемы с конкретным синтаксисом.
User.where(:id > 200)
а также
User.where("? > 200", :id)
оба потерпели неудачу.
Какие-либо предложения?
Ответы:
Попробуй это
User.where("id > ?", 200)
?
, а не встраивание 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
сопоставители. Для простоты >
я предлагаю использовать >= (number_you_want + 1)
. Если вы действительно хотите убедиться, что это всего лишь >
запрос, вы можете получить доступ к таблице ARel. Каждый класс, наследующий от, ActiveRecord
имеет arel_table
метод получения, который возвращает Arel::Table
для этого класса. Доступ к столбцам в таблице осуществляется с помощью []
метода вроде User.arel_table[:id]
. Это возвращает, что Arel::Attributes::Attribute
вы можете позвонить gt
и пройти 200
. Затем его можно передать в where
. напр User.where(User.arel_table[:id].gt(200))
.
User.where(created_at: 3.days.ago..DateTime::Infinity.new)
.
В Rails 6.1 добавлен новый «синтаксис» для операторов сравнения в where
условиях, например:
Post.where('id >': 9)
Post.where('id >=': 9)
Post.where('id <': 3)
Post.where('id <=': 3)
Итак, ваш запрос можно переписать следующим образом:
User.where('id >': 200)
Вот ссылка на PR, где можно найти больше примеров.
Если вы хотите более интуитивного написания, существует драгоценный камень под названием squeel , который позволит вам написать свою инструкцию следующим образом:
User.where{id > 200}
Обратите внимание на символы "скобки" {} и id
это просто текст.
Все, что вам нужно сделать, это добавить squeel в ваш Gemfile:
gem "squeel"
Это может значительно облегчить вашу жизнь при написании сложных операторов SQL на Ruby.
Еще одна интересная возможность ...
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)
У меня часто возникает эта проблема с полями даты (где операторы сравнения очень распространены).
Чтобы подробнее рассказать об ответе Михая, который, я считаю, является надежным подходом.
К моделям можно добавить такие прицелы:
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 будет обрабатывать эту часть генерации запроса.