2014-05-04 54 views
0

我需要爲報告獲取數據。我有2個表A和B. 表A有許多用於相同ID的插入,並且可以只有表中的條目或與表B共享數據, 表B可以只有表中的條目或與表A共享數據。Oracle僅從表A獲取數據,僅從表B獲取並共享

Create table A (
    id number, 
    name varchar2(30), 
    seq number 
); 

Create table B (
    name_s varchar2 (30), 
    a_id number 
); 

insert into A (id, name,seq) values (1, 'first',1); 
insert into A (id, name,seq) values (3, 'first',2); 
insert into A (id, name,seq) values (1, 'second',3); 
insert into A (id, name,seq) values (2, 'first',4); 
insert into A (id, name,seq) values (2, 'second',5); 
insert into A (id, name,seq) values (1, 'third',6); 
insert into A (id, name,seq) values (3, 'second',7); 
insert into A (id, name,seq) values (1, 'fourth',8); 
insert into A (id, name,seq) values (1, 'fifth',9); 
insert into A (id, name,seq) values (1, 'sixth',10); 
insert into A (id, name,seq) values (2, 'third',11); 
insert into A (id, name,seq) values (3, 'third',12); 

insert into B (name_s, a_id) values ('sale1', 3); 
insert into B (name_s, a_id) values ('sale2', null); 
insert into B (name_s, a_id) values ('sale3', 1); 

現在我想返回的數據: 一切從表A,但不是在B,一切從表B,而不是在A和一切他們分享什麼,但如果B連接與A - 它應該從B表中返回最近的條目與來自B表的a_id。

所以我希望退貨:

column headers: A_id, A_name, A_seq, B_name 
    --everything what is not in table B 
     (2, 'first',4, null); 
     (2, 'second',5, null); 
     (2, 'third',11, null); 
    --everything what is not in table A 
    (null, null,null, 'sale2'); 
    --everything what is shared 
    (3, 'third', 12,'sale1'); 
    (1, 'sixth', 10,'sale3'); 

我的解決方案是運行3個查詢來獲得這些數據:

--just from table A 
select * from A where id not in (select nvl(a_id,-1) from B); 
--just from table B 
select * from B where a_id is null; 
--shared 
select * from B,A where B.a_id = A.id and A.seq = 
(select max(seq) from A where A.id = B.a_id); 

有沒有更好的辦法是使用連接做(我試過但它總是讓我比預期的更多)?只運行一個或兩個而不是3個查詢?

這裏是鏈接到小提琴例如:http://sqlfiddle.com/#!4/9fdb3/3

感謝

回答

3

如果我理解正確的邏輯,你可以做你想做一個full outer join和一些額外的邏輯是什麼:

select coalesce(a.id, b.a_id) as id, 
     a.name, 
     a.seq, 
     b.name_s, 
     (case when a.id is not null and b.name_s is not null 
      then 'Both' 
      when a.id is not null 
      then 'A-Only' 
      else 'B-Only' 
     end) as which 
from (select a.*, 
      row_number() over (partition by id order by seq desc) as seqnum 
     from a 
    ) a full outer join 
    b 
    on a.id = b.a_id 
where b.name_s is not null and coalesce(a.seqnum, 1) = 1 or b.name_s is null; 

的Twist正在處理where子句中的奇怪排序邏輯 - 只有最近的A存在匹配時纔有效,而當沒有匹配時只需要最新的A。這會在SQL小提琴中產生你想要的結果。