專案上線後發現所有中文字元皆顯示為「????」,經排查資料寫入前正常,鎖定問題在資料庫層級。本文記錄從症狀到根因的完整診斷流程,並說明修改資料庫排序規則為何不足、必須連同資料行一併調整的關鍵細節。
SQL_Latin1_General_CP1_CI_AS 等非中文友善規則。將資料庫排序規則改為 Chinese_PRC_CI_AI(簡體拼音、不區分大小寫、不區分重音)後,僅部分新資料正常,舊資料與部份欄位仍亂碼。
TrueName)可能因建立時指定了排序規則,導致不隨資料庫變更而更新。Chinese_PRC_CI_AI 或 Chinese_Taiwan_Stroke_CI_AI。char/varchar/text/nchar/nvarchar/ntext 欄位的排序規則逐一改為目標規則。DECLARE @TargetCollation SYSNAME = N'Chinese_PRC_CI_AI';
DECLARE @SQL NVARCHAR(MAX) = N'';
SELECT @SQL += N'
ALTER TABLE ' + QUOTENAME(SCHEMA_NAME(t.schema_id)) + N'.' + QUOTENAME(t.name) + N'
ALTER COLUMN ' + QUOTENAME(c.name) + N' ' +
UPPER(TYPE_NAME(c.system_type_id)) +
CASE WHEN TYPE_NAME(c.system_type_id) IN (N'char', N'varchar', N'nchar', N'nvarchar')
THEN N'(' + CASE WHEN c.max_length = -1 THEN N'MAX' ELSE CAST(c.max_length / CASE WHEN TYPE_NAME(c.system_type_id) LIKE N'n%' THEN 2 ELSE 1 END AS NVARCHAR(10)) END + N')'
ELSE N'' END +
N' COLLATE ' + @TargetCollation +
CASE WHEN c.is_nullable = 1 THEN N' NULL' ELSE N' NOT NULL' END + N';'
FROM sys.tables t
JOIN sys.columns c ON c.object_id = t.object_id
WHERE t.is_ms_shipped = 0
AND TYPE_NAME(c.system_type_id) IN (N'char', N'varchar', N'nchar', N'nvarchar', N'text', N'ntext')
AND c.collation_name <> @TargetCollation;
-- PRINT @SQL; -- 先檢查
-- EXEC sp_executesql @SQL; -- 確認無誤後執行
注意:執行前請完整備份資料庫,且需考慮索引、外鍵、檢查條件約束等相依物件可能需先卸除再重建。
sys.columns 確認所有字串欄位排序規則一致。CREATE DATABASE 即指定 COLLATE Chinese_PRC_CI_AI,從源頭避免問題。總結:資料庫排序規則只是「預設值」,真正決定字串儲存與比較行為的是資料行層級的排序規則。徹底解決亂碼,必須將現有所有字串欄位逐一修正至目標排序規則。