業務常遇到:前端傳入 "0001ME,0002BL" 這類逗號分隔字串,需查詢 scode IN (...)。直接 WHERE scode IN ('0001ME,0002BL') 會將整串視為單一值,**無法匹配**。本文對比失敗嘗試,給出 INSTR 解法與效能建議。
-- 嘗試用 REPLACE/CONCAT 產生 '0001ME','0002BL'
SELECT CONVERT(CONCAT('''', REPLACE('0001ME,0002BL', ',', ''','''), ''''), CHAR);
-- 結果仍是單一字串 '0001ME','0002BL',IN 子句視為一個元素,不生效
本質原因:SQL 解析期已確定 IN 列表元素個數,運行期字串無法動態展開為多元素。
INSTR(haystack, needle) 回傳 needle 在 haystack 首次出現位置(1-based),不存在回傳 0。利用此特性:
-- 字串包含目標碼則回傳 >0(真)
SELECT * FROM stocks_orderlist s
WHERE INSTR('0001ME,0002BL', s.scode) > 0;
測試驗證:
SELECT INSTR('0001ME,0002BL', '0003ME'); -- 0
SELECT INSTR('0001ME,0002BL', '0001ME'); -- 1
SELECT INSTR('0001ME,0002BL', '0002BL'); -- 8
| 場景 | 建議 |
|---|---|
| 資料量 < 10 萬、字串長度 < 1000 字元 | INSTR 可接受,無索引也能用 |
| 大表、高頻查詢 | **拆分字串為臨時表/表變數 JOIN**,或應用層拆分後用 IN (?,?,...) 參數化 |
| 字串含邊界干擾(如 '001' 匹配到 '0010') | 改用 FIND_IN_SET(s.scode, '0001ME,0002BL'),專為逗號分隔設計,邊界精確 |
| MySQL 8.0+ | 可用 JSON_TABLE 將字串轉虛擬表 JOIN,效能最佳 |
SELECT * FROM stocks_orderlist s
WHERE FIND_IN_SET(s.scode, '0001ME,0002BL') > 0;
FIND_IN_SET 內部按逗號分割,精確匹配元素,避免 INSTR 子串誤匹配。IN 列表。FIND_IN_SET(推薦)或 INSTR。JOIN/IN,才能利用索引。掌握此技巧,快速解決「前端傳字串、後端查 IN」的經典痛點。