STUFF ( character_expression , start , length , replacement_expression )
在 character_expression 中,從 start 位置刪除 length 個字元,並插入 replacement_expression。回傳型別與輸入字元表達式型別一致 (字元型回傳字元,二進位型回傳二進位)。
| 參數 | 資料型別 | 說明 | 邊界行為 |
|---|---|---|---|
character_expression | 字元/二進位型別 (常數/變數/欄位) | 目標字串 | 若為 NULL → 回傳 NULL |
start | INT / BIGINT | 刪除/插入起始位置 (1-based) | ≤ 0 或 > LEN(character_expression) → 回傳空字串 '' |
length | INT / BIGINT | 要刪除的字元數 | < 0 → 空字串; > 剩餘長度 → 刪除至字串結尾 |
replacement_expression | 字元/二進位型別 | 插入的新字串 | 若為 NULL → 僅刪除不插入 (相當 REPLACE 為空) |
-- 經典範例:abcdef 從第 2 字元刪 3 個 (bcd) 插入 ijklmn
SELECT STUFF('abcdef', 2, 3, 'ijklmn'); -- 結果:aijklmnef
-- 僅刪除不插入 (replacement 為空字串)
SELECT STUFF('abcdef', 2, 3, ''); -- 結果:aef
-- 僅插入不刪除 (length = 0)
SELECT STUFF('abcdef', 3, 0, 'XYZ'); -- 結果:abXYZcdef
-- 起始位置超過長度
SELECT STUFF('abc', 5, 1, 'X'); -- 結果:'' (空字串)
-- 負數參數
SELECT STUFF('abc', -1, 2, 'X'); -- 結果:''
-- 身分證字號:保留首碼與末 3 碼,中間遮罩
DECLARE @ID VARCHAR(10) = 'A123456789';
SELECT STUFF(@ID, 2, LEN(@ID)-4, REPLICATE('*', LEN(@ID)-4)); -- A*******89
-- 手機號碼:保留前 3 後 4
DECLARE @Phone VARCHAR(10) = '0912345678';
SELECT STUFF(@Phone, 4, 4, '****'); -- 091****5678
DECLARE @Cols NVARCHAR(MAX) = N'Col1, Col2, Col3, ';
-- 移除最後的逗號空白
SELECT STUFF(@Cols, LEN(@Cols) - 1, 2, ''); -- Col1, Col2, Col3
-- 實際動態 SQL 組裝模式
DECLARE @SQL NVARCHAR(MAX) = N'SELECT ' + STUFF(@Cols, LEN(@Cols) - 1, 2, '') + N' FROM dbo.Table1;';
-- 將 20240115 轉為 2024-01-15
DECLARE @DateStr CHAR(8) = '20240115';
SELECT STUFF(STUFF(@DateStr, 5, 0, '-'), 8, 0, '-'); -- 2024-01-15
DECLARE @XML XML = N'- A
- B
';
-- 將第一個 item 的 id 從 1 改為 100 (示範字串操作,實際建議用 modify())
DECLARE @XMLStr NVARCHAR(MAX) = CAST(@XML AS NVARCHAR(MAX));
SELECT STUFF(@XMLStr, CHARINDEX('id="1"', @XMLStr) + 4, 1, '100');
-- 經典模式:取得某資料表所有欄位名稱逗號分隔
SELECT STUFF((
SELECT N', ' + QUOTENAME(name)
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.YourTable')
ORDER BY column_id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, ''); -- 移除開頭 ", "
-- 結果:[Col1], [Col2], [Col3]...
| 主題 | 說明 |
|---|---|
| 二進位資料操作 | STUFF(0x123456, 2, 1, 0xAB) → 0x12AB56,適用於二進位欄位局部修改。 |
| 搭配 REPLACE 差異 | REPLACE 替換**所有**符合子字串;STUFF 針對**指定位置/長度**精準手術。 |
| 效能考量 | 純量函數,大量列逐列呼叫有函數開銷。集合操作優先用集合邏輯 (如 FOR XML PATH)。 |
| 結果長度溢位 | 若結果超過目標型別最大長度 (如 VARCHAR(8000)) 會報錯。大字串用 VARCHAR(MAX)。 |
| NULL 處理 | 任一參數為 NULL → 回傳 NULL (依 ANSI_NULLS)。建議 ISNULL/COALESCE 預處理。 |
STUFF(@s, 0, 1, 'X') 回傳空字串。length < 0 直接回傳空字串,不報錯但邏輯錯誤。character_expression 為 VARCHAR 但 replacement 為 NVARCHAR → 隱含轉換可能導致截斷或排序規則衝突。顯式 CAST 統一型別。STUFF 是 T-SQL 字串處理的「精密手術刀」:**指定位置、指定長度、精準替換**。掌握其邊界行為 (負數、超長、NULL)、搭配 LEN/CHARINDEX/FOR XML PATH 等函數,即可優雅解決「移除尾端分隔符、遮罩敏感資訊、動態 SQL 組裝、格式轉換」等高頻需求。記住:**位置從 1 起算、長度可為 0 (純插入)、替換字串可為空 (純刪除)**,三種基本模式組合出無限變化。