痛點:DB2 LIKE 不支援變量/列作為模式
在 DB2 函數或存儲過程中,常見需求是「根據傳入參數動態模糊查詢」。然而 DB2 **不允許** LIKE 後跟變量或列:
-- 錯誤示範
CREATE PROCEDURE SEARCH_BY_KEYWORD(IN P_KEYWORD VARCHAR(100))
BEGIN
SELECT * FROM PRODUCTS WHERE NAME LIKE '%' || P_KEYWORD || '%'; -- SQL0104N
END
報錯:SQL0104N An unexpected token "P_KEYWORD" was found following "LIKE"。
解決方案:LOCATE 函數
語法
LOCATE(search_string, source_string [, start_position])
-- 返回 search_string 在 source_string 中首次出現的位置 (1-based),未找到返回 0
改寫模式對照
| LIKE 模式 | LOCATE 等價邏輯 | 說明 |
COL LIKE 'ABC%' | LOCATE('ABC', COL) = 1 | 前綴匹配 |
COL LIKE '%ABC' | LOCATE('ABC', COL) > 0 AND LOCATE('ABC', COL) = LENGTH(COL) - LENGTH('ABC') + 1 | 後綴匹配 (較繁瑣) |
COL LIKE '%ABC%' | LOCATE('ABC', COL) > 0 | **包含匹配 (最常用)** |
COL LIKE '_ABC' | LOCATE('ABC', COL) = 2 | 單字符通配 |
實戰範例:存儲函數動態檢測項目
CREATE FUNCTION GDZJ.GETNOPASS (
ITEMNAME VARCHAR(100),
REPORTTYPE INTEGER,
RESULTID INTEGER
)
RETURNS INTEGER
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
BEGIN ATOMIC
DECLARE IRESULT INTEGER DEFAULT 0;
DECLARE ICOUNT INTEGER;
-- REPORTTYPE: 1=外單位, 0=非外單位
IF REPORTTYPE = 1 THEN
SET ICOUNT = (
SELECT COUNT(1)
FROM DETECT_END_INFO
WHERE CHECK_OUT_UNIT_INFO_ID = RESULTID
AND LOCATE(ITEMNAME, PROJECT_NAME) > 0 -- 動態包含查詢
);
ELSE
SET ICOUNT = (
SELECT COUNT(1)
FROM DETECT_END_INFO
WHERE CHECK_OUT_UNIT_INFO_ID = RESULTID
AND LOCATE(ITEMNAME, PROJECT_NAME) > 0
);
END IF;
-- 返回邏輯: 0=無項目, 1=全合格, 2=有不合格
IF ICOUNT = 0 THEN
RETURN 0;
ELSE
-- 這裡可進一步檢查是否有不合格記錄
RETURN CASE WHEN EXISTS (
SELECT 1 FROM DETECT_END_INFO
WHERE CHECK_OUT_UNIT_INFO_ID = RESULTID
AND LOCATE(ITEMNAME, PROJECT_NAME) > 0
AND RESULT_FLAG = 'FAIL'
) THEN 2 ELSE 1 END;
END IF;
END
效能考量與索引策略
- LOCATE 無法使用普通 B-Tree 索引:會導致全表掃描。
- 對策 1:全文索引 (DB2 Text Search / Net Search Extender) — 專為模糊/包含查詢設計。
- 對策 2:觸發器維護關鍵字表 — 將需模糊查詢的列拆解為關鍵字存入關聯表,走等值索引。
- 對策 3:應用層前綴過濾 — 若業務允許,改為
LIKE 'PREFIX%' 走索引範圍掃描。
進階:REGEXP_LIKE (DB2 11.1+ / Db2 on Cloud)
SELECT * FROM PRODUCTS
WHERE REGEXP_LIKE(NAME, '^.*' || :keyword || '.*$');
支援正則表達式,同樣接受變量,但同樣**無法走普通索引**,需全文索引支援。
總結
DB2 存儲程序/函數中實現動態模糊查詢,**首選 LOCATE(keyword, column) > 0** 替代 LIKE。對於大表高頻查詢,務必引入**全文索引**或**關鍵字倒排表**,避免全表掃描拖垮性能。
- 上一篇文章: DB2 客戶端訪問伺服器端實戰指南(一):節點編目、資料庫編目與核心命令詳解
- 下一篇文章: DB2 SQL 批處理腳本執行全攻略:從單條命令到生產級 .bat 自動化
Copyright ©
程式碼之家 All Rights Reserved