在多表關聯查詢中,常需根據一張表的字段值,去另一張表做模糊匹配(如:標簽表匹配文章標題、分類名匹配商品描述)。MySQL 中不能直接用 + 或 || 拼接字符串,必須使用 CONCAT() 函數構建 LIKE 模式。本文通過反面教材與正確示例,釐清核心用法。
-- 錯誤:MySQL 中 + 是算術加法,非字符串拼接;|| 在默認 SQL 模式下是邏輯 OR
SELECT info.id, info.name
FROM tag, info
WHERE info.name LIKE '%' + tag.name + '%'; -- 結果全為 0 或報錯
-- 錯誤:Oracle/PostgreSQL 風格,MySQL 默認不支持
SELECT info.id, info.name
FROM tag, info
WHERE info.name LIKE '%' || tag.name || '%';
-- 標準寫法:CONCAT('%', 列名, '%')
SELECT info.id, info.name
FROM tag, info
WHERE info.name LIKE CONCAT('%', tag.name, '%');
CONCAT(str1, str2, ...) 返回拼接後的字符串,任一參數為 NULL 則結果為 NULL。若需容忍 NULL,可用 CONCAT_WS('', '%', tag.name, '%') 或 IFNULL(tag.name, '')。
源碼片段展示了 CMS 系統中主表 table 與關聯表 table1 的查詢,table1.sid 存儲管道分隔的 ID 串(|1|2|3|),需反向匹配:
$sql = $empire->query("
SELECT table.title, lianxi, table.dizhi, table.id
FROM table, table1
WHERE table1.sid LIKE CONCAT('%|', table.id, '|%')
AND table1.id = " . $navinfor[id]
);
CONCAT('%|', table.id, '|%') 生成 %|123|% 模式,精確匹配邊界,避免誤匹配 1234、1123 等。
| 問題 | 影響 | 優化方案 |
|---|---|---|
LIKE '%xxx%' 導掛首字符通配 | 無法利用 B-Tree 索引,全表掃描 | 1. 全文索引 FULLTEXT + MATCH() AGAINST()2. 外部搜索引擎 3. 將標簽拆分為關聯表(多對多),走等值 JOIN |
| 跨表模糊匹配 + 大數據量 | 笛卡爾積 + 全掃描,極慢 | 業務層面拆解:寫入時預計算關聯,查詢時走精確 JOIN |
CONCAT(),切勿用 + 或 ||。|id|),查詢用 CONCAT('%|', id, '|%') 精確匹配。tag_map),將 O(N*M) 降為 O(log N)。LIMIT、考慮 FULLTEXT 或 Elasticsearch。