Rails 3使用SQL IN和SQL OR运算符进行ActiveRecord查询

kat*_*ray 16 ruby sql activerecord ruby-on-rails ruby-on-rails-3

我正在使用"where"语法编写Rails 3 ActiveRecord查询,该语法使用SQL IN和SQL OR运算符,并且无法弄清楚如何将它们一起使用.

此代码有效(在我的用户模型中):

Question.where(:user_id => self.friends.ids)
#note: self.friends.ids returns an array of integers
Run Code Online (Sandbox Code Playgroud)

但这段代码

Question.where(:user_id => self.friends.ids OR :target => self.friends.usernames)
Run Code Online (Sandbox Code Playgroud)

返回此错误

syntax error, unexpected tCONSTANT, expecting ')'
...user_id => self.friends.ids OR :target => self.friends.usern...
Run Code Online (Sandbox Code Playgroud)

知道如何在Rails中编写它,或者只是原始SQL查询应该是什么?

Fáb*_*sta 46

您不需要使用原始SQL,只需将模式作为字符串提供,并添加命名参数:

Question.where('user_id in (:ids) or target in (:usernames)', 
               :ids => self.friends.ids, :usernames => self.friends.usernames)
Run Code Online (Sandbox Code Playgroud)

或位置参数:

Question.where('user_id in (?) or target in (?)', 
               self.friends.ids, self.friends.usernames)
Run Code Online (Sandbox Code Playgroud)

您也可以使用优秀的Squeel gem,正如@erroric在他的回答中指出的那样(my { }只有在需要访问self或实例变量时才需要块):

Question.where { user_id.in(my { self.friends.ids }) |
                 target.in(my { self.friends.usernames }) }
Run Code Online (Sandbox Code Playgroud)


Tim*_*imo 9

虽然Rails 3 AR没有给你一个或运算符,你仍然可以实现相同的结果,而不必一直到SQL并直接使用Arel.我的意思是你可以这样做:

t = Question.arel_table
Question.where(t[:user_id].in(self.friends.ids).or(t[:username].in(self.friends.usernames)))
Run Code Online (Sandbox Code Playgroud)

有人可能会说它不是那么漂亮,有些人可能会说这很简单,因为它不包含SQL.无论如何,它肯定会更漂亮,也有它的宝石:MetaWhere

有关详细信息,请参阅此railscast:http: //railscasts.com/episodes/215-advanced-queries-in-rails-3和MetaWhere站点:http://metautonomo.us/projects/metawhere/

更新:后来Ryan Bates又制作了关于metawhere和元搜索的轨道广播:http: //railscasts.com/episodes/251-metawhere-metasearch后来虽然Metawhere(和搜索)已成为或多或少的遗产宝石.即他们甚至不使用Rails 3.1.作者觉得他们(Metawhere和搜索)需要大幅改写.他真的一起去了一块新宝石.Metawhere的继任者是Squeel.在此处阅读有关作者公告的更多信息:http: //erniemiller.org/2011/08/31/rails-3-1-and-the-future-of-metawhere-and-metasearch/ 并查看项目主页: http://erniemiller.org/projects/squeel/"Metasearch 2.0"被称为Ransack,您可以从这里阅读有关它的内容:http: //erniemiller.org/2011/04/01/ransack-the-library-formerly -known-AS-元搜索-2-0 /


err*_*ric 6

或者,您可以使用Squeel.在我看来,它更简单.您可以使用以下语法完成IN(>>)和OR(|)操作:

Question.where{(:user_id >> my{friends.id}) | (:target >> my{friends.usernames})}
Run Code Online (Sandbox Code Playgroud)

我通常将我的条件(...)包括在内以确保适当的操作顺序 - IN都发生在OR之前.

my{...}self在Squeel调用之前定义的上下文中执行方法- 在本例中Question.在Squeel块内部,self指的是Squeel对象而不是Question对象(有关更多信息,请参阅Squeel自述文件).您可以通过使用my{...}包装器来恢复原始上下文.


jon*_*tar -7

原始SQL

SELECT *
FROM table
WHERE user_id in (LIST OF friend.ids) OR target in (LIST OF friends.usernames)
Run Code Online (Sandbox Code Playgroud)

每个列表以逗号分隔。我不太了解 Rails ActiveRecord 的东西。对于 AND,您只需在这两个条件之间放置一个逗号,但不知道 OR

  • 活动记录的想法是与数据库无关,因此在 Rails 中使用原始 sql 不应被视为最佳解决方案,除非性能下降(此查询中并非如此) (14认同)
  • OP - 你真的应该接受法比奥下面的答案。当它被接受时我不会删除我的,但如果你进行交换我可能会的。 (2认同)