Oracle外連接中對非連接條件使用(+)需要注意的地方

Oracle外連接中對非連接條件使用(+)需要注意的地方

 

1.先來說下Oracle外連接語句中對非鏈接條件使用(+)的作用問題

 

之前問過朋友,當時大腦處於短路狀態,居然沒想明白作用是啥。先看例子如下:

 

select * from dept,emp where dept.deptno=emp.deptno(+) and emp.ename(+)!='KING';
使用scott賬戶登錄,執行上面的sql語句,可以分析出此sql語句的意圖是將部門表和員工表進行左外鏈,找出鏈接中員工名字不爲‘KING’的記 錄,在emp.ename後面加上(+)後,名字爲空的記錄也會列出來,即沒有員工的部門也會列出來,如果不加(+),這樣的記錄就列不出來。

 

2.上面是使用oracle自己的外聯結語法的sql語句,如果使用ANSIsql1992標準,即left join,那麼情況會有所變化,(+)不能同時和ANSI標準的join一起使用,那麼我想emp.ename後面的(+)應該變成 emp.ename is null,(可經過試驗,發現根據ename字段的類型不同,結果有所不同,一下列出幾個sql語句,供試驗,待有執行環境後,整理之,本次只整理了varchar的情況)

 

--vacrchar類型
    select * from dept,emp where dept.deptno=emp.deptno(+) and emp.ename!='KING';
    select * from dept left join emp on(dept.deptno=emp.deptno) where emp.ename!='KING';

 

select * from dept,emp where dept.deptno=emp.deptno(+) and emp.ename(+)!='KING';
    select * from dept left join emp on(dept.deptno=emp.deptno) where emp.ename!='KING' or emp.ename is null;

 

--number類型
    select * from dept,emp where dept.deptno=emp.deptno(+) and emp.empno!=7782;
    select * from dept left join emp on(dept.deptno=emp.deptno) and emp.empno!=7782;

 

select * from dept,emp where dept.deptno=emp.deptno(+) and emp.empno(+)!=7782;
    select * from dept left join emp on(dept.deptno=emp.deptno) and emp.empno!=7782 or emp.empno is null;
--char類型又不一樣

 

(以上用!='KING',用=‘KING’又將如何?)

 

----------------------------------------------------------------------------------------------

 

分析:

先列出兩張表的數據

 

dept:

DEPTNO DNAME LOC
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON

 

 

emp:

DEPTNO EMPNO ENAME JOB MGR HIREDATE SAL COMM
10 7782 CLARK MANAGER 7839 1981-6-9 2450.00  
10 7839 KING PRESIDENT   1981-11-17 5000.00  
10 7934 MILLER CLERK 7782 1982-1-23 1300.00  
20 7369 SMITH CLERK 7902 1980-12-17 800.00  
20 7566 JONES MANAGER 7839 1981-4-2 2975.00  
20 7788 SCOTT ANALYST 7566 1987-4-19 3000.00  
20 7876 ADAMS CLERK 7788 1987-5-23 1100.00  
20 7902 FORD ANALYST 7566 1981-12-3 3000.00  
30 7499 ALLEN SALESMAN 7698 1981-2-20 1600.00 300.00
30 7521 WARD SALESMAN 7698 1981-2-22 1250.00 500.00
30 7654 MARTIN SALESMAN 7698 1981-9-28 1250.00 1400.00
30 7698 BLAKE MANAGER 7839 1981-5-1 2850.00  
30 7844 TURNER SALESMAN 7698 1981-9-8 1500.00 0.00
30 7900 JAMES CLERK 7698 1981-12-3 950.00  

 

 

dept對emp做外連接後的結果是:

