Oracle仅从表A获取数据,仅从表B获取并共享

时间:2014-05-04 20:40:34

标签: sql oracle select join

我需要获取报告数据。我有2张桌子A和B. 表A有许多相同ID的插入,可以在此表中只有条目或与表B共享数据, 表B只能包含此表中的条目或与表A共享数据。

 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中的所有内容,表A中的所有内容,但A中的内容以及它们共享的内容,但如果B与A连接 - 它应该从表A返回最近的条目,其中包含来自B表的a_id。 / p>

所以我希望能够被退回:

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);

有没有更好的方法来使用join(我试过但它总是让我回复超过我的期望)?只运行一个或两个查询而不是3?

以下是小提琴示例的链接:http://sqlfiddle.com/#!4/9fdb3/3

由于

1 个答案:

答案 0 :(得分: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;

扭曲是在where子句中处理奇怪的排序逻辑 - 当匹配时你只需要最近的A,而当没有匹配时你想要所有的{{1}}。这会在SQL Fiddle中产生您想要的结果。