185

我正在尝试查找 id 大于 200 的所有用户,但我在使用特定语法时遇到了一些问题。

User.where(:id > 200) 

User.where("? > 200", :id) 

都失败了。

有什么建议么?

4

10 回答 10

316

试试这个

User.where("id > ?", 200) 
于 2012-07-03T19:22:13.730 回答
175

最先进的

Ruby 2.7 引入了beginless 范围>,这使得指定<及其包含的表亲 (>=<=) 变得更加容易。

User.where(id: 200..).to_sql
  => "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"id\" >= 200"
# There is no difference w/ a non-inclusive endless range (e.g. `200...`)

User.where(id: ..200).to_sql
  => "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"id\" <= 200"
User.where(id: ...200).to_sql
  => "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"id\" < 200"

这也适用于时间戳!

User.where(created_at: 1.day.ago..).to_sql
  => "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"created_at\" >= '2021-09-12 15:38:32.665061'"
User.where(created_at: ..1.day.ago).to_sql
  => "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"created_at\" <= '2021-09-12 15:38:37.756870'"

原始答案和更新

我只在 Rails 4 中对此进行了测试,但是有一种有趣的方法可以使用带有where哈希的范围来获得这种行为。

User.where(id: 201..Float::INFINITY)

将生成 SQL

SELECT `users`.* FROM `users`  WHERE (`users`.`id` >= 201)

也可以用少于 with 来做同样的事情-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 发布(2018 年 12 月 25 日),您将能够使用新的无限范围语法!而不是201..Float::INFINITY你将能够只写201... 此博客文章中的更多信息。

于 2014-05-29T14:51:36.750 回答
24

更好的用法是在用户模型中创建范围where(arel_table[:id].gt(id))

于 2016-08-08T21:07:12.847 回答
20

更新

Rails 核心团队决定暂时恢复此更改,以便更详细地讨论它。有关更多信息,请参阅此评论此 PR

我仅出于教育目的而留下我的答案。


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 的链接,您可以在其中找到更多示例。

于 2020-07-21T17:10:10.187 回答
11

Arel 是你的朋友:

User.where(User.arel_table[:id].gt(200))
于 2018-03-20T20:55:59.170 回答
7

另一个奇特的可能性是……

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)
于 2019-07-15T17:47:19.697 回答
6

如果您想要更直观的写作,它存在一个名为squeel的 gem,它可以让您像这样编写指令:

User.where{id > 200}

请注意“大括号”字符 { } 并且id只是一个文本。

您所要做的就是将 squeel 添加到您的 Gemfile 中:

gem "squeel"

在 Ruby 中编写复杂的 SQL 语句时,这可能会让您的生活轻松很多。

于 2015-09-03T08:55:36.270 回答
3

我经常在日期字段中遇到这个问题(比较运算符非常常见)。

进一步详细说明 Mihai 的答案,我认为这是一种可靠的方法。

您可以向模型添加如下范围:

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 将处理查询生成的那部分。

于 2018-03-19T19:42:03.107 回答
0

对于 Ruby 2.6,可以接受以下范围:

# => 2.6
User.where(id: 201..)
# < 2.6
User.where(id: 201..Float::INFINITY)
于 2021-03-24T13:05:09.690 回答
-3

更短:

User.where("id > 200")
于 2017-02-09T00:48:42.500 回答