查询两个相似的表并合并排序的结果

Query two similar tables and combine sorted results

我有三张表

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

如此按顺序细分,实际付款和预计付款是多少,预计付款可能比实际付款多,或实际付款比预计多,按日期对齐(只需对两者进行排序,没有什么比那)。

似乎我应该能够通过从 orders 到其他两个表的某种 unionleft join 来实现这一点,并用 order by 排序,但我没能让它发挥作用,所以它可能是完全不同的东西。我知道我不能加入 orderpaymentprojectedpayment 这三个表,否则我会得到后两个表的叉积。

我碰巧使用的是 postgresql 9.4,但希望我们不需要过于特定于数据库。

这应该有效

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

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

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 另一种选择(工作方式略有不同,您不仅可以为相同 orderid 的最后记录设置 NULL 值,而且会在一个时间轴中按日期完全排序):

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

我不知道 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+ AFAIK)

这里的逻辑是,您需要为每个预测和实际付款分配一个唯一编号,以便您可以将两个 table 连接在一起,但每一行仅与另一行匹配 table.

如果您每天只有一次付款,那么您可以对订单 ID 和日期进行完整连接,而不必担心行号。

完全连接允许你在两边都有空值,所以你需要合并 orderid

*这也不会显示没有付款或预测的订单。如果这是一个问题,请发表评论。