子查詢是構建複雜查詢的核心工具。依返回結果集結構,分為單行單列、單行多列、多行單列 三類。本文以 EMP 表為例,系統演示各類子查詢在 WHERE 子句中的寫法、適用操作符 (IN/ANY/ALL/EXISTS) 及空值陷阱。
SELECT * FROM emp e WHERE e.sal = (SELECT MIN(sal) FROM emp);
SELECT * FROM emp e WHERE e.sal < (SELECT sal FROM emp WHERE ename = 'ALLEN');
SELECT * FROM emp e WHERE e.sal > (SELECT AVG(sal) FROM emp);
SELECT * FROM emp e WHERE e.job = (SELECT job FROM emp WHERE ename = 'ALLEN') AND e.sal > (SELECT sal FROM emp WHERE empno = 7521);
SELECT * FROM emp e WHERE (e.job, e.sal) = (SELECT job, sal FROM emp WHERE ename = 'SCOTT') AND e.ename <> 'SCOTT';
SELECT * FROM emp e WHERE (e.job, e.mgr) = (SELECT job, mgr FROM emp WHERE empno = 7521);
SELECT * FROM emp e
WHERE (e.job, TO_CHAR(e.hiredate, 'YYYY')) =
(SELECT job, TO_CHAR(hiredate, 'YYYY') FROM emp WHERE ename = 'ALLEN');
SELECT * FROM emp e WHERE e.sal IN (SELECT MIN(sal) FROM emp GROUP BY deptno);
SELECT * FROM emp e WHERE e.sal NOT IN (SELECT MIN(sal) FROM emp GROUP BY deptno); -- ⚠️ 陷阱:若子查詢結果含 NULL,NOT IN 永遠返回 FALSE (無資料)。建議用 NOT EXISTS。
= ANY 等價於 IN> ANY 大於集合中最小值 (即 > MIN)< ANY 小於集合中最大值 (即 < MAX)SELECT * FROM emp WHERE sal = ANY (SELECT MIN(sal) FROM emp WHERE job = 'MANAGER' GROUP BY deptno);
SELECT * FROM emp WHERE sal > ANY (SELECT MIN(sal) FROM emp WHERE job = 'MANAGER' GROUP BY deptno); -- 即薪資 > 最低經理薪資
SELECT * FROM emp WHERE sal < ANY (SELECT MIN(sal) FROM emp WHERE job = 'MANAGER' GROUP BY deptno); -- 即薪資 < 最高經理薪資
<> ALL 等價於 NOT IN (但 = ALL 不等價於 IN)> ALL 大於集合中最大值 (即 > MAX)< ALL 小於集合中最小值 (即 < MIN)SELECT * FROM emp WHERE sal <> ALL (SELECT MIN(sal) FROM emp WHERE job = 'MANAGER' GROUP BY deptno);
SELECT * FROM emp WHERE sal < ALL (SELECT MIN(sal) FROM emp WHERE job = 'MANAGER' GROUP BY deptno);
SELECT * FROM emp WHERE sal > ALL (SELECT MIN(sal) FROM emp WHERE job = 'MANAGER' GROUP BY deptno);
EXISTS (subquery):子查詢返回至少一行 → TRUE。常用於關聯子查詢 (相關子查詢)。NOT EXISTS:子查詢無資料返回 → TRUE。不受 NULL 影響,是 NOT IN 的安全替代。SELECT * FROM emp WHERE EXISTS (SELECT * FROM emp WHERE empno = 9999); -- 無此員工,無輸出
SELECT * FROM emp WHERE EXISTS (SELECT * FROM emp); -- 有資料,返回所有員工
SELECT * FROM emp WHERE NOT EXISTS (SELECT * FROM emp); -- 有資料,取反無輸出
IN/ANY/ALL,存在性判斷用 EXISTS。NOT IN 遇 NULL 失效,務必改用 NOT EXISTS 或 <> ALL。ANY/ALL 常配合聚合函數 (MIN/MAX) 簡化邏輯:> ANY = > MIN, < ALL = < MIN。EXISTS 子查詢引用外部表欄位) 通常效能優於非相關 IN,因可利用半連結優化。