打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
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:
DEPTNODNAMELOC
10ACCOUNTINGNEW YORK
20RESEARCHDALLAS
30SALESCHICAGO
40OPERATIONSBOSTON
emp:
DEPTNOEMPNOENAMEJOBMGRHIREDATESALCOMM
107782CLARKMANAGER78391981-6-92450.00 
107839KINGPRESIDENT 1981-11-175000.00 
107934MILLERCLERK77821982-1-231300.00 
207369SMITHCLERK79021980-12-17800.00 
207566JONESMANAGER78391981-4-22975.00 
207788SCOTTANALYST75661987-4-193000.00 
207876ADAMSCLERK77881987-5-231100.00 
207902FORDANALYST75661981-12-33000.00 
307499ALLENSALESMAN76981981-2-201600.00300.00
307521WARDSALESMAN76981981-2-221250.00500.00
307654MARTINSALESMAN76981981-9-281250.001400.00
307698BLAKEMANAGER78391981-5-12850.00 
307844TURNERSALESMAN76981981-9-81500.000.00
307900JAMESCLERK76981981-12-3950.00 
dept对emp做外连接后的结果是:
DEPTNODNAMELOCEMPNOENAMEJOBMGRHIREDATESALCOMMDEPTNO
10ACCOUNTINGNEW YORK7782CLARKMANAGER78391981-6-92450.00 10
10ACCOUNTINGNEW YORK7839KINGPRESIDENT 1981-11-175000.00 10
10ACCOUNTINGNEW YORK7934MILLERCLERK77821982-1-231300.00 10
20RESEARCHDALLAS7369SMITHCLERK79021980-12-17800.00 20
20RESEARCHDALLAS7566JONESMANAGER78391981-4-22975.00 20
20RESEARCHDALLAS7788SCOTTANALYST75661987-4-193000.00 20
20RESEARCHDALLAS7876ADAMSCLERK77881987-5-231100.00 20
20RESEARCHDALLAS7902FORDANALYST75661981-12-33000.00 20
30SALESCHICAGO7499ALLENSALESMAN76981981-2-201600.00300.0030
30SALESCHICAGO7521WARDSALESMAN76981981-2-221250.00500.0030
30SALESCHICAGO7654MARTINSALESMAN76981981-9-281250.001400.0030
30SALESCHICAGO7698BLAKEMANAGER78391981-5-12850.00 30
30SALESCHICAGO7844TURNERSALESMAN76981981-9-81500.000.0030
30SALESCHICAGO7900JAMESCLERK76981981-12-3950.00 30
40OPERATIONSBOSTON        
最后一行,编号为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' ,上面两种情况都是对于条件是在右边的表的情况,如果条件是在左边的表中呢?加上(+)又是什么效果?
 
 因为左连接在没有其他任何条件的情况下,会将左边表中的所有记录都列出来,实验发现,当条件中只有关于左边表中的条件时,无论!=还是=的情况,不论加上(+)还是不加,效果都是一样的,都不会有多余记录列出。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Oracle 19c 新特性:ANY_VALUE 函数和 LISTAGG 的增强
Oracle中表的连接及其调整
Oracle笔记(七) 数据更新、事务处理、数据伪列
Oracle笔记之select查询
SQLPLUS命令的使用大全—编程爱好者网站 http://www.programfan.com
表的基本查询(重要)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服