【问题标题】:How do I perform a full join in ARel?如何在 ARel 中执行完全联接?
【发布时间】:2012-08-19 00:09:40
【问题描述】:

假设我有两个表 TableATableB 通过连接表 TableABJoin 具有多对多关系。我想使用 ARel 3 生成一个查询,该查询执行 TableATableB 的完全连接。

我想要生成的查询应该是这样的:

SELECT a.id, b.code
FROM TableA as a, TableB as b

这会导致表 A 和 B 的完全连接。

在不编写显式 sql 字符串的情况下,我能够得到的最接近的方法是破解外连接:

part_a = TableA.arel_table
part_b = TableB.arel_table
query = part_a.join(part_b, Arel::Nodes::OuterJoin).on('1=1').project(part_a[:id], part_b[:code]).to_sql

这会产生以下 SQL:

SELECT "TableA"."id", "TableB"."code" FROM "TableA" LEFT OUTER JOIN "TableB" ON 1=1

如果我排除 .on 组件,我最终会得到一个尾随 NULL:

SELECT "TableA"."id", "TableB"."code" FROM "TableA" LEFT OUTER JOIN "TableB" NULL

有没有更合理的方法来生成正确的完全联接或至少生成相同的结果而不破解 ARel 中的左外联接?

【问题讨论】:

  • 我也在做这个,如何进行全外连接?

标签: ruby activerecord arel


【解决方案1】:

我用 SQL 编写连接。它更清晰,工作正常:

part_a = TableA.arel_table
part_b = TableB.arel_table
query = part_a.joins('LEFT OUTER JOIN "TableB"').other_scopes.to_sql

【讨论】:

    【解决方案2】:

    实际上,无法使用 arel 执行完全外连接(和右外连接),它只支持内连接和外连接(LEFT OUTER)。

    因为我不喜欢这个,所以我更新了 arel 3-0-stable(我正在开发一个 3.2.13 rails 应用程序),以便它也支持右外连接和全外连接。即使使用未记录的代码,添加这些也非常简单,这很容易,所以如果你尝试它应该不会遇到任何问题。

    在这里你可以找到我的拉取请求:https://github.com/rails/arel/pull/202
    在这里您可以找到带有分支的更新存储库:https://github.com/Fire-Dragon-DoL/arel/tree/3-0-right-full-outer-join

    您可以通过将它添加到您的 Gemfile 中轻松地在 Rails 应用程序中使用它:

    gem 'arel', '~> 3.0.3.4', github: 'Fire-Dragon-DoL/arel', branch: '3-0-right-full-outer-join'
    

    这里你可以看到一个语法示例:

    class Cat < ActiveRecord::Base
      has_many :cat_diseases
    end
    class Disease < ActiveRecord::Base
      has_many :cat_diseases
    end
    
    class CatDisease < ActiveRecord::Base
      belongs_to :cat
      belongs_to :disease
    
      def self.all_diseases_for_cat(cat)
        cat_diseases = self.arel_table
        diseases     = Disease.arel_table
    
        scoped
        .joins(
          cat_diseases.join(diseases, Arel::Nodes::RightOuterJoin)
                        .on(cat_diseases[:disease_id].eq(diseases[:id]))
          .join_sources
        )
        .where(
          cat_diseases[:cat_id].eq(cat.id)
          .or(cat_diseases[:cat_id].eq(nil))
        )
      end
    end
    

    【讨论】:

    • 谢谢,很高兴看到一些反馈,由于某种原因,它被忽略了很长时间
    猜你喜欢
    • 2017-10-27
    • 2011-01-06
    • 1970-01-01
    • 2021-11-17
    • 1970-01-01
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    相关资源
    最近更新 更多