執行 UPDATE table SET column = REPLACE(column, 'old', 'new') 時,若 column 為 text 或 ntext 類型,報錯:
參數數據類型 text 對於 replace 函數的參數 1 無效
原因:text、ntext、image 屬於大對象 (LOB) 類型,不支持直接進行字符串函數操作 (REPLACE, SUBSTRING, CHARINDEX 等)。
UPDATE YourTable
SET YourColumn = REPLACE(CAST(YourColumn AS VARCHAR(MAX)), '舊文本', '新文本');
原理:VARCHAR(MAX) / NVARCHAR(MAX) / VARBINARY(MAX) 是 SQL Server 2005 引入的大值數據類型,最高支持 2^31-1 字節 (2GB),完全替代舊 LOB 類型,且原生支持所有字符串函數。
VARCHAR(8000) 最大 8000 字節。若 text 列內容超過 8000,CAST(... AS VARCHAR(8000)) 會靜默截斷,導致數據丟失。VARCHAR(MAX) 無此限制,安全完整。
| 特性 | 舊 LOB (text/ntext/image) | 大值類型 (varchar(max)/nvarchar(max)/varbinary(max)) |
|---|---|---|
| 最大存儲 | 2GB | 2GB |
| 字符串函數支持 | 不支持 (需 TEXTPTR + READTEXT/UPDATETEXT) | 全支持 (REPLACE, SUBSTRING, LEN 等) |
| 變量聲明 | 不可聲明局部變量 | 可聲明變量/參數 |
| 行內存儲 | 不支持 | ≤8000 字節行內,超過移至 LOB 頁 (可配置 sp_tableoption 'large value types out of row') |
| 游標支持 | 受限 | 完整支持 |
| .WRITE 部分更新 | 不支持 (需 UPDATETEXT) | 支持 UPDATE ... .WRITE() |
| 觸發器 inserted/deleted | 不可引用 | 可引用 |
重要提示:請使用 varchar(max)、nvarchar(max) 和 varbinary(max) 數據類型,而不要使用 text、ntext 和 image 數據類型。
遷移建議:ALTER TABLE YourTable ALTER COLUMN YourColumn VARCHAR(MAX); (元數據操作,極快,無數據移動)。
COL_LENGTH, CHARINDEX, PATINDEX, LEN, DATALENGTH, SUBSTRING,
LEFT, RIGHT, REPLACE, STUFF, REVERSE, UPPER, LOWER,
LTRIM, RTRIM, ASCII, UNICODE, CHAR, NCHAR, QUOTENAME,
SPACE, STR, DIFFERENCE, SOUNDEX, CONCAT, CONCAT_WS (2017+)
-- 僅替換第 1000 字符開始的 10 個字符,不重寫整個大值
UPDATE LargeTable
SET BigColumn.WRITE('NewText', 1000, 10) -- @Offset 從 0 開始
WHERE Id = 123;
適用於大文本微量修改,避免全列重寫產生大量日志和頁分裂。
-- 1. 創建測試表
CREATE TABLE TestTextReplace (
Id INT IDENTITY PRIMARY KEY,
OldTextCol TEXT,
NewMaxCol VARCHAR(MAX)
);
-- 2. 插入超長文本 (>8000)
DECLARE @long VARCHAR(MAX) = REPLICATE(CAST('ABCDEFGHIJ' AS VARCHAR(MAX)), 1000); -- 10000 字符
INSERT INTO TestTextReplace (OldTextCol) VALUES (@long);
-- 3. 直接 REPLACE 失敗
-- UPDATE TestTextReplace SET OldTextCol = REPLACE(OldTextCol, 'A', 'X'); -- 報錯
-- 4. 正確:CAST 為 VARCHAR(MAX) 後 REPLACE
UPDATE TestTextReplace
SET NewMaxCol = REPLACE(CAST(OldTextCol AS VARCHAR(MAX)), 'A', 'X');
-- 5. 驗證
SELECT LEN(NewMaxCol), LEFT(NewMaxCol, 20) FROM TestTextReplace; -- 10000, 'XBCDEFGHIJ...'
-- 6. 遷移列類型 (生產環境建議)
-- ALTER TABLE TestTextReplace ALTER COLUMN OldTextCol VARCHAR(MAX);
| 誤區 | 正確認知 |
|---|---|
| 用 VARCHAR(8000) 接收 text | 會截斷,必須用 VARCHAR(MAX) |
| 以為 CAST 複製了數據 | CAST 只是類型轉換,配合 REPLACE 產生新值,再 UPDATE 寫回 |
| 覺得 text 類型還能用 | 已棄用,新開發嚴禁使用,存量表應規劃遷移 |
| REPLACE 大文本性能好 | 全列重寫產生大量日志,大表建議分批、低峰期、或用 .WRITE |