ORACLE外连接

今天开发过程中遇到了一个很麻烦的外连接的问题,到最后都没有找到很好的解决方法,最后只能用union all 实现了,虽然性能不比外连接,但至少拓展了外连接的局限性。

  首先给出我测试用的三个表和数据(左右外连接道理是一样的,我只总结了左连接):

KC21表:
create table KC21
(
  AKB020 VARCHAR2(14) not null,
  AKC190 VARCHAR2(18) not null,
  AAC001 VARCHAR2(20) not null
);
INSERT INTO KC21  (AKB020, AKC190, AAC001) VALUES('110', '266', '1302012062942');
INSERT INTO KC21  (AKB020, AKC190, AAC001) VALUES('456', '369', '1302012063210');
INSERT INTO KC21  (AKB020, AKC190, AAC001) VALUES('1000', '472', '1302012045811');
INSERT INTO KC21  (AKB020, AKC190, AAC001) VALUES('123', '335', '1302012063275');
KC24表:
create table KC24
(
  AKB020 VARCHAR2(14) not null,
  AKC190 VARCHAR2(18) not null,
  AAE072 VARCHAR2(20) not null
);
insert into KC24 (AKB020, AKC190, AAE072)values ('110', '335', '2188038055');
insert into KC24 (AKB020, AKC190, AAE072)values ('11', '369', '2188038092');
insert into KC24 (AKB020, AKC190, AAE072)values ('1000', '472', '2188038197');
insert into KC24 (AKB020, AKC190, AAE072)values ('110', '339', '2188038058');
KB01表:
create table KB01
(
  AKB020 VARCHAR2(14) not null,
  AKB021 VARCHAR2(50)
);
insert into KB01 (AKB020, AKB021)values ('1000', '唐山实时测试医院');
insert into KB01 (AKB020, AKB021)values ('110', '唐山大医院A');
insert into KB01 (AKB020, AKB021)values ('123', '唐山大医院B');
insert into KB01 (AKB020, AKB021)values ('456', '唐山大医院C');
insert into KB01 (AKB020, AKB021)values ('11', '唐山大医院D');
     oracle官方提供了两种方来实现外连接,一种是在from子句中使用left outer join/right outer join/full outer join,另外一种是在where子句中使用大家都比较熟悉的符号“(+)”,这里我想写一下我对这两个方法的理解。

一、使用一个连接条件的外连接:

SQL> select * from kc21 left outer join kc24 on kc21.akb020=kc24.akb020;
 
AKB020         AKC190             AAC001               AKB020         AKC190             AAE072
-------------- ------------------ -------------------- -------------- ------------------ --------------------
110            266                1302012062942        110            335                2188038055
1000           472                1302012045811        1000           472                2188038197
110            266                1302012062942        110            339                2188038058
123            335                1302012063275                                          
456            369                1302012063210                                          
 
SQL> select * from kc21 ,kc24 where kc21.akb020=kc24.akb020(+);
 
AKB020         AKC190             AAC001               AKB020         AKC190             AAE072
-------------- ------------------ -------------------- -------------- ------------------ --------------------
110            266                1302012062942        110            335                2188038055
1000           472                1302012045811        1000           472                2188038197
110            266                1302012062942        110            339                2188038058
123            335                1302012063275                                          
456            369                1302012063210 
不难看出这两个语句查询的结果是一样的,因此我们可以说这两种语法是可以转化的,但是很明显第一种写法比较好理解,这也是oracle官方建议的。官方文档是这样说的:Oracle recommends that you use the FROM clause OUTER JOIN syntax rather than the Oracle join operator。
        KC21中的akb020与KC24中相等的有110和1000,在KC24中有两个akb020为110的记录,因此结果产生三条连接上的,把没有匹配剩下的两条显示出来,对应KC24的项以NULL填充,这也是左外连接要实现的目的。

二、使用两个连接条件的情况:

SQL> select * from kc21 left outer join kc24 on (KC21.akb020=kc24.akb020 and KC21.akc190=KC24.akc190);
 
AKB020         AKC190             AAC001               AKB020         AKC190             AAE072
-------------- ------------------ -------------------- -------------- ------------------ --------------------
1000           472                1302012045811        1000           472                2188038197
110            266                1302012062942                                          
123            335                1302012063275                                          
456            369                1302012063210                                          
 
SQL> select * from kc21,kc24 where kc21.akb020=kc24.akb020(+) and kc21.akc190=KC24.akc190(+);
 
