【问题标题】:How to combine inner join and left outer join in Rails如何在 Rails 中结合内连接和左外连接
【发布时间】:2014-11-20 00:12:49
【问题描述】:

我有两个模型invoicepayments。它们之间的关系是invoicehas_many payments

我正在使用以下左外连接来返回所有尚未支付的发票:

result1 = Invoice.includes(:payments).where(:payments => { :id => nil })

我还对所有已部分支付的发票感兴趣。要返回那些我使用内部连接:

result2 = Invoice.joins(:payments).group("transfers.id").having("sum(payments.amount) < invoice.amount")

我现在想合并这两个结果,即我想要所有未付款或未全额付款的发票。我知道我可以做result = result1 + result2。但是,这不会返回 ActiveRecord 对象。有没有办法将这两个查询合并到一个查询中?

我使用 Rails 4.1 和 PostgreSQL

【问题讨论】:

    标签: sql ruby-on-rails postgresql


    【解决方案1】:

    我相信你是正确的,你不能让 ActiveRecord 生成除内部连接之外的任何东西,而不自己编写它。但我不会在这种情况下使用includes,因为虽然它确实会导致 ActiveRecord 生成不同的连接,但这是一个“实现细节”——它的基本目的是加载关联模型,不一定是你想要的。

    在您提出的解决方案中,我不明白您为什么要同时按 invoices.idpayments.id 进行分组——这似乎违背了分组的目的。

    您可以执行以下操作,尽管我不能说这看起来更像 Rails。

    Invoice.joins("LEFT JOIN payments ON payments.transfer_id = invoices.id")
      .select("invoices.id, SUM(payments.amount) AS total_paid")
      .group("invoices.id")
      .having("SUM(payments.amount) IS NULL OR SUM(payments.amount) < invoices.amount")
    

    这将返回仅包含 id 字段和 total_paid 字段集的 Invoice 对象列表。如果您需要其他可用字段,请将它们添加到 select 语句和 group 语句中。

    【讨论】:

    • 我必须同时按invoices.idpayments.id 分组,否则我不能将payevents.id IS NULL 放在HAVING 子句中。
    • 人力资源部。我认为您的 SUM 表达式没有达到您的预期 - 您是否尝试过测试两次付款一起涵盖发票总额的场景?您打算从您的查询中排除该发票(因为它已全额支付),但我认为您会发现您的查询包含它。
    • 你说得对,这是个问题。不幸的是,您的解决方案也不起作用。我得到ERROR: column "total_paid" does not exist
    • 好的,我认为现在的版本应该适合你。它看起来与您的原始提案非常相似,但有两个显着差异。首先,它仅按发票 ID 分组。其次,在having子句中,它允许支付的总和IS NULL——像SQL这样的三元逻辑系统的一个有趣特征是,通过NULL输入的函数通常返回NULL。这包括发票没有付款的情况。
    • 酷!要考虑的另一项改进:使用COALESCE function 编写更紧凑的HAVING 子句:'"COALESCE(SUM(payments.amount), 0) OR。
    【解决方案2】:

    我最终只做了一个 LEFT OUTER JOIN。但是,Rails 似乎不支持grouphavingincludes() 生成的LEFT OUTER JOIN。因此,我不得不手动构建连接,这实际上并不像“Rails 方式”。

    我的查询:

        Invoice.joins("LEFT JOIN payments ON payments.transfer_id = invoices.id").group("invoices.id, payments.id").having("((payments.id IS NULL) OR (sum(payments.amount) < invoices.amount))")
    

    更新:这没有按预期工作。请查看已接受的答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 1970-01-01
      • 2016-12-19
      • 2015-01-11
      • 1970-01-01
      • 1970-01-01
      • 2014-02-06
      相关资源
      最近更新 更多