假设我们有3个名为TRANSACTIONS
,ORDERS
,PAYMENTS
的表,所有这些表都有TRANSACTION_ID
。
这是我在加入包含5个订单和3次付款的交易时获得的常规输出:
transaction_id, order_id, payment_id
----------
1, 20, 35
1, 20, 36
1, 20, 37
1, 21, 35
1, 21, 36
1, 21, 37
....
我应该得到的是:
transaction_id, order_id, payment_id
----------
1, 20, 35
1, 21, 36
1, 22, 37
1, 23, null
1, 24, null
如果付款多于订单,则NULL
列中应该有order_id
。
基本上我需要每transaction_id
行的行数等于orders
/ payments
的更大数量(在此示例中为5> 3,所以5)。
请记住,每个表都有几百万条记录。
修改:
根据评论中的请求,上面的查询是简单的连接
SELECT t.transaction_id, o.order_id, p.payment_id
FROM TRANSACTION t
LEFT JOIN ORDERS o on o.transaction_id = t.transaction_id
LEFT JOIN PAYMENTS p on p.transaction_id = o.transaction_id
编辑2 :
我无法透露完整的表格方案,我只编写了查询工作必不可少的列。实际上,每个表都有20多列,查询应该返回大约20列的总和。
同样,TRANSACTIONS
有超过100万条记录,ORDERS
和PAYMENTS
都有150米以上的记录,我们需要返回大约100万条记录。
答案 0 :(得分:1)
在这种情况下,您应该向Orders
和Payments
表添加一个额外的RowNumber列(使用ROW_NUMBER() OVER),然后将其与此列连接。
select tr.transaction_id,
Orders.order_id,
Payments.payment_id
from TRANSACTIONS tr
LEFT JOIN
(
select transaction_id,order_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY order_id) as rn
FROM ORDERS
) Orders on tr.transaction_id=Orders.transaction_id
LEFT JOIN
(
select transaction_id,payment_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY payment_id) as rn
FROM PAYMENTS
) Payments on (tr.transaction_id=Payments.transaction_id)
AND (Orders.rn=Payments.rn)
UNION
select tr.transaction_id,
Orders.order_id,
Payments.payment_id
from TRANSACTIONS tr
LEFT JOIN
(
select transaction_id,payment_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY payment_id) as rn
FROM PAYMENTS
) Payments on (tr.transaction_id=Payments.transaction_id)
LEFT JOIN
(
select transaction_id,order_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY order_id) as rn
FROM ORDERS
) Orders on tr.transaction_id=Orders.transaction_id
AND (Orders.rn=Payments.rn)
另一种方式就是没有结合。在这种情况下,我们需要生成序列1,2,3,4 ....然后JOIN两个表也与RowNumber连接到此序列。在这个例子中,我们生成从1到1000(CONNECT BY LEVEL <= 1000
)的序列。如果您不知道可能的最大行数是多少,那么您可以使用两个表中的select COUNT() ...
生成序列作为序列生成器的最大数量。
select tr.transaction_id,
Orders.order_id,
Payments.payment_id
from TRANSACTIONS tr
CROSS JOIN
(SELECT LEVEL as rn
FROM dual
CONNECT BY LEVEL <= 1000
) Cnt
LEFT JOIN
(
select transaction_id,order_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY order_id) as rn
FROM ORDERS
) Orders on (tr.transaction_id=Orders.transaction_id)
AND
(cnt.rn=Orders.rn )
LEFT JOIN
(
select transaction_id,payment_id,
ROW_NUMBER()
OVER (PARTITION BY transaction_id ORDER BY payment_id) as rn
FROM PAYMENTS
) Payments on (tr.transaction_id=Payments.transaction_id)
AND
(cnt.rn=Payments.rn)
WHERE Payments.payment_id IS NOT NULL or
Orders.Order_id IS NOT NULL
order by tr.transaction_id,cnt.rn
答案 1 :(得分:1)
你应该结合两个结果并检查行,如下所示:
select transaction_id, sum(order_id) as order_id, sum(payment_id) as payment_id
from
(
SELECT t.transaction_id,
ROW_NUMBER() OVER (PARTITION BY t.transaction_id ORDER BY order_id) RowNo,
o.order_id,
null as payment_id
FROM TRANSACTIONS t
LEFT JOIN ORDERS o on o.transaction_id = t.transaction_id
union
SELECT t.transaction_id,
ROW_NUMBER() OVER (PARTITION BY t.transaction_id ORDER BY payment_id) RowNo,
null as order_id,
p.payment_id
FROM TRANSACTIONS t
LEFT JOIN Payments p on p.transaction_id = t.transaction_id
) tt
group by transaction_id, RowNo
SQL小提琴演示:http://sqlfiddle.com/#!3/e991d/21
更新:
请尝试使用JOIN代替UNION,如下所示:
SELECT t1.transaction_id, t1.order_id, t2.payment_id
from
(
SELECT t.transaction_id,
ROW_NUMBER() OVER (PARTITION BY t.transaction_id ORDER BY order_id) RowNo,
o.order_id
FROM TRANSACTIONS t
LEFT JOIN ORDERS o on o.transaction_id = t.transaction_id
) t1
full join
(
SELECT t.transaction_id,
ROW_NUMBER() OVER (PARTITION BY t.transaction_id ORDER BY p.payment_id) RowNo,
p.payment_id
FROM TRANSACTIONS t
LEFT JOIN Payments p on p.transaction_id = t.transaction_id
) t2
on t1.transaction_id = t2.transaction_id and t1.RowNo = t2.RowNo
SQL小提琴演示:http://sqlfiddle.com/#!3/e991d/20