我正在尝试查找ID大于200的所有用户,但我在使用特定语法时遇到了一些问题。
User.where(:id > 200)
和
User.where("? > 200", :id)
都失败了。
有什么建议吗?
答案 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 comment和this PR。
我仅出于教育目的而保留答案。
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")