AKB020         AKC190             AAC001               AKB020         AKC190             AAE072
-------------- ------------------ -------------------- -------------- ------------------ --------------------
1000           472                1302012045811        1000           472                2188038197
110            266                1302012062942                                          
456            369                1302012063210                                          
123            335                1302012063275
不难看出这两个语句查询的结果也是一样的,这两个语句是等价的。意思是只有AKB020和akc190同时相等才算匹配。同样很明显还是第一个语句好理解。有时候直接给出第二个语句,我们很难想象最终会是一个什么样的结果。这里还是Oracle官方给出了我们为什么要这样写的理由:If A and B are joined by multiple join conditions, then you must use the (+) operator in all of these conditions.
三、三个表其中两个表有外连接关系,另外一个表没有外连接关系,oracle不允许在一个SQL语句中一个表外连接两个表:
SQL> SELECT A.akb020, A.AKC190, B.akb020, B.akc190, C.akb021
  2    FROM kc21 A, kc24 B, kb01 C
  3   WHERE A.akb020 = B.akb020(+)
  4     AND A.akc190 = B.akc190(+)
  5     AND A.akb020 = C.akb020;
 
AKB020         AKC190             AKB020         AKC190             AKB021
-------------- ------------------ -------------- ------------------ --------------------------------------------------
1000           472                1000           472                唐山实时测试医院
110            266                                                  唐山大医院A
123            335                                                  唐山大医院B
456            369                                                  唐山大医院C
可以看出这就好像是在第二步的基础上关联第三个表将医院编码转化为医院名称,得出这样的结果是很好理解的。
四、两个连接的表中,连接条件有两个,一个是外连接,一个是内连接,这样的话,会是什么样的结果呢:
SQL> select * from kc21,kc24 where kc21.akb020=kc24.akb020(+);
 
AKB020         AKC190             AAC001               AKB020         AKC190             AAE072
-------------- ------------------ -------------------- -------------- ------------------ --------------------
110            266                1302012062942        110            335                2188038055
1000           472                1302012045811        1000           472                2188038197
110            266                1302012062942        110            339                2188038058
123            335                1302012063275                                          
456            369                1302012063210                                          
 
SQL> select * from kc21,kc24 where kc21.akc190=kc24.akc190;
 
AKB020         AKC190             AAC001               AKB020         AKC190             AAE072
-------------- ------------------ -------------------- -------------- ------------------ --------------------
123            335                1302012063275        110            335                2188038055
456            369                1302012063210        11             369                2188038092
1000           472                1302012045811        1000           472                2188038197
 
SQL> select * from kc21,kc24 where kc21.akb020=kc24.akb020(+) and  kc21.akc190=kc24.akc190;
 
AKB020         AKC190             AAC001               AKB020         AKC190             AAE072
-------------- ------------------ -------------------- -------------- ------------------ --------------------
1000           472                1302012045811        1000           472                2188038197
 
SQL> select * from kc21,kc24 where kc21.akb020=kc24.akb020 and  kc21.akc190=kc24.akc190;
 
AKB020         AKC190             AAC001               AKB020         AKC190             AAE072
-------------- ------------------ -------------------- -------------- ------------------ --------------------
1000           472                1302012045811        1000           472                2188038197
在上面几个SQL语句用有了一个和第二个,我们很自然的能过得到第三个,这也是符合常理的,第三个结果集刚好是第一和第二的交集。现在要说明的是第三个和第四个SQL语句效果是一样的,因为在有多个连接条件的两个表在连接时如果没有都写上“(+)”,那么oracle视同简单的等值内连接。这也是oracle官方声明的:If Aand B are joined by multiple join conditions, then you must use the (+) operator in all of these conditions. If you do not, then Oracle Database will return only the rows resulting from a simple join, but without a warning or error to advise you that you do not have the results of an outer join.

五、全外连接
oracle对于全连接不支持在连接条件的左右都加“(+)”,只有一种方式,就是在from子句中使用full outer join ,在on子句中加连接条件:

SQL> select * from kc21 full outer join kc24 on (kc21.akb020=KC24.akb020);
 
AKB020         AKC190             AAC001               AKB020         AKC190             AAE072
-------------- ------------------ -------------------- -------------- ------------------ --------------------
110            266                1302012062942        110            335                2188038055
1000           472                1302012045811        1000           472                2188038197
110            266                1302012062942        110            339                2188038058
123            335                1302012063275                                          
456            369                1302012063210                                          
                                                       11             369                2188038092
 
6 rows selected
这个结果很好理解,满足匹配条件的作为一条成功记录返回,不满足对应另外一个表的字段都以NULL填充。
六、结束!


你可能感兴趣的:(ORACLE外连接)