2015-01-14 89 views
1

我有三个表查询两个类似的表和合并排序结果

orders.orderid (and other non-pertinent stuff) 

payment.orderid 
payment.transactiondate 
payment.amount 

projectedpayment.orderid 
projectedpayment.projecteddate 
projectedpayment.projectedamount 

从本质上讲,payment表示当收到实际付款; projectedpayment表示何时系统认为应该收到它们。我需要建立一个查询来比较投影与实际。

我想查询它们,以便查询中的每一行都有orderid,payment.transactiondate,payment.amount,projectedpayment.projecteddate,projectedpayment.projectedamount,其中来自付款和预计付款的行按其各自的日期排序。例如,

orderid transactiondate amount projecteddate projectedamount 
     1  2015-01-01 12.34 2015-01-03   12.34 
     1  2015-01-15 12.34 2015-01-15   12.44 
     1   null null 2015-02-01   12.34 
     2  2014-12-31 50.00   null   null 

因此,通过订单分解,有哪些实际和预计支付,其中可能会有更多的投影支付比实际的,或比预计的更实际支付,按日期(排列简单地通过排序两种,没有比这更复杂的了)。

好像我应该能够从ordersleft join实现这一目标,以某种与order by排序的其他两个表的union,但我一直没能使其工作,所以它可能是完全不同的东西。我知道我无法加入order,paymentprojectedpayment的全部三个,或者我得到后两个表的交叉积。

我恰好在使用postgresql 9.4,但希望我们不需要太过于数据库特定。

回答

2

我不知道postgres对不起:(但如果你知道如何做分区行号这样的事情应该工作。

select 
    coalesce(a.orderid,b.orderid) as orderid 
    ,transactiondate 
    ,amount 
    ,projecteddate 
    ,projectedamount 
FROM 

     (select 
      orderid 
      ,ransactiondate 
      ,amount 
      ,row_number() over (partition by orderid order by orderid,transactiondate) as rn 
     from payment) as a 

     full join 
     (select 
      orderid 
      ,projecteddate 
      ,projectedamount 
      ,row_number() over (partition by orderid order by orderid,projecteddate) as rn 
     from projectedpayment) as b 

     on a.orderid= b.orderid 
     and a.rn = b.rn 

*这是SQLSERVER语法(2K5 +据我所知)

这里的逻辑是,你需要一个唯一的编号分配给每个预测与实际付款,这样就可以加入两个表在一起,但只有每行与另一个表中的单个行匹配。

如果您有每天只需支付一笔款项那么您可以在订单ID和日期上完整连接,无需担心行号。

全部加入可以让你有任何一方空,所以你将需要合并的OrderID

*也并不没有付款或预测显示订单..评论,如果这是一个问题。

+1

谢谢!与'row_number().. over()'结合的'full join'是解决我以前从未见过的一个聪明的方法。 – koehn

+0

我做了大量的数据迁移/主数据/数据审查工作,像这样的技术是救星:D – gordatron

0

这应该工作

Select * from Orders o 
Left Join Payments p on o.ID = p.OrderID 
Left Join ProjectedPaymentp pp on o.ID = pp.OrderID 
Order By o.ID 
+0

我不认为这是他正在寻找的。对于'订单'的每个'ProjectedPayment',每个'支付'都有一个记录。也就是说,如果您为一个“订单”有四个“付款”,并且说4个“ProjectedPayments”,每个月有一个,您将获得该订单的16条记录。我相信** OP希望'ProjectedPayments'在某种程度上受到最接近的'timestamp'的限制......如果有任何意义的话:) – Tom

+0

不,你不会得到16条记录。仔细观察加入。我不参加ProjectedPaymentp上的付款。我加入他们两个产品 –

+0

但我想要四行,在这个例子中。或者,对于给定的订单,更一般地说'max(count(payment。*),count(projectedpayment。*))'行。 – koehn

0

如果我理解正确的,下面的查询应该有所帮助:

select o.orderid, ap.transactiondate, ap.amount, pp.projecteddate, pp.projectedamount 
from orders o 
left join 
(
    select p.orderid, p.transactiondate, p.amount, 
     row_number() over (partition by p.orderid order by p.transactiondate) n 
    from payment p  
) ap on o.orderid = ap.order 
left join 
(
    select p.orderid, p.projecteddate, p.projectedamount, 
     row_number() over (partition by p.orderid order by p.projecteddate) n 
    from projectedpayment p 
) pp on o.orderid = ap.order and (ap.n is null or ap.n = pp.n) 
order by o.orderid, ap.n, pp.n 

UPD 另一种选择(工作在稍微不同的方式,你可以有NULL值不仅为最后记录orderid,但它将完全按日期排序,在一个时间轴上):

select o.orderid, ap.transactiondate, ap.amount, pp.projecteddate, pp.projectedamount 
from orders o 
inner join 
(
    select ap.orderid, ap.transactiondate d from payment ap 
    union 
    select ap.orderid, ap.projecteddate d from projectedpayment pp 
) d on d.orderid = o.orderid 
left join payment ap on ap.orderid = o.orderid and ap.transactiondate = d.d 
left join projectedpayment pp on pp.orderid = o.orderid and pp.projecteddate = d.d 
order by o.orderid, d.d
+0

这是不是有问题,如果有更多的预计付款比实际? – gordatron

+1

好点。我固定条件工作,如果有预计的付款,但没有实际支付与相同的号码 – oryol

+0

你不需要强迫那里有一行o.orderid不为空,pn为空,以允许第三表加入它?对不起,我很好奇,因为我以前没有使用过这种技术,它的有趣的 – gordatron