HAVING
的行为类似于where子句,EXISTS
检查给定行的行是否存在。因此,当我们使用HAVING NOT EXISTS
时,它应该具有与MINUS
相同的功能,从而消除第一个表中的公共行。
但是在我将HAVING NOT EXISTS
替换为MINUS
的示例中,结果集不相同。查询是
(
select empno,ename,job,mgr,hiredate,sal,comm,deptno
,
count(*) as cnt
from v
group by empno,ename,job,mgr,hiredate,sal,comm,deptno
minus
( select empno,ename,job,mgr,hiredate,sal,comm,deptno
,
count(*) as cnt
from emp
group by empno,ename,job,mgr,hiredate,sal,comm,deptno)
)
union all
(
select empno,ename,job,mgr,hiredate,sal,comm,deptno
,
count(*) as cnt
from emp
group by empno,ename,job,mgr,hiredate,sal,comm,deptno
minus
( select empno,ename,job,mgr,hiredate,sal,comm,deptno
,
count(*) as cnt
from v
group by empno,ename,job,mgr,hiredate,sal,comm,deptno)
)
V是一个视图,形成如
create or replace view v
as
select * from emp where deptno != 10
union all
select * from emp where ename = 'WARD';
查询是确定表是否具有相同数据的示例
这是我的emp表:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
7566 JONES MANAGER 7839 02-APR-81 2975 20
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7788 SCOTT ANALYST 7566 09-DEC-82 3000 20
7839 KING PRESIDENT 17-NOV-81 5000 10
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30
7876 ADAMS CLERK 7788 12-JAN-83 1100 20
7900 JAMES CLERK 7698 03-DEC-81 950 30
7902 FORD ANALYST 7566 03-DEC-81 3000 20
7934 MILLER CLERK 7782 23-JAN-82 1300 10
这是视图V
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
7566 JONES MANAGER 7839 02-APR-81 2975 20
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30
7788 SCOTT ANALYST 7566 09-DEC-82 3000 20
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30
7876 ADAMS CLERK 7788 12-JAN-83 1100 20
7900 JAMES CLERK 7698 03-DEC-81 950 30
7902 FORD ANALYST 7566 03-DEC-81 3000 20
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
使用minus
时,查询结果为
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO CNT
------ ---------- --------- ---------- --------- ---------- ---------- ---------- ----------
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 2
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 1
7782 CLARK MANAGER 7839 09-JUN-81 2450 10 1
7839 KING PRESIDENT 17-NOV-81 5000 10 1
7934 MILLER CLERK 7782 23-JAN-82 1300 10 1
使用HAVING NOT EXISTS
时,no rows
来自查询
我对这些条款的理解是否有任何错误。请用简短的例子解释为什么结果集不同。谢谢
答案 0 :(得分:1)
这总是不会产生任何行:
select empno,ename,job,mgr,hiredate,sal,comm,deptno,count(*) as cnt
from v
group by empno,ename,job,mgr,hiredate,sal,comm,deptno
having not exists (
select empno,ename,job,mgr,hiredate,sal,comm,deptno, count(*) as cnt
from emp
group by empno,ename,job,mgr,hiredate,sal,comm,deptno
);
主select
与having
子句中查询返回的数据之间没有相关性。除非emp
为空,否则该子句中总会存在某些内容,因此having not exists
必须为false,因此主查询中的所有行都将被丢弃。
这与你的数据无关;简化版本也是如此:
select * from dual
where not exists (select * from dual);
dual
中的行在逻辑上是不可能的,同时dual
中没有行。 (好吧,如果dual
中没有行,那你就麻烦大了,所以也许这不是一个很好的例子。)
在您的情况下v
和emp
相关;如果emp
为空,则v
也必须为空。
此部分中的主select
找到v
中的11行。 select
子句中的having
从emp
中找到14行,但如果它找到1行或100行则无关紧要,因为两组行之间没有关系。 having
子句仅用作过滤器; having not exists (<query that finds anything>)
过滤掉所有内容。如果您将其分解,exists (select ...)
为真,因为emp
中有行; not exists (select ...)
只是对此的否定,所以它是假的;所以你有效地说'给我行true = false'。
union
的第二部分找到emp
中的14行,但同样的'true = false'过滤器适用,因此所有行仍然被丢弃,即使内部select
只找到v
的11行。您未在v
和emp
中的数据之间建立任何关联。
但是任何总是产生行的子查询都会产生相同的效果;因为没有相关性,你可以查询一个与emp
完全无关的不同表,并且只要子查询返回一行或多行,你的having
子句就会过滤掉你期望的所有内容查看。这表现相同,例如:
select empno,ename,job,mgr,hiredate,sal,comm,deptno,count(*) as cnt
from v
group by empno,ename,job,mgr,hiredate,sal,comm,deptno
having not exists (
select * from dual
);
对于联合的第二部分,您可以通过添加相关性来获取一些数据:
select empno,ename,job,mgr,hiredate,sal,comm,deptno,count(*) as cnt
from v
group by empno,ename,job,mgr,hiredate,sal,comm,deptno
having not exists (
select empno,ename,job,mgr,hiredate,sal,comm,deptno, count(*) as cnt
from emp
where emp.empno = v.empno
and emp.ename = v.ename
and emp.job = v.job
and emp.mgr = v.mgr
and emp.hiredate = v.hiredate
and emp.sal = v.sal
and emp.deptno = v.deptno
group by empno,ename,job,mgr,hiredate,sal,comm,deptno
);
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO CNT
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- ----------
7782 CLARK MANAGER 7839 09-JUN-81 2450 10 1
7934 MILLER CLERK 7782 23-JAN-82 1300 10 1
7839 KING PRESIDENT 17-NOV-81 5000 10 1
如果它是主键或唯一,只使用empno
可能有效,除非你真的在寻找其他字段之间的差异。但是将v
和emp
之间的计数关联起来很棘手,可能不值得付出努力。看着伯爵看起来有点奇怪;它们仅因WARD
而有所不同,因为您已经构建了视图。在这里使用minus
更简单,也可能更快。