【问题标题】:ActiveRecord OR queryActiveRecord OR 查询
【发布时间】:2011-04-08 01:37:33
【问题描述】:

如何在 Rails 3 ActiveRecord 中进行 OR 查询。我发现的所有示例都只有 AND 查询。

编辑:OR 方法从 Rails 5 开始可用。请参阅 ActiveRecord::QueryMethods

【问题讨论】:

  • 学习 SQL。 ActiveRecord 使事情变得容易,但您仍然需要知道您的查询在做什么,否则您的项目可能无法扩展。我还认为我不必处理 SQL 也能过得很好,但我错了。
  • @ryan0,你说得对。我们可能会使用花哨的gem和其他东西,但是我们应该知道这些gem在里面做什么以及底层技术是什么,如果需要的话,可能会在没有gem的帮助的情况下使用底层技术,以便表现。创建 Gem 时会考虑到特定数量的用例,但在某些情况下,我们项目中的用例之一可能会有所不同。
  • 可能会有所帮助:ActiveRecord OR query Hash notation
  • 从 Rails 5 开始,恕我直言,接受的答案应该是 Greg Olsen 版本:Post.where(column: 'something').or(Post.where(other: 'else'))
  • 这个问题的标签是ruby-on-rails-3。为什么接受的答案只与 Rails 5 相关?

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


【解决方案1】:

只需在条件中添加 OR

Model.find(:all, :conditions => ["column = ? OR other_column = ?",value, other_value])

【讨论】:

  • 这更像是 Rails 2 的语法,它要求我至少写一段 sql 字符串。
【解决方案2】:

使用ARel

t = Post.arel_table

results = Post.where(
  t[:author].eq("Someone").
  or(t[:title].matches("%something%"))
)

生成的 SQL:

ree-1.8.7-2010.02 > puts Post.where(t[:author].eq("Someone").or(t[:title].matches("%something%"))).to_sql
SELECT     "posts".* FROM       "posts"  WHERE     (("posts"."author" = 'Someone' OR "posts"."title" LIKE '%something%'))

【讨论】:

  • 感觉有点乱,但至少我不是在写sql,就是感觉不对!我将不得不考虑更多地使用 Arel。
  • 我无法相信续集有多优雅
  • SQL 没有问题。可能出错的是我们如何构建 SQL 字符串,即SQL Injection。因此,在将用户输入提供给必须针对数据库运行的 SQL 查询之前,我们必须对其进行清理。这将由ORMs 处理,这些一直在处理我们往往会错过的边缘情况。因此,始终建议使用ORM 创建 SQL 查询。
  • SQL 的另一个问题是它与数据库无关。例如,matches 将为 sqlite 生成 LIKE(默认情况下不区分大小写)和在 postgres 上生成ILIKE(需要显式不区分大小写的运算符)。
  • @ToniLeigh ActiveRecord 在后台使用 SQL。它只是一种编写 SQL 查询的语法,它处理 SQL 清理并使您的查询与数据库无关。唯一的开销是 Rails 将语法转换为 SQL 查询的地方。这只是几毫秒的事情。当然,您应该编写性能最佳的 SQL 查询并尝试将其转换为 ActiveRecord 语法。如果 SQL 不能用 ActiveRecord 语法表示,那么你应该使用普通 SQL。
【解决方案3】:

MetaWhere 插件非常棒。

轻松混合 OR 和 AND,连接任何关联的条件,甚至指定 OUTER JOIN!

Post.where({sharing_level: Post::Sharing[:everyone]} | ({sharing_level: Post::Sharing[:friends]} & {user: {followers: current_user} }).joins(:user.outer => :followers.outer}

【讨论】:

    【解决方案4】:

    在 Rails 3 中,应该是

    Model.where("column = ? or other_column = ?", value, other_value)
    

    这也包括原始 sql,但我认为 ActiveRecord 中没有办法进行 OR 操作。你的问题不是菜鸟问题。

    【讨论】:

    • 即使有原始 sql — 这个语句对我来说看起来比 Arel 清晰得多。甚至可能是 DRYer。
    • 如果您需要链接其他可能具有相同列名的列的表连接,您应该像这样使用它,Page.where("pages.column = ? or pages.other_column = ?", value, other_value)
    • 如果查询给表起别名,那将失败。这就是艾瑞尔大放异彩的时候。
    • 如果您检查具有 nil 值的列,此解决方案将不起作用
    • @GaneshSagare 是的,在这种情况下,sql 查询应该是 column IS NULL or other_column IS NULL。我认为 Rails 提供了一种获取 sql 片段的中间方法(where_clause 之类的),让我挖掘一下。这可能在这里有用。
    【解决方案5】:

    我刚刚从客户端工作中提取了this plugin,它允许您将范围与.or. 结合起来,例如。 Post.published.or.authored_by(current_user)。 Squeel(MetaSearch 的较新实现)也很棒,但不允许您使用 OR 范围,因此查询逻辑可能有点多余。

    【讨论】:

      【解决方案6】:

      如果您想对某一列的值使用 OR 运算符,可以将数组传递给 .where,ActiveRecord 将使用 IN(value,other_value)

      Model.where(:column => ["value", "other_value"]
      

      输出:

      SELECT `table_name`.* FROM `table_name` WHERE `table_name`.`column` IN ('value', 'other_value')
      

      这应该相当于在单个列上使用OR

      【讨论】:

      • 这是最干净最“rails way”的答案,应该被接受
      • 感谢@koonse,这不是完全 'OR' 查询,但在这种情况下它会产生相同的结果。
      • 如果可以,请提供帮助 - stackoverflow.com/questions/15517286/…
      • 此解决方案不能替代 OR,因为您不能以这种方式使用两个不同的列。
      【解决方案7】:

      如果你想使用数组作为参数,下面的代码可以在 Rails 4 中使用:

      query = Order.where(uuid: uuids, id: ids)
      Order.where(query.where_values.map(&:to_sql).join(" OR "))
      #=> Order Load (0.7ms)  SELECT "orders".* FROM "orders" WHERE ("orders"."uuid" IN ('5459eed8350e1b472bfee48375034103', '21313213jkads', '43ujrefdk2384us') OR "orders"."id" IN (2, 3, 4))
      

      更多信息:OR queries with arrays as arguments in Rails 4

      【讨论】:

      • 或者这个:Order.where(query.where_values.inject(:or)) 一直使用 arel。
      • > 在 Rails 4 中使用数组作为参数的 OR 查询。有用的链接!谢谢!
      【解决方案8】:

      Rails/ActiveRecord 的更新版本可能原生支持这种语法。它看起来类似于:

      Foo.where(foo: 'bar').or.where(bar: 'bar')
      

      如此拉取请求中所述https://github.com/rails/rails/pull/9052

      目前,只需坚持以下方法即可:

      Foo.where('foo= ? OR bar= ?', 'bar', 'bar')
      

      更新:根据https://github.com/rails/rails/pull/16052or 功能将在 Rails 5 中可用

      更新:功能已合并到 Rails 5 分支

      【讨论】:

      • or 现在 Rails 5 可用,但不能以这种方式实现,因为它需要传递 1 个参数。它需要一个 Arel 对象。查看接受的答案
      • ActiveRecord 中的or 方法如果您直接使用它就可以工作:但如果它在随后被链接的作用域中使用,则可能会打破您的期望。
      • @JeremyList 说的很到位。这让我很难受。
      【解决方案9】:

      使用rails + arel,更清晰的方式:

      # Table name: messages
      #
      # sender_id:    integer
      # recipient_id: integer
      # content:      text
      
      class Message < ActiveRecord::Base
        scope :by_participant, ->(user_id) do
          left  = arel_table[:sender_id].eq(user_id)
          right = arel_table[:recipient_id].eq(user_id)
      
          where(Arel::Nodes::Or.new(left, right))
        end
      end
      

      生产:

      $ Message.by_participant(User.first.id).to_sql 
      => SELECT `messages`.* 
           FROM `messages` 
          WHERE `messages`.`sender_id` = 1 
             OR `messages`.`recipient_id` = 1
      

      【讨论】:

        【解决方案10】:

        Rails 最近将此添加到 ActiveRecord 中。它看起来在 Rails 5 中发布。已经致力于掌握:

        https://github.com/rails/rails/commit/9e42cf019f2417473e7dcbfcb885709fa2709f89

        Post.where(column: 'something').or(Post.where(other: 'else'))
        
        # => SELECT * FROM posts WHERE (column = 'something') OR (other = 'else)
        

        【讨论】:

          【解决方案11】:
          Book.where.any_of(Book.where(:author => 'Poe'), Book.where(:author => 'Hemingway')
          

          【讨论】:

          • 为你的答案添加一些解释
          • 我相信 Matthew 指的是 activerecord_any_of gem,它增加了对这种语法的支持。
          • 如果属实,谢谢@DannyB。答案必须解释其背景。
          【解决方案12】:

          Rails 5 带有一个or 方法。 (link to documentation)

          此方法接受 ActiveRecord::Relation 对象。例如:

          User.where(first_name: 'James').or(User.where(last_name: 'Scott'))
          

          【讨论】:

            【解决方案13】:

            你可以这样做:

            Person.where("name = ? OR age = ?", 'Pearl', 24)
            

            或者更优雅,安装rails_or gem 并像这样:

            Person.where(:name => 'Pearl').or(:age => 24)
            

            【讨论】:

              【解决方案14】:

              我想补充一下,这是一种搜索 ActiveRecord 的多个属性的解决方案。自从

              .where(A: param[:A], B: param[:B])
              

              将搜索 A 和 B。

              【讨论】:

                猜你喜欢
                • 2015-12-21
                • 1970-01-01
                • 2015-09-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多