合并Oracle中一个表的数据

时间:2014-08-14 03:40:08

标签: sql oracle

这个问题很难描述,特别是在标题中。或许更容易展示我想要实现的目标。这是一个Oracle数据库。

给出以下DDL(http://sqlfiddle.com/#!4/e0730):

CREATE TABLE TEST_LIST(CONTRACT VARCHAR2(10), RECEIPT_CITY VARCHAR2(15), DELIVERY_CITY VARCHAR2(15));

INSERT INTO TEST_LIST VALUES ('CTR_01', 'DETROIT', '');
INSERT INTO TEST_LIST VALUES ('CTR_01', 'KALAMAZOO', '');
INSERT INTO TEST_LIST VALUES ('CTR_01', '', 'KALAMAZOO');
INSERT INTO TEST_LIST VALUES ('CTR_01', '', 'MUSKEGON');
INSERT INTO TEST_LIST VALUES ('CTR_01', 'SOUTH HAVEN', '');
INSERT INTO TEST_LIST VALUES ('CTR_02', 'BATTLE CREEK', '');
INSERT INTO TEST_LIST VALUES ('CTR_02', '', 'KALAMAZOO');

我想获得以下结果:

CONTRACT  CITY          DIRECTION
--------  ------------  -----------
CTR_01    DETROIT       RECEIPT
CTR_01    KALAMAZOO     RECDEL
CTR_01    MUSKEGON      DELIVERY
CTR_01    SOUTH HAVEN   DELIVERY
CTR_02    BATTLE CREEK  RECEIPT
CTR_02    KALAMAZOO     DELIVERY

我挣扎的部分是当城市既是收据又是交付时,让它在一行显示为RECDEL。我尝试过UNION,INTERSECT和FULL OUTER JOIN的各种组合无济于事。可以使用LISTAGG吗?不确定该工作如何与多列一起使用。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

| CONTRACT |         CITY | DIRECTION |
|----------|--------------|-----------|
|   CTR_01 |      DETROIT |   RECEIPT |
|   CTR_01 |    KALAMAZOO |    RECDEL |
|   CTR_01 |     MUSKEGON |  DELIVERY |
|   CTR_01 |  SOUTH HAVEN |   RECEIPT |
|   CTR_02 | BATTLE CREEK |   RECEIPT |
|   CTR_02 |    KALAMAZOO |  DELIVERY |

由:

select distinct
      t1.contract
    , case when t1.delivery_city = t2.receipt_city then t1.delivery_city
           when t1.delivery_city is not null       then t1.delivery_city
           when t1.receipt_city is not null        then t1.receipt_city
           else 'unexpected'
      end as CITY
    , case when t1.delivery_city = t2.receipt_city 
             or t1.receipt_city = t3.delivery_city  then 'RECDEL'
           when t1.delivery_city is not null        then 'DELIVERY'
           when t1.receipt_city is not null         then 'RECEIPT'
           else 'unexpected'
      end as DIRECTION
from TEST_LIST t1
left join test_list t2
 on t1.CONTRACT = t2.CONTRACT
 and t1.delivery_city = t2.receipt_city
left join test_list t3
 on t1.CONTRACT = t3.CONTRACT
 and t1.receipt_city = t3.delivery_city
order by
      t1.contract
    , CITY
    , DIRECTION

请参阅:http://sqlfiddle.com/#!4/57f0b/1

答案 1 :(得分:1)

可能有一种更清洁的方式,但这有效:

SELECT contract, receipt_city AS city, 'RECEIPT' as direction from test_list t1 where receipt_city IS NOT NULL AND NOT EXISTS (SELECT * FROM test_list t2 WHERE t2.contract = t1.contract and t2.delivery_city = t1.receipt_city )
UNION
SELECT contract, receipt_city AS city, 'RECDEL' as direction from test_list t1 where receipt_city IS NOT NULL AND EXISTS (SELECT * FROM test_list t2 WHERE t2.contract = t1.contract and t2.delivery_city = t1.receipt_city )
UNION
SELECT contract, delivery_city AS city, 'DELIVERY' as direction from test_list t1 where delivery_city IS NOT NULL AND NOT EXISTS (SELECT * FROM test_list t2 WHERE t2.contract = t1.contract and t2.receipt_city = t1.delivery_city )
ORDER BY contract;

答案 2 :(得分:1)

这是LISTAGG的解决方案。它会生成Delivery Receipt而不是RECDEL。我希望你能够理解这一点。

SELECT contract,
       COALESCE(receipt_city, delivery_city, '') "City",
       LISTAGG(CASE WHEN receipt_city IS NOT NULL THEN 'Receipt' END ||
               CASE WHEN delivery_city IS NOT NULL THEN 'Delivery' END,
              ' ') 
                 WITHIN GROUP (ORDER BY contract) "Direction"
FROM test_list
GROUP BY contract, COALESCE(receipt_city, delivery_city, '');

SQL Fiddle