Reputation: 271
This problem is difficult to describe, especially in the title. Perhaps it would be easier to show what I am trying to accomplish. This is an Oracle database.
Given the following 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');
I am trying to get the following result:
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
The part I'm struggling with is when the city is both a receipt and a delivery and getting it to show on one row as RECDEL. I've tried various combinations of UNIONs, INTERSECTs and FULL OUTER JOINs to no avail. Could LISTAGG be used? Not sure how that work work with the multiple columns. Any help would be appreciated.
Upvotes: 1
Views: 69
Reputation: 4751
There is probably a cleaner way, but this works:
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;
Upvotes: 1
Reputation: 13334
Here's a solution with LISTAGG
. It produces Delivery Receipt
instead of RECDEL
. I hope it's enough for you to get the idea.
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, '');
Upvotes: 1
Reputation: 35553
| 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 |
by:
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
see: http://sqlfiddle.com/#!4/57f0b/1
Upvotes: 2