DEPTNO DNAME LOC EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
10 ACCOUNTING NEW YORK 7782 CLARK MANAGER 7839 1981-6-9 2450.00   10
10 ACCOUNTING NEW YORK 7839 KING PRESIDENT   1981-11-17 5000.00   10
10 ACCOUNTING NEW YORK 7934 MILLER CLERK 7782 1982-1-23 1300.00   10
20 RESEARCH DALLAS 7369 SMITH CLERK 7902 1980-12-17 800.00   20
20 RESEARCH DALLAS 7566 JONES MANAGER 7839 1981-4-2 2975.00   20
20 RESEARCH DALLAS 7788 SCOTT ANALYST 7566 1987-4-19 3000.00   20
20 RESEARCH DALLAS 7876 ADAMS CLERK 7788 1987-5-23 1100.00   20
20 RESEARCH DALLAS 7902 FORD ANALYST 7566 1981-12-3 3000.00   20
30 SALES CHICAGO 7499 ALLEN SALESMAN 7698 1981-2-20 1600.00 300.00 30
30 SALES CHICAGO 7521 WARD SALESMAN 7698 1981-2-22 1250.00 500.00 30
30 SALES CHICAGO 7654 MARTIN SALESMAN 7698 1981-9-28 1250.00 1400.00 30
30 SALES CHICAGO 7698 BLAKE MANAGER 7839 1981-5-1 2850.00   30
30 SALES CHICAGO 7844 TURNER SALESMAN 7698 1981-9-8 1500.00 0.00 30
30 SALES CHICAGO 7900 JAMES CLERK 7698 1981-12-3 950.00   30
40 OPERATIONS BOSTON                

最後一行,編號爲40的部門是外連接的效果,emp表對應的字段都爲空

  • 首先,對於!=號,varchar

 

   現在考慮如下情況,如果想要找出所有部門中員工姓名不爲King的員工和部門都找出來,並且沒有員工的部門也列出來,那麼一般會想到用
select * from dept,emp where dept.deptno=emp.deptno(+) and emp.ename!='KING';
這條sql語句,但是發現40這個部門並不在結果中,也就是說,最後一行中雖然emp的ename爲空,符合!=‘KING’的條件,但卻沒有作爲結果返 回,似乎oracle認爲這條記錄不存在,於是想要這條結果出來,那麼必須在條件emp.ename!='KING'處加上一個(+)即
select * from dept,emp where dept.deptno=emp.deptno(+) and emp.ename(+)!='KING',使得好像是外聯結果產生的記錄中對應於emp表的ename字段的值是任何一個不爲‘KING’的字符串,這樣這條記錄便被算作是結果列了出來。
    同樣,使用ANSI語法的語句
select * from dept left join emp on(dept.deptno=emp.deptno) where emp.ename!='KING'
也沒有達到效果,仍然將外聯結產生的記錄排除在外了,如果想要包含該條記錄,就應該加上emp.ename is null,即
select * from dept left join emp on(dept.deptno=emp.deptno) where emp.ename!='KING' or emp.ename is null
  • 其次,再來看=號的情況
    再來看這樣一個需求,如果我們想看一下每個部門及其助理的信息,並且如果該部門沒有助理的話,把部門信息列出來,助理的信息顯示空,那麼我們可能會想到如下sql
select * from dept,emp where dept.deptno=emp.deptno(+) and emp.job='ASSISTENT'
但是結果是沒有任何記錄,因爲外聯結結果中沒有任何記錄符合其員工職位爲ASSITENT,如果要達到我們的要求,sql語句應該寫爲
select * from dept,emp where dept.deptno=emp.deptno(+) and emp.job(+)='ASSISTENT' ,
(+)的作用就好象是使oracle造出了這樣的外聯結記錄,部門的員工中有一個的工作職位是ASSISTENT,但因爲實際並沒有這樣的記錄,所以這條記錄的emp表的字段都是空。
    我們可能希望ANSI格式的SQL語句也能達到這樣的效果,你也許可能想到加上emp.job is null不久可以了麼,但是那樣只會列出外連接記錄,即部門40的記錄,部門10,20和30的記錄都不會列出來.
所以需要做如下變通,通過左外連接一個子查詢來實現:
select * from dept left join (select * from emp where ename='ASSISTENT') t on dept.deptno=t.deptno

  • 注意:
     如上的分析是dept對emp進行左外聯,外聯條件也是dept.deptno=emp.deptno(+),我們注意到(+)是加在右邊的表上,而條件中我們的(+)也是加在右邊表的字段上,而不是常量值上,如emp.job(+)='ASSISTENT' ,上面兩種情況都是對於條件是在右邊的表的情況,如果條件是在左邊的表中呢?加上(+)又是什麼效果?
 
 因爲左連接在沒有其他任何條件的情況下,會將左邊表中的所有記錄都列出來,實驗發現,當條件中只有關於左邊表中的條件時,無論!=還是=的情況,不論加上(+)還是不加,效果都是一樣的,都不會有多餘記錄列出。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章