Oracle 提供四種不等於運算子:<>、!=、~=、^=,功能完全相同。但所有比較運算子遇到 NULL 結果皆為 UNKNOWN(視同 FALSE),導致 WHERE col <> 100 無法撈出 col IS NULL 的列。本文說明陷阱與三種正確解法。
SELECT * FROM product WHERE price <> 180000;
SELECT * FROM product WHERE price != 180000;
SELECT * FROM product WHERE price ~= 180000;
SELECT * FROM product WHERE price ^= 180000;
-- 以上四句執行計畫、結果完全一致
CREATE TABLE test (name VARCHAR2(20));
INSERT INTO test VALUES ('xn');
INSERT INTO test VALUES ('abc');
INSERT INTO test VALUES (NULL);
SELECT * FROM test WHERE name <> 'xn';
-- 僅回傳 'abc',NULL 列消失!
SELECT * FROM test WHERE name <> 'xn' OR name IS NULL;
SELECT * FROM test WHERE NVL(name, '<>') <> 'xn';
-- 將 NULL 替換為絕不會出現的標記
SELECT * FROM test WHERE INSTR(CONCAT(name, 'xx'), 'xn') = 0;
-- CONCAT 遇 NULL 回傳另一參數,故 CONCAT(NULL,'xx')='xx',INSTR('xx','xn')=0 符合條件
| 寫法 | 可讀性 | 索引使用 | 備註 |
|---|---|---|---|
col <> val OR col IS NULL | 高 | 可用索引(需函數索引) | 推薦 |
NVL(col, marker) <> val | 中 | 無法使用一般索引 | 需函數索引 |
INSTR(CONCAT(col, x), val) = 0 | 低 | 無法使用索引 | 不推薦 |
NULL 只能用 IS NULL / IS NOT NULL 判斷,任何比較運算子(=、<>、>、<、LIKE、IN 等)與 NULL 運算結果皆為 UNKNOWN,WHERE/HAVING 視同 FALSE 過濾掉。
col <> val OR col IS NULL 或 NOT (col = val)(同樣需加 IS NULL)。