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
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
- 其次,再來看=號的情況
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
- 注意:
因爲左連接在沒有其他任何條件的情況下,會將左邊表中的所有記錄都列出來,實驗發現,當條件中只有關於左邊表中的條件時,無論!=還是=的情況,不論加上(+)還是不加,效果都是一樣的,都不會有多餘記錄列出。