Oracle Query在3个表上有2个外连接

时间:2017-02-20 17:11:59

标签: oracle11g outer-join ansi

我在编写一个看似简单的查询时遇到了一些麻烦,但解决方案却在逃避我。

我们有三个表(为了这个问题而简化): 人员 - 用户名表:

  per_id      number(10) - primary key, populated by a sequence
  user_name   varchar2(50)
  user_id     varchar2(15) - unique, basically the employee ID

work_assignments - 有点像船员任务,但更一般:

  wa_id     number(10) - primary key, populated by a sequence
  wa_name   varchar2(25)

current_assignments - 哪些用户拥有哪个work_assignments;每个用户的平均约25个工作任务,但有些"幸运"个人有150以上:

  wa_id   number(10)
  per_id  number(10)

我尝试编写一个查询,比较两个用户的work_assignments,总共三列。结果应如下所示:

WA_Name   User_Name1    User_Name2
Crew A    Bob           Joe
Crew B                  Joe
Crew C    Bob

基本上,两个用户中的任何一个具有的每个work_assignment,以及拥有它的用户的名称。

这是我能提出的最接近的(好吧,我确实提出了一个丑陋的查询,其中有3个子查询可以完成这项工作,但似乎应该有一个更优雅的解决方案):

select distinct * from (
  select wa.name      work_assignment,
         per.name     user_name1,
         per2.name    user_name2
    from work_assignments  wa join current_assignments ca  on wa.wa_id = ca.wa_id
                              join current_assignments ca2 on wa.wa_id = ca2.wa_id
                   left outer join persons per  on per.per_id  = ca.per_id  and per.user_id  = 'X12345'
                   left outer join persons per2 on per2.per_id = ca2.per_id and per2.user_id = 'Y67890'
                   )
   where user_name1 is not null or user_name2 is not null
   order by 1;

这个问题是,如果两个用户都有工作任务,它会显示3条记录:一条用于Bob,一条用于Joe,一条用于两者:

WA_Name   User_Name1    User_Name2
Crew A    Bob           Joe
Crew A                  Joe
Crew A    Bob

请帮忙!

谢谢, 丹

1 个答案:

答案 0 :(得分:1)

我创建了一组示例数据/表

drop table persons;
drop table work_assgn;
drop table curr_assgn;


create table persons(
  per_id number(10) not null
, user_name varchar2(10) not null
, user_id varchar2(10) not null
)
;

insert into persons values( 1, 'Bob', 'X123' );
insert into persons values( 2, 'Joe', 'Y456' );
insert into persons values( 3, 'Mike', 'Z789' );
insert into persons values( 4, 'Jeff', 'J987' );

commit;

create table work_assgn(
  wa_id number(10) not null
, wa_name varchar2(25)
)
;

insert into work_assgn values( 10, 'Crew A' );
insert into work_assgn values( 20, 'Crew B' );
insert into work_assgn values( 30, 'Crew C' );
insert into work_assgn values( 40, 'Crew D' );

commit;

create table curr_assgn(
  wa_id number(10) not null
, per_id number(10) not null
)
;

insert into curr_assgn values( 10, 1 );
insert into curr_assgn values( 10, 2 );
insert into curr_assgn values( 20, 2 );
insert into curr_assgn values( 30, 1 );
insert into curr_assgn values( 40, 4 );

commit;


select * from persons;
select * from work_assgn;
select * from curr_assgn;

所以数据看起来像

PERSONS
    PER_ID USER_NAME  USER_ID
---------- ---------- ----------
         1 Bob        X123
         2 Joe        Y456
         3 Mike       Z789
         4 Jeff       J987


WORK_ASSGN
     WA_ID WA_NAME
---------- -------------------------
        10 Crew A
        20 Crew B
        30 Crew C
        40 Crew D

CURRASSGN
     WA_ID     PER_ID
---------- ----------
        10          1
        10          2
        20          2
        30          1
        40          4

一种方法可能是使用PIVOT

with assignment as
(
select  p.user_id, p.user_name, a.wa_name
from persons p
join curr_assgn c
  on p.per_id =c.per_id
join work_assgn a
  on a.wa_id = c.wa_id
where p.user_id in ( 'X123', 'Y456' )
)
select * from assignment
pivot
( max(user_name) for user_id in ( 'X123', 'Y456' )
)
;