Я пытаюсь найти всех пользователей с идентификатором больше 200, но у меня проблемы с конкретным синтаксисом.
User.where(:id > 200)
а также
User.where("? > 200", :id)
оба потерпели неудачу.
Какие-либо предложения?
ruby-on-rails
syntax
where
Адам Темплтон
источник
источник
?
, а не встраивание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)
.Лучшее использование - создать область видимости в пользовательской модели.
where(arel_table[:id].gt(id))
источник
Rails 6.1+
В 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, где можно найти больше примеров.
источник
Арел твой друг:
User.where(User.arel_table[:id].gt(200))
источник
Если вы хотите более интуитивного написания, существует драгоценный камень под названием 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 будет обрабатывать эту часть генерации запроса.
источник
Короче:
User.where("id > 200")
источник
where("id > ?", 200)
синтаксис). Этого не добиться.