前端傳入逗號分隔字串 '張三,李四,王五',資料庫需轉為結果集供 IN / JOIN 使用。注意:大數據量不建議此模式,應改用表值參數 (TVP) 或暫存表。
CREATE FUNCTION [dbo].[fnSplitStr] (
@sText NVARCHAR(MAX),
@sDelim CHAR(1)
)
RETURNS @retArray TABLE (value VARCHAR(100))
AS
BEGIN
DECLARE @posStart BIGINT, @posNext BIGINT, @valLen BIGINT, @sValue NVARCHAR(100)
IF @sDelim IS NULL
BEGIN
IF LEN(@sText) > 100 SET @sText = SUBSTRING(@sText, 1, 100)
INSERT @retArray (value) VALUES (@sText)
END
ELSE
BEGIN
SET @posStart = 1
WHILE @posStart <= LEN(@sText)
BEGIN
SET @posNext = CHARINDEX(@sDelim, @sText, @posStart)
IF @posNext <= 0
SET @valLen = LEN(@sText) - @posStart + 1
ELSE
SET @valLen = @posNext - @posStart
SET @sValue = SUBSTRING(@sText, @posStart, @valLen)
SET @posStart = @posStart + @valLen + 1
IF LEN(@sValue) > 0
BEGIN
IF LEN(@sValue) > 100 SET @sValue = SUBSTRING(@sValue, 1, 100)
INSERT @retArray (value) VALUES (@sValue)
END
END
END
RETURN
END
-- 1. 直接查詢 SELECT * FROM dbo.fnSplitStr(N'張三,李四,王五', N',') -- 2. 配合 IN 條件 SELECT * FROM Users WHERE UserName IN (SELECT value FROM dbo.fnSplitStr(@Names, N',')) -- 3. 配合 JOIN(效能優於 IN) SELECT u.* FROM Users u INNER JOIN dbo.fnSplitStr(@Names, N',') f ON u.UserName = f.value
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| fnSplitStr 純 T-SQL | 相容性好、無需建立類型 | WHILE 迴圈慢、大量值效能差、無統計資訊 | 少量值 (<100)、舊版本相容 |
| XML 解析法 | 集合式、無迴圈 | XML 解析開銷大、字串需轉 XML 安全 | 中等量值、SQL 2005+ |
| STRING_SPLIT (SQL 2016+) | 原生、高效、並行 | 不保證順序、無索引、無分隔符參數(固定單字符) | SQL 2016+、大量值、不需順序 |
| 表值參數 (TVP) | 強類型、有統計資訊、可索引、效能最佳 | 需建立類型、應用層需構造 DataTable | 大量值、高頻呼叫、生產環境首選 |
| OPENJSON (SQL 2016+) | JSON 標準、支援嵌套、效能優 | 需構造 JSON 陣列字串 | 前端已用 JSON、複雜結構 |
SELECT value FROM STRING_SPLIT(@Names, N',') -- 簡潔高效,但無順序保證
-- 1. 建立類型
CREATE TYPE dbo.NameList AS TABLE (Name NVARCHAR(100) PRIMARY KEY)
-- 2. 存儲過程接收
CREATE PROC usp_GetUsers @Names dbo.NameList READONLY
AS
SELECT u.* FROM Users u INNER JOIN @Names n ON u.UserName = n.Name
-- 3. C# 調用
var dt = new DataTable(); dt.Columns.Add("Name", typeof(string));
names.ForEach(n => dt.Rows.Add(n));
cmd.Parameters.AddWithValue("@Names", dt);
fnSplitStr 解決舊版本/簡單場景分割需求,邏輯清晰:定位分隔符 → 截取子串 → 迴圈插入表變數。