2010-11-17 74 views
16

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

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

Question.where(:user_id => self.friends.ids) 
#note: self.friends.ids returns an array of integers 

但是这个代码

Question.where(:user_id => self.friends.ids OR :target => self.friends.usernames) 

返回该错误

syntax error, unexpected tCONSTANT, expecting ')' 
...user_id => self.friends.ids OR :target => self.friends.usern... 

不知道如何在Rails中写这篇文章,或者只是原始的SQL查询应该是什么?

回答

-7

原始SQL

SELECT * 
FROM table 
WHERE user_id in (LIST OF friend.ids) OR target in (LIST OF friends.usernames) 

每个列表逗号分隔。我不太了解Rails ActiveRecord的东西。对于和你只想把那两个条件之间用逗号,但IDK的约OR

+0

谢谢!我使用的确切查询是:Question.where('target IN(?)OR user_id IN(?)',self.friends.usernames,self.friends.ids) – kateray 2010-11-17 20:23:01

+0

好,我忘记了。我觉得他们应该是=>散列格式中的一种方式。你不应该需要一个字符串模式来在两个有效的条件之间添加OR,但是谁在乎你。 – 2010-11-17 20:26:48

+13

主动记录的想法是数据库不可知的,所以在rails中使用原始sql不应该被认为是最好的解决方案,除非性能降低,而在这个查询中情况并非如此。 – nunopolonia 2011-08-08 14:13:40

45

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

Question.where('user_id in (:ids) or target in (:usernames)', 
       :ids => self.friends.ids, :usernames => self.friends.usernames) 

或位置参数:

Question.where('user_id in (?) or target in (?)', 
       self.friends.ids, self.friends.usernames) 

您也可以使用优秀Squeel宝石,如@erroric指出了他的答案(只需要my { }块,如果你需要访问self个或实例变量):

Question.where { user_id.in(my { self.friends.ids }) | 
       target.in(my { self.friends.usernames }) } 
+0

嘿人类需要帮助..如何编写查询,如果我需要选择两个用户之间的所有消息(说id1&id2)和消息有sender_id和receiver_id。所以我需要选择“((sender_id = id1和reciver_id = id2)或(sender_id = id2和reciver_id = id1))”的所有消息。我需要对它们进行排序和分页,如果我做两个单独的查询然后添加它们(我将得到期望的结果,但分页变得困难),这是无法完成的。所以请帮我写单行查询。任何帮助将不胜感激。 – zeal 2014-08-06 20:23:17

+0

@zeal,请打开一个新问题,描述你已经尝试了什么以及我们如何提供帮助。社区很棒,但你必须学会​​如何使用它。 – 2014-08-07 03:09:14

9

虽然Rails 3的AR不给你或操作员仍然可以达到同样的效果,而不去一路下跌到SQL和直接使用阿雷尔。我的意思是,你可以做这样的:

t = Question.arel_table 
Question.where(t[:user_id].in(self.friends.ids).or(t[:username].in(self.friends.usernames))) 

也许有人会说这是不是很漂亮,有人可能会说这是很简单,因为它不包含SQL。无论如何它肯定会是漂亮,有一个为它的宝石太:MetaWhere

欲了解更多信息请参阅本railscast:http://railscasts.com/episodes/215-advanced-queries-in-rails-3 和MetaWhere网站:http://metautonomo.us/projects/metawhere/

UPDATE:后来瑞安贝茨取得了约metawhere另一个railscast和元搜索: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/ “元搜索2.0”被称为洗劫,您可以从这里读到关于它: http://erniemiller.org/2011/04/01/ransack-the-library-formerly-known-as-metasearch-2-0/

6

或者,你可以使用Squeel。在我看来,这很简单。你可以做到既IN(>>)和OR(|)操作使用的语法如下:

Question.where{(:user_id >> my{friends.id}) | (:target >> my{friends.usernames})} 

我一般缠上了我的条件(...),以确保适当的操作顺序 - 两个或之前诸IN发生。

my{...}块执行在Squeel调用之前定义的self上下文中的方法 - 在此例中为Question。在Squeel块内部,self是指Squeel对象而不是Question对象(see the Squeel Readme for more)。您通过使用my{...}包装来恢复原始上下文。

+1

看起来不错,但他们[倒下活动记录的'where()'](https://github.com/ernie/squeel#compatibility-with-active-record),这似乎是不幸的。 – crizCraig 2013-06-11 22:26:02