SQL 在外连接查询里使用OR逻辑

SQL 在外连接查询里使用OR逻辑,你想返回部门编号为 10 和 20 的全体员工的名子和部门信息,以及部门编号为 30 和 40 的部门信息(但不包含员工信息)。你最初试图这样做。

SQL 在外连接查询里使用OR逻辑 问题描述

你想返回部门编号为 10 和 20 的全体员工的名子和部门信息,以及部门编号为 30 和 40 的部门信息(但不包含员工信息)。你最初试图这样做。

select e.ename, d.deptno, d.dname, d.loc
  from dept d, emp e
 where d.deptno = e.deptno
   and (e.deptno = 10 or e.deptno = 20)
 order by 2
 
ENAME       DEPTNO DNAME          LOC
------- ---------- -------------- -------------
CLARK           10 ACCOUNTING     NEW YORK
KING            10 ACCOUNTING     NEW YORK
MILLER          10 ACCOUNTING     NEW YORK
SMITH           20 RESEARCH       DALLAS
ADAMS           20 RESEARCH       DALLAS
FORD            20 RESEARCH       DALLAS
SCOTT           20 RESEARCH       DALLAS
JONES           20 RESEARCH       DALLAS

以上查询里的连接操作是内连接,因此返回的结果集里不包含 DEPTNO 是 30 和 40 的部门信息。
在下面的查询里你又试图将 EMP 表外连接到 DEPT 表,但仍然没有得到正确的结果集。

select e.ename, d.deptno, d.dname, d.loc
  from dept d left join emp e
    on (d.deptno = e.deptno)
 where e.deptno = 10
    or e.deptno = 20
 order by 2
 
ENAME       DEPTNO DNAME          LOC
------- ---------- -------------- -----------
CLARK           10 ACCOUNTING     NEW YORK
KING            10 ACCOUNTING     NEW YORK
MILLER          10 ACCOUNTING     NEW YORK
SMITH           20 RESEARCH       DALLAS
ADAMS           20 RESEARCH       DALLAS
FORD            20 RESEARCH       DALLAS
SCOTT           20 RESEARCH       DALLAS
JONES           20 RESEARCH       DALLAS

其实,你只是希望得到如下所示的结果集。

ENAME       DEPTNO DNAME          LOC
------- ---------- -------------- ---------
CLARK           10 ACCOUNTING     NEW YORK
KING            10 ACCOUNTING     NEW YORK
MILLER          10 ACCOUNTING     NEW YORK
SMITH           20 RESEARCH       DALLAS
JONES           20 RESEARCH       DALLAS
SCOTT           20 RESEARCH       DALLAS
ADAMS           20 RESEARCH       DALLAS
FORD            20 RESEARCH       DALLAS
                30 SALES          CHICAGO
                40 OPERATIONS     BOSTON

SQL 在外连接查询里使用OR逻辑 解决方案

DB2、MySQLPostgreSQLSQL Server
OR 条件移到 JOIN 子句里。

1  select e.ename, d.deptno, d.dname, d.loc
2    from dept d left join emp e
3      on (d.deptno = e.deptno
4          and (e.deptno=10 or e.deptno=20))
5   order by 2

或者,我们也可以先利用内嵌视图过滤 EMP.DEPTNO,然后再执行外连接。

1  select e.ename, d.deptno, d.dname, d.loc
2    from dept d
3    left join
4         (select ename, deptno
5            from emp
6           where deptno in ( 10, 20 )
7         ) e on ( e.deptno = d.deptno )
8   order by 2

Oracle
对于 Oracle 9i 及后续版本,上述针对其他数据库的解决方案也适用。除此之外,我们也可以使用 CASEDECODE 的变通方案。下面是使用 CASE 的解决方案。

select e.ename, d.deptno, d.dname, d.loc
  from dept d, emp e
 where d.deptno = e.deptno (+)
   and d.deptno = case when e.deptno(+) = 10 then e.deptno(+)
                       when e.deptno(+) = 20 then e.deptno(+)
                  end
 order by 2

接下来的解决方案做法也是一样的,但用到了 DECODE 函数。

select e.ename, d.deptno, d.dname, d.loc
  from dept d, emp e
 where d.deptno = e.deptno (+)
   and d.deptno = decode(e.deptno(+),10,e.deptno(+),
                                     20,e.deptno(+))
 order by 2

如果用了 Oracle 专有的外连接语法“(+)”,并在外连接列上用到了 INOR 条件,查询操作就会返回错误。解决办法是把 INOR 条件移到一个内嵌视图中。

select e.ename, d.deptno, d.dname, d.loc
  from dept d,
      ( select ename, deptno
          from emp
         where deptno in ( 10, 20 )
       ) e
 where d.deptno = e.deptno (+)
 order by 2

SQL 在外连接查询里使用OR逻辑 扩展知识

DB2、MySQLPostgreSQL 和 SQL Server
针对这些数据库,我们提供了两种解决方案。第一种把 OR 条件移到了 JOIN 子句里,使它成为连接条件的一部分。这样一来,我们既能筛选出 EMP 表的数据,又不会丢掉 DEPT 表里 DEPTNO 等于 30 和 40 的数据。
第二种解决方案把过滤条件移到了内嵌视图里。内嵌视图 E 基于 EMP.DEPTNO 过滤数据,从 EMP 表里提取出我们感兴趣的行。然后,这些行被外连接到 DEPT 表。DEPT 表是外连接的基础表,因此包括部门编号为 30 和 40 在内的所有部门都会被返回。
Oracle
旧式的外连接语法似乎存在缺陷,我们使用了 CASEDECODE 函数以避免该问题。除此之外,使用了内嵌视图 E 的那个解决方案,首先从 EMP 表里筛选出我们感兴趣的行,然后再外连接到 DEPT

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程