【问题标题】:Ruby on Rails 3 howto make 'OR' conditionRuby on Rails 3 如何制作“或”条件
【发布时间】:2010-07-20 14:44:44
【问题描述】:

我需要一条 SQL 语句来检查一个条件是否满足:

SELECT * FROM my_table WHERE my_table.x=1 OR my_table.y=1

我想以“Rails 3”的方式执行此操作。我正在寻找类似的东西:

Account.where(:id => 1).or.where(:id => 2)

我知道我总是可以回退到 sql 或条件字符串。但是,根据我的经验,这在组合范围时经常会导致混乱。最好的方法是什么?

另一个相关问题是如何描述依赖于 OR 条件的关系。我找到的唯一方法:

has_many :my_thing, :class_name => "MyTable",  :finder_sql => 'SELECT my_tables.* ' + 'FROM my_tables ' +
'WHERE my_tables.payer_id = #{id} OR my_tables.payee_id = #{id}'

但是,当它们组合使用时,它们又会中断。有没有更好的方法来指定这个?

【问题讨论】:

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


    【解决方案1】:

    Account.where(id: [1,2]) 无需解释。

    【讨论】:

    • 我见过的最干净、最干燥的。干得好!
    • 这很棒,也很简单。我还了解到您可以安全地使用nil:例如Thing.where(foo: [1, nil]) 将被翻译成 SELECT "things".* FROM "things" WHERE (("things"."foo" = 1 OR "things"."foo" IS NULL))。太棒了!
    • 但是例如如果你使用“A is not null OR A is null”你不能使用这个答案,但是你可以在rails 3中使用Account.arel_table[:id].not_eq(nil).or()组合跨度>
    • 喜欢这个解决方案。其他所有答案都非常复杂!
    • 这是对另一个问题的回答。原问题问my_table.x=1 OR my_table.y=1 x 和 y 是表中的不同列
    【解决方案2】:

    这适用于 Rails 5,请参阅 rails master

    Post.where('id = 1').or(Post.where('id = 2'))
    # => SELECT * FROM posts WHERE (id = 1) OR (id = 2)
    

    对于 Rails 3.0.4+:

    accounts = Account.arel_table
    Account.where(accounts[:id].eq(1).or(accounts[:id].eq(2)))
    

    【讨论】:

    • 绝对不喜欢这种语法。不过,仍然很有趣。
    • 我喜欢它,因为它可以是组合的
    【解决方案3】:

    这些 arel 查询对我来说是不可读的。

    SQL 字符串有什么问题?事实上,Rails 指南将这种方式公开为在查询中创建条件的第一种方式:http://guides.rubyonrails.org/active_record_querying.html#array-conditions

    所以,我打赌这种方式是“Rails 方式”:

    Account.where("id = 1 OR id = 2")
    

    以我的拙见,它更短更清晰。

    【讨论】:

    • 更喜欢这个,但我会使用参数化值。 Account.where("id = ? OR id = ?",1,2)
    • 我看不出使用简单数字时参数化值的任何原因。
    • 如果你对 id 进行硬编码,那么没有简单的数字会很好,但我怀疑这些是从其他地方返回的,所以参数化是避免 sql 注入的方法。
    • 当然,正如第一位评论者所说,使用参数是实现此目的的好方法。我只是写了硬编码的数字作为例子。
    【解决方案4】:

    遗憾的是,.or 还没有实现(但如果实现了,那就太棒了)。

    所以你必须这样做:

    class Project < ActiveRecord::Base
      scope :sufficient_data, :conditions=>['ratio_story_completion != 0 OR ratio_differential != 0']
      scope :profitable, :conditions=>['profit > 0']
    

    这样你仍然可以很棒并且做:

    Project.sufficient_data.profitable
    

    【讨论】:

    • 来自 arel github 站点:尚不支持 OR 运算符。它将像这样工作: users.where(users[:name].eq('bob').or(users[:age].lt(25)))
    【解决方案5】:

    我会选择IN 子句,例如:

    Account.where(["id in (?)", [1, 2]])
    

    【讨论】:

    • 那是合适的,但请注意作者正在查看@ 2 个不同的字段...
    • 哦,是的,这是真的,我根据此声明 Account.where(:id =&gt; 1).or.where(:id =&gt; 2) 写了答案。显然它不适用于不同的领域。
    • 如果数组中的值之一是nil,则不起作用。假设您要查找“已查看”为falsenil 的所有记录,而您执行Notification.where(:viewed =&gt; [false, nil]),它将无法正常工作,因为MySQL 需要语法viewed = 0 OR viewed IS NULL 无法使用 viewed = 0 OR viewed = NULLviewed IN (0, NULL)
    • Account.where(["id in (?)", [1, 2]]) 你忘了( ? )
    【解决方案6】:

    我使用 Squeel gem (https://github.com/ernie/squeel/) 进行 OR 查询,效果很好。

    它可以让你将查询写成Account.where{(id == 1) | (id == 2)}

    【讨论】:

      【解决方案7】:

      您可以将数组定义为:conditions Hash 中的值。

      所以你可以这样做:

      Account.all(:conditions => { :id => [1, 2] })
      

      使用 Rails 3.1.0 测试

      【讨论】:

      • 这是低效的,因为您正在从数据库中检索所有项目并检查内存
      【解决方案8】:

      使用哈希的替代语法

      Account.where("id = :val1 OR id = :val2", val1: 1, val2: 2).
      

      当值与多列进行比较时,这特别有用。例如:

      User.where("first_name = :name OR last_name = :name", name: 'tom')
      

      【讨论】:

        【解决方案9】:

        使用rails_or,您可以这样做:

        Account.where(id: 1).or(id: 2)
        

        (它也适用于 Rails 4 和 5。)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-02
          • 2012-08-22
          • 1970-01-01
          相关资源
          最近更新 更多