分類標籤明明有三筆,匯出後卻只剩「alpha,be」,連 beta 都少了一截。若查詢使用 GROUP_CONCAT(),先檢查輸出長度上限,不要立刻認定資料已遺失。這個函式把多列值串成一個字串,結果過長時可能被截斷。
網站的標籤清單、附件名稱或後台報表都可能遇到這種情況。下面用 MySQL 8.4 的三筆文字示例分清兩件事:來源查到幾列,以及最後串出的文字是否完整。示例只讀臨時組出的資料,不建立或修改資料表。
先查執行那筆查詢的連線
SELECT VERSION(),
@@SESSION.group_concat_max_len,
@@GLOBAL.group_concat_max_len;
MySQL 8.4 的 group_concat_max_len 預設值是 1024,但站點可能已調整。它限制的是位元組數,不是可容納幾個標籤或幾個中文字;分隔符號也占輸出長度。因此要讀實際設定,不能只按「大約幾個字」估算。
尤其要看 SESSION 值。管理工具開的一條連線,和網站程式使用的連線可能不同;在工具裡調好了,不表示網站的那筆查詢已採用相同設定。
用小上限重現:三列資料,結果卻只剩半個名稱
在獨立測試連線依序執行以下內容,先保存原設定,再暫時將這條連線的上限設成 8:
SET @saved_limit = @@SESSION.group_concat_max_len;
SET SESSION group_concat_max_len = 8;
SELECT COUNT(*) AS source_rows,
GROUP_CONCAT(name ORDER BY id SEPARATOR ',') AS names
FROM (
SELECT 1 AS id, 'alpha' AS name
UNION ALL SELECT 2, 'beta'
UNION ALL SELECT 3, 'gamma'
) AS sample;
SHOW WARNINGS;
這筆查詢的 source_rows 仍是 3,但 names 是 alpha,be;緊接著的警告會指出 GROUP_CONCAT 有內容被截斷,這個例子會出現代碼 1260。原資料沒有因為截斷而被刪除,只是串接結果不完整。
請在那筆 SELECT 後立即查看警告,別先執行一串其他查詢,才回頭找截斷原因。若你的客戶端自動執行額外查詢,也要確認看到的是哪一筆操作的警告。
提高本連線上限後,再核對完整結果
仍在同一條測試連線,把上限改成足夠容納這個例子的 64,重跑相同的 SELECT:
SET SESSION group_concat_max_len = 64;
SELECT COUNT(*) AS source_rows,
GROUP_CONCAT(name ORDER BY id SEPARATOR ',') AS names
FROM (
SELECT 1 AS id, 'alpha' AS name
UNION ALL SELECT 2, 'beta'
UNION ALL SELECT 3, 'gamma'
) AS sample;
SHOW WARNINGS;
SET SESSION group_concat_max_len = @saved_limit;
這次應得到 3 與 alpha,beta,gamma。這組 ASCII 文字連同兩個逗號共占 16 位元組,64 只為了讓示例容易重現,並不是正式站的建議通用值。測完要在同一連線還原原值;若中途換了連線,保存原值的使用者變數也不能沿用。
正式報表要同時檢查長度與資料規則
確認是截斷後,再按實際資料量估算所需上限。不要直接設成極大值:MySQL 文件提醒,過高設定可能影響效能,甚至耗盡記憶體;輸出的有效最大長度也受 max_allowed_packet 限制。
如果資料量會一直增加,匯出程式可考慮逐列讀取,而非把所有名稱塞進一個大字串。程式確實需要串接時,應在執行查詢的那條連線設定並讀回 SESSION 值。使用連線池時,依框架的連線初始化與重設方式處理,避免把測試設定留給下一個借用者。
最後也別把每種「少了項目」都歸咎於長度:GROUP_CONCAT() 會略過 NULL,DISTINCT 會去掉重複值,JOIN 與 WHERE 則可能先改變來源列。範例把排序寫在 GROUP_CONCAT 內,是為了固定名稱串接順序;只在外層對查詢結果排序,不能替代這個順序要求。先核對來源,再看警告與最後字串,才知道應改查詢條件還是長度設定。
