Рельсы: использование больше / меньше, чем с оператором 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 будет обрабатывать эту часть генерации запроса.