SQL Server 內建無 STRING_SPLIT(2016 才引入),早期版本須自行實作。批量操作(如一次傳入數千 ID 進行 IN 查詢或批次更新)若逐筆呼叫,網路往返開銷極大;透過單一字串參數 + Split 函數轉為資料表值,可大幅降低 Round-trip。
| 型別 | 最大長度 | Unicode | 適用場景 |
|---|---|---|---|
| VARCHAR(8000) | 8,000 字元 | 否 | 一般 ANSI 字串 |
| NVARCHAR(4000) | 4,000 字元 | 是 | 多語系 Unicode |
| TEXT | 2 GB | 否 | 超長 ANSI 字串(舊版相容) |
| NTEXT | 1 GB 字元 | 是 | 超長 Unicode 字串(舊版相容) |
關鍵點: 區域變數無法宣告 TEXT/NTEXT,但可直接將 SUBSTRING 結果 INSERT 進表值變數,避免中間賦值。
CREATE FUNCTION dbo.Split
(
@SplitString TEXT, -- 或 NTEXT
@Separator VARCHAR(2) = ',' -- 或 NVARCHAR(2)
)
RETURNS @SplitStringsTable TABLE
(
[id] INT IDENTITY(1,1),
[value] VARCHAR(8000) -- 或 NVARCHAR(4000)
)
AS
BEGIN
DECLARE @CurrentIndex INT, @NextIndex INT, @ReturnText VARCHAR(8000);
SELECT @CurrentIndex = 1;
WHILE (@CurrentIndex <= DATALENGTH(@SplitString)) -- NTEXT 時用 DATALENGTH/2
BEGIN
SELECT @NextIndex = CHARINDEX(@Separator, @SplitString, @CurrentIndex);
IF (@NextIndex = 0 OR @NextIndex IS NULL)
SELECT @NextIndex = DATALENGTH(@SplitString) + 1;
SELECT @ReturnText = SUBSTRING(@SplitString, @CurrentIndex, @NextIndex - @CurrentIndex);
INSERT INTO @SplitStringsTable([value]) VALUES (@ReturnText);
SELECT @CurrentIndex = @NextIndex + 1;
END
RETURN;
END
-- 批量刪除
DELETE FROM Orders
WHERE OrderID IN (SELECT value FROM dbo.Split('10248,10249,10250', ','));
-- 批量更新搭配 JOIN
UPDATE p
SET p.Status = 'Shipped'
FROM Production.Product p
JOIN dbo.Split('707,708,709', ',') s ON p.ProductID = CAST(s.value AS INT);
STRING_SPLIT(但無順序保證,2022 新增 ordinal 欄位)。CLR 實作或 XML 方案(CAST('' + REPLACE(@str, ',', ' ') + ' ' AS XML))。CHARINDEX,可預先計算分隔符位置陣列(CLR 優勢)。