查询两个相似的表并合并排序的结果
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
到其他两个表的某种 union
的 left join
来实现这一点,并用 order by
排序,但我没能让它发挥作用,所以它可能是完全不同的东西。我知道我不能加入 order
、payment
和 projectedpayment
这三个表,否则我会得到后两个表的叉积。
我碰巧使用的是 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
*这也不会显示没有付款或预测的订单。如果这是一个问题,请发表评论。
我有三张表
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
到其他两个表的某种 union
的 left join
来实现这一点,并用 order by
排序,但我没能让它发挥作用,所以它可能是完全不同的东西。我知道我不能加入 order
、payment
和 projectedpayment
这三个表,否则我会得到后两个表的叉积。
我碰巧使用的是 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
*这也不会显示没有付款或预测的订单。如果这是一个问题,请发表评论。