在一个表上加入两个表,而不是每个记录的mutyplying行

时间:2013-11-15 10:55:57

标签: sql oracle

假设我们有3个名为TRANSACTIONSORDERSPAYMENTS的表,所有这些表都有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万条记录,ORDERSPAYMENTS都有150米以上的记录,我们需要返回大约100万条记录。

2 个答案:

答案 0 :(得分:1)

在这种情况下,您应该向OrdersPayments表添加一个额外的RowNumber列(使用ROW_NUMBER() OVER),然后将其与此列连接。

SQLFiddle demo

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() ...生成序列作为序列生成器的最大数量。

SQLFiddle demo

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