[英]How to combine inner join and left outer join in Rails
I have two Models invoice
and payments
. 我有两个模型invoice
和payments
。 The relationship between them is invoice
has_many payments
. 它们之间的关系是has_many payments
invoice
。
I'm using the following left outer join to return all invoices that have not been paid at all: 我正在使用以下左外部联接来返回所有尚未支付的所有发票:
result1 = Invoice.includes(:payments).where(:payments => { :id => nil })
I'm also interested in all invoices that have been partially paid. 我也对所有已部分支付的发票感兴趣。 To return those I use an inner join: 为了返回那些,我使用一个内部联接:
result2 = Invoice.joins(:payments).group("transfers.id").having("sum(payments.amount) < invoice.amount")
I would now like to combine the two results, ie I want all Invoices that have either not been paid, or not been fully paid. 现在,我想将这两个结果结合起来,即我想要所有尚未付款或未全部付款的发票。 I know that I could just do result = result1 + result2
. 我知道我可以做result = result1 + result2
。 However, this doesn't return an ActiveRecord object. 但是,这不会返回ActiveRecord对象。 Is there a way to combine those two queries in a single query? 有没有一种方法可以将这两个查询合并到一个查询中?
I use Rails 4.1 and PostgreSQL 我使用Rails 4.1和PostgreSQL
I believe you're correct that you can't get ActiveRecord to generate anything other than an inner join without writing it yourself. 我相信您是对的,除非您自己编写,否则无法让ActiveRecord生成除内部联接以外的任何东西。 But I wouldn't use includes
in this context, for while it does happen to cause ActiveRecord to generate a different join, that is an "implementation detail" -- it's fundamental purpose is to load the associated models, which is not necessarily what you want. 但是我不会在这种情况下使用includes
,因为它确实会导致ActiveRecord生成不同的联接,这是“实现细节”-它的基本目的是加载关联的模型,而这不一定是您所需要的。想。
In your proposed solution, I don't understand why you'd group by both invoices.id
and payments.id
-- that seems to defeat the purpose of grouping. 在您提出的解决方案中,我不明白为什么要同时对invoices.id
和payments.id
进行分组-这似乎违背了分组的目的。
You could do something like the following, although I can't say that this seems much more Rails-ish. 您可以执行以下操作,尽管我不能说这看起来更像是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")
This will return a list of Invoice objects with only the id
field and total_paid
field set. 这将返回仅设置id
字段和total_paid
字段的发票对象列表。 If you need other fields available, add them to both the select
statement and the the group
statement. 如果需要其他可用字段,请将它们添加到select
语句和group
语句中。
I ended up doing just a LEFT OUTER JOIN. 我最终只是做一个左外连接。 However, Rails doesn't seem to support group
and having
with the LEFT OUTER JOIN generated by includes()
. 但是,Rails似乎不支持group
并且having
includes()
生成的LEFT OUTER JOIN。 Therefore, i had to construct the join manually which actually doesn't feel like "the Rails way". 因此,我不得不手动构造实际上不像“ Rails方式”的联接。
My query: 我的查询:
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))")
Update : This doesn't work as expected. 更新 :不能按预期工作。 Please see the accepted answer. 请查看已接受的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.