【问题标题】:Grouping ands and ors in AREL在 AREL 中对 ands 和 ors 进行分组
【发布时间】:2011-11-10 16:56:20
【问题描述】:

我正在尝试使用 arel 查询此 sql sn-p 的等效项:

WHERE (("participants"."accepted" = 'f' AND "participants"."contact_id" = 1) 
  OR "participants"."id" IS NULL)

所以我想要(accepted && contact_id=1) OR NULL

这就是我在 AREL 中得到的东西

participants[:accepted].eq(false).and(participants[:contact_id].eq(1).
  or(participants[:id].is(nil)

问题是,这会生成:

("participants"."accepted" = 'f' AND "participants"."contact_id" = 1 OR "participants"."id" IS NULL)

请注意我的和条件周围没有括号。我相信,根据运算符的优先级,我得到:

accepted && (contact_id=1 OR NULL)

在 AREL 查询中添加括号没有影响。有什么想法吗?

【问题讨论】:

    标签: sql ruby arel


    【解决方案1】:

    您可以使用Arel::Nodes::Grouping 生成括号。

    participants = Arel::Table.new("participants")
    
    arel = participants.grouping(
      participants[:accepted].eq(false).and(participants[:contact_id].eq(1))
    ).or(participants[:id].eq(nil))
    
    arel.to_sql # => (("participants"."accepted" = 'f' AND "participants"."contact_id" = 1) OR "participants"."id" IS NULL)
    

    【讨论】:

    • 谢谢,.grouping 效果很好。我用participants = Participant.arel_table代替participants = Arel::Table.new("participants")
    • 这个解决方案运行优雅,解决了手头的问题。这将是我对这个问题的首选答案。虽然周围都有很好的选择:-)
    【解决方案2】:

    我相信根据运算符优先级

    问题是AND has higher precedence than OR。所以1 AND 2 OR 3 等价于(1 AND 2) OR 3

    附带说明:如果您使用像 this one 这样的包装器,您可以这样写:

    User.where((User[:created_at] > 3.days.ago) & (User[:enabled] == true))
    

    【讨论】:

    • 这正是 Arel 为您提供的。怎么太低级了?
    • Squeel 看起来很棒,不过(我不知道)。但称它比 Arel 低级并不准确——它只是一种语法修改。
    • 鉴于上下文,我不清楚“低级”是指整个库 - 看起来更像是指 Aaron 正在编写的内部结构.
    • 不,“低水平”和“高水平”不是主观的,至少作为相对术语。你说Squeel比Arel等级高。据我所知,它只是 Arel 的一个语法模型,因此在完全相同的级别上工作。筛选器是个例外,它抽象了 Arel,因此可以在更高的层次上工作。
    • 嗯...你是对的。我实际上是在尝试将手写的LEFT OUTER JOIN participants 翻译为使用includes(:participants)。问题是我的加入有附加条件。所以我希望我可以将它们添加到where,但它们并不等同。必须修改我的问题
    【解决方案3】:

    为什么不把它们翻过来。应该相当于:

    participants[:id].is(nil).or(participants[:accepted].eq(false).and(participants[:contact_id].eq(1))
    

    希望我在上面正确设置了括号,但你明白我的意思......

    【讨论】:

    • 是的,我认为我需要这个是错误的,Tokland 是对的,优先级不是我的问题,实际上是我的查询与我需要的不同。
    【解决方案4】:

    这是一种允许您在代码中使用现有 AR 方法(例如 where)以及可能任何现有范围等的方法。因此,可以根据需要轻松地通过 Arel 重用现有的 AR 代码。

    class Participant
      scope :grouped, -> {
        group1 = arel_table.grouping(where(accepted: false, contact_id: 1)).arel.constraints
        group2 = arel_table.grouping(where(id: nil).arel.constraints
    
        where(group1.or(group2))
      }
    end
    

    这在 Rails 7 中有效,也许在 Rails 6.x 中也有效。

    【讨论】:

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