首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

SQL 查詢逗號分隔多值欄位?先重構表結構符合 1NF,實在不行用 JSON 或自訂 Split 函數

     編輯:程式設計綜合問答

現狀:`name` 欄位存 `aaa,bbb,ccc`,想查「包含多個值」的行。直接 SQL 判斷極其低效且違反關係型資料庫第一範式 (1NF)。

最佳方案:重構資料模型 (強烈建議)

-- 原表
CREATE TABLE entity (id INT, name VARCHAR(200)); -- name 存 "aaa,bbb,ccc"

-- 重構為兩張表
CREATE TABLE entity (id INT, ...);
CREATE TABLE entity_name (entity_id INT, name VARCHAR(50), PRIMARY KEY (entity_id, name));
-- 查詢「有多個 name」變得極簡單且走索引
SELECT entity_id, COUNT(*) AS cnt FROM entity_name GROUP BY entity_id HAVING cnt > 1;
  • 符合 1NF:單一欄位存單一值。
  • 可建立索引、支援 JOIN、統計聚合效能高。
  • 避免 `LIKE '%,%'` 全表掃描。

次佳方案:MySQL 5.7+ 原生 JSON

ALTER TABLE entity MODIFY name JSON; -- 存 ["aaa","bbb","ccc"]
-- 查詢包含多個元素
SELECT * FROM entity WHERE JSON_LENGTH(name) > 1;
-- 查詢包含特定值
SELECT * FROM entity WHERE JSON_CONTAINS(name, '"bbb"');
  • JSON 索引 (虛擬欄位 + 索引) 可加速特定值查詢。
  • 不需拆表,適合半結構化、頻繁變動屬性。

下策:自訂 Split 函數 (僅限舊系統無法改結構)

MySQL 無內建 `SPLIT_STRING`,需自建函數:

CREATE FUNCTION SPLIT_STR(str VARCHAR(255), delim VARCHAR(12), pos INT)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(str, delim, pos),
       LENGTH(SUBSTRING_INDEX(str, delim, pos - 1)) + 1), delim, '');

查詢邏輯:

SELECT * FROM entity
WHERE SPLIT_STR(name, ',', 2) != '';  -- 至少有兩段
  • **效能極差**:每行每查詢都要呼叫函數,無法用索引,百萬行查詢可能跑分鐘級。
  • 僅作過渡方案,上線後排期重構。

參考資源

MySQL Split 函數完整實現

結論:**違反 1NF 的設計,查詢永遠沒有好效能。** 能改結構就改,不能改上 JSON,實在不行寫函數並接受慢查詢風險。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved