Рельсы: использование больше / меньше, чем с оператором where
Я пытаюсь найти всех пользователей с ID больше, чем 200, но у меня возникли некоторые проблемы с конкретным синтаксисом.
User.where(:id > 200)
и
User.where("? > 200", :id)
оба ошиблись.
какие предложения?
7 ответов:
я только проверил это в Rails 4, но есть интересный способ использовать диапазон с
whereхэш, чтобы получить такое поведение.User.where(id: 201..Float::INFINITY)будет генерировать SQL
SELECT `users`.* FROM `users` WHERE (`users`.`id` >= 201)то же самое можно сделать менее чем с
-Float::INFINITY.я только что опубликовал аналогичный вопрос, спрашивающий об этом с датами так.
>=vs>чтобы избежать людей, которые должны копать и следовать комментарии разговор Вот основные моменты.
метод выше только создает
>=запрос и не a>. Есть много способов справиться с этой альтернативой.для дискретных чисел
вы можете использовать
number_you_want + 1стратегия, как и выше, где я заинтересован в пользователях сid > 200но на самом деле искатьid >= 201. Это хорошо для целых чисел и чисел, где вы можете увеличить на одну единицу интерес.если у вас есть число, извлеченное в хорошо названную константу, это может быть самым простым для чтения и понимания с первого взгляда.
перевернутая логика
мы можем использовать тот факт, что
x > y == !(x <= y)и использовать где не цепь.User.where.not(id: -Float::INFINITY..200)который генерирует SQL
SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))это занимает дополнительную секунду, чтобы прочитать и рассуждать о том, но будет работать для не дискретных значений или столбцов, где вы не можете использовать
+ 1стратегии.Arel таблица
если вы хотите получить фантазии, вы можете использовать
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... Подробнее в этой статье.
Если вы хотите более интуитивное письмо, он существует драгоценный камень под названием squeel это позволит вам написать свою инструкцию следующим образом:
User.where{id > 200}обратите внимание на символы "скобки" { } и
idпросто текст.все, что вам нужно сделать, это добавить squeel в свой Gemfile:
gem "squeel"Это может облегчить вашу жизнь много при написании сложного оператора SQL в Ruby.
у меня часто возникает эта проблема с полями дат (где операторы сравнения очень распространены).
чтобы подробнее остановиться на ответе Михая, который я считаю солидным подходом.
к моделям вы можете добавить области, как это:
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'))огромным преимуществом такого подхода является (a) он позволяет создавать запросы из разных областей и (b) позволяет избежать конфликтов псевдонимов при подключении к одной и той же таблице дважды, так как arel_table будет обрабатывать эту часть генерации запроса.