ANY、SOME、ALL 是 Oracle 子查詢比較的三大運算子,常用於「與子查詢結果集任一值/所有值比較」的場景。本文以實例拆解其語義、等價轉換與效能特性。
| 寫法 | 語義 | 等價轉換 |
|---|---|---|
FLD > ALL (subq) | 大於子查詢最大值 | FLD > (SELECT MAX(FLD) FROM ...) |
FLD > ANY (subq) | 大於子查詢最小值 | FLD > (SELECT MIN(FLD) FROM ...) |
FLD = ANY (subq) | 等於子查詢任一值 | FLD IN (subq) |
FLD != ALL (subq) | 不等於子查詢所有值 | FLD NOT IN (subq) |
SELECT * FROM EMP
WHERE SAL > ALL (SELECT AVG(SAL) FROM EMP GROUP BY DEPTNO);
-- 等價於
SELECT * FROM EMP
WHERE SAL > (SELECT MAX(AVG_SAL) FROM (SELECT AVG(SAL) AVG_SAL FROM EMP GROUP BY DEPTNO));
SELECT * FROM EMP
WHERE SAL > ANY (SELECT AVG(SAL) FROM EMP GROUP BY DEPTNO);
-- 等價於
SELECT * FROM EMP
WHERE SAL > (SELECT MIN(AVG_SAL) FROM (SELECT AVG(SAL) AVG_SAL FROM EMP GROUP BY DEPTNO));
SELECT * FROM EMP WHERE DEPTNO = ANY (SELECT DEPTNO FROM DEPT WHERE LOC = 'NEW YORK');
-- 等價於
SELECT * FROM EMP WHERE DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE LOC = 'NEW YORK');
MAX/MIN 或 IN/NOT IN,效能相近。NULL,NOT IN 永遠回傳「未知」(無資料);改用 NOT EXISTS 或 != ALL 可避免此問題。文中另提到 HAVING 用於分組後過濾,WHERE 用於分組前過濾。HAVING 需先完成 GROUP BY 聚合再過濾,效能較差;若條件與分組無關,務必下推至 WHERE。
-- 正確:分組前過濾
SELECT NAME, AVG(PRICE) FROM STORE WHERE PRICE > 10 GROUP BY NAME;
-- 僅當需對聚合結果過濾時用 HAVING
SELECT NAME, AVG(PRICE) FROM STORE GROUP BY NAME HAVING AVG(PRICE) > 10;