【问题标题】:Rails 3 ActiveRecord query using both SQL IN and SQL OR operatorsRails 3 ActiveRecord 查询同时使用 SQL IN 和 SQL OR 运算符
【发布时间】:2011-05-11 14:41:21
【问题描述】:

我正在使用“where”语法编写 Rails 3 ActiveRecord 查询,它同时使用 SQL IN 和 SQL OR 运算符,但不知道如何将它们一起使用。

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

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 查询应该是什么?

【问题讨论】:

    标签: sql ruby-on-rails ruby ruby-on-rails-3 activerecord


    【解决方案1】:

    原始 SQL

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

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

    【讨论】:

    • 谢谢!我使用的确切查询是: Question.where('target IN (?) OR user_id IN (?)', self.friends.usernames, self.friends.ids)
    • 好的,我忘了。我觉得它们应该是 => 哈希格式中的一种方式。你不应该只需要一个字符串模式来在两个有效条件之间添加 OR,但谁在乎你得到它。
    • 活动记录的想法是与数据库无关,因此在 Rails 中使用原始 sql 不应被视为最佳解决方案,除非性能下降,但在此查询中不是这种情况跨度>
    • OP - 你真的应该接受下面法比奥的回答。当它被接受时,我不会删除我的,但如果你进行交换,我可能会。
    【解决方案2】:

    您不需要使用原始 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 gem,正如@erroric 在他的回答中指出的那样(仅当您需要访问self 或实例变量时才需要my { } 块):

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

    【讨论】:

    • 嘿,需要帮助。如果我需要选择两个用户(比如 id1 和 id2)之间的所有消息并且消息具有 sender_id 和 receiver_id,如何编写查询。所以我需要选择“所有消息,其((sender_id = id1 and reciver_id = id2)或(sender_id = id2 and reciver_id = id1))”。我需要对它们进行排序并分页,如果我进行两个单独的查询然后添加它们,则无法完成(我将获得所需的结果,但分页变得困难)。因此,请帮助我为此编写单行查询。任何帮助将不胜感激。
    • @zeal,请打开一个新问题,描述您已经尝试过的内容以及我们如何提供帮助。社区很棒,但你必须学习如何使用它。
    【解决方案3】:

    尽管 Rails 3 AR 没有为您提供 or 运算符,但您仍然可以实现相同的结果,而无需一直使用 SQL 并直接使用 Arel。我的意思是你可以这样做:

    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/

    更新:后来 Ryan Bates 又做了一次关于元位置和元搜索的 railscast:http://railscasts.com/episodes/251-metawhere-metasearch 后来虽然 Metawhere(和搜索)或多或少地成为了传统的宝石。 IE。他们甚至不能使用 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-metasearch-2-0/

    【讨论】:

      【解决方案4】:

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

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

      我通常将我的条件包装在 (...) 中以确保正确的操作顺序 - 两个 IN 都发生在 OR 之前。

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

      【讨论】:

      猜你喜欢
      • 2012-12-07
      • 1970-01-01
      • 2014-05-05
      • 1970-01-01
      • 2016-04-09
      • 2020-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多