Rails:使用大于/小于where语句

时间:2012-07-03 19:16:54

标签: ruby-on-rails syntax where

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

User.where(:id > 200) 

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

都失败了。

有什么建议吗?

10 个答案:

答案 0 :(得分:229)

试试这个

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

答案 1 :(得分:94)

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

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

将生成SQL

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

-Float::INFINITY相比,可以做的相同。

我刚刚发布了一个类似的问题,询问是否使用日期here on SO进行此操作。

>= vs >

为避免人们不得不深入挖掘并遵循评论对话,这里是重点。

上述方法仅生成>=查询, a >。有很多方法可以处理这种替代方案。

对于离散数字

您可以使用上述number_you_want + 1策略,我对id > 200用户感兴趣,但实际上会查找id >= 201。这适用于整数和数字,您可以通过单个兴趣单位递增。

如果您将数字提取到一个名为常数的常数中,这可能是最容易阅读和理解的。

倒置逻辑

我们可以使用x > y == !(x <= y)这一事实并使用where not chain。

User.where.not(id: -Float::INFINITY..200)

生成SQL

SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))

这需要额外一秒的时间来阅读和推理,但适用于非离散值或无法使用+ 1策略的列。

Arel table

如果您想获得幻想,可以使用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..即可。更多信息in this blog post

答案 2 :(得分:21)

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

中创建范围

答案 3 :(得分:11)

更新

Rails核心团队决定暂时撤消此更改,以便对其进行详细讨论。有关更多信息,请参见this commentthis 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) 

这里是a link to PR,您可以在其中找到更多示例。

答案 4 :(得分:5)

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

import Tkinter as tk
import guiOpMenu2

class Omenu(object):

    def __init__(self):
        self.app = tk.Tk()
        self.app.title('test1')
        self.OpMenu()
        self.btn()

    def OpMenu(self):
        self.op = tk.StringVar()
        self.opt =['1', '2']
        self.men = tk.OptionMenu(self.app, self.op, *self.opt)
        self.men.pack()

    def btn(self):
        self.btn_btn = tk.Button(self.app, text='newGui', command=self.test)
        self.btn_btn.pack()

    def test(self):
        win = guiOpMenu2.Omenu2(self.app)

win = Omenu()
win.app.mainloop()

注意&#39;支撑&#39;字符{}和User.where{id > 200} 只是一个文字。

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

id

在Ruby中编写复杂的SQL语句时,这可能会大大减轻您的生活。

答案 5 :(得分:3)

Arel是你的朋友。

  

User.where(User.arel_table [:ID]。GT(200))

答案 6 :(得分:1)

我经常遇到日期字段的问题(比较运算符很常见)。

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

答案 7 :(得分:0)

另一种可能的可能性是...

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)

答案 8 :(得分:0)

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

# => 2.6
User.where(id: 201..)
# < 2.6
User.where(id: 201..Float::INFINITY)

答案 9 :(得分:-2)

更短的:

User.where("id > 200")