shanzm-2023年2月22日
0. 背景
程式碼中執行儲存過程,引數是多個且不確定數量,期望SQL查詢時使用該引數作為IN
的篩選條件
比如說,具體引數@Ids="1,2,3,4"
,
期望在儲存過程中,實現 select * from Table where id In @Ids
直接這樣寫會報錯
(當然可以使用動態sql 進行拼接,但不需要這麼做),而是將傳遞的引數分裂為單列的行記錄!
1. 使用STRING_SPLIT函式
-
Sql Server在2016版本中支援使用
STRING_SPLIT
函式- 可以將字串按照分隔符,切割成一個資料表
-
若是低版本資料使用提示
物件名 'STRING_SPLIT' 無效。
- 可以右鍵資料庫--屬性--選項--相容性等級--SqlServer2016(130)
- 不建議修改相容性等級,可能造成查詢資料的異常,具體可以參考:設定資料庫相容級別的兩種方法
SELECT * FROM STRING_SPLIT('1,2,3,4,5', ',');
--結果:
value
-------------
1
2
3
4
5
2. 自定義分裂函式
-
實現方式1:基於字串操作
- 將目標字串末尾拼接上一個分隔符
- 從字串第一個位置開始查詢分隔符在字串中第一次出現的位置索引
- 從左擷取(第一個分隔符索引-1)長度的字串,此外分裂出的第一個結果
- 將目標字串從第一個分隔符之前的替換為空
- 迴圈上述2~4步驟
-- ======================================================
-- Author: shanzm
-- Create date: 2021年6月30日 15:52:02
-- Description: 將指定字串按照指定的分裂符分裂為單列表
-- ======================================================
ALTER FUNCTION [dbo].[funGetSplitStr]
(
@Str VARCHAR(8000), --目標字串,形如"a,b,c"
@StrSeprate VARCHAR(1) --分隔符,形如","
)
RETURNS @temp TABLE --返回表值變數,只有一列F1
(
F1 VARCHAR(100)
)
AS
BEGIN
DECLARE @ch AS VARCHAR(100);
SET @Str = @Str + @StrSeprate;
WHILE (@Str <> '')
BEGIN
SET @ch = LEFT(@Str, CHARINDEX(@StrSeprate, @Str, 1) - 1);
INSERT @temp
VALUES
(@ch);
SET @Str = STUFF(@Str, 1, CHARINDEX(@StrSeprate, @Str, 1), '');
END;
RETURN;
END;
- 實現方式2:基於XML
-- ======================================================
-- Author: shanzm
-- Create date: 2021年6月30日 15:52:02
-- Description: 將指定字串按照指定的分裂符分裂為單列表
-- ======================================================
CREATE FUNCTION dbo.funGetSplitStr2
(
@str varchar(1000),
@strSperate varchar(10)
)
RETURNS @tableVar TABLE
(
F1 VARCHAR(100)
)
AS
BEGIN
DECLARE @xmlstr XML;
--SET ARITHABORT ON;
SET @xmlstr = CONVERT(XML, '<root><v>' + REPLACE(@str, @strSperate, '</v><v>') + '</v></root>');
--SELECT @xmlstr;
INSERT INTO @tableVar
SELECT F1 = N.v.value('.', 'varchar(100)') FROM @xmlstr.nodes('/root/v') N(v);
RETURN;
END;
GO
--測試
SELECT * FROM funGetSpliterStr2('1.2.3','.')
--結果
F1
---------
1
2
3
(3 行受影響)
3. 使用示例
程式碼中傳遞的引數@Ids="1,2,3,4"
,執行儲存過程作為篩選條件
這裡任意使用一個測試表Company,該表有一個Id欄位,儲存過程簡單的演示了Ids字串進行查詢
- 建立測試儲存過程
CREATE PROCEDURE [dbo].[proTest]
@Ids VARCHAR(500)
AS
BEGIN
SELECT *
FROM dbo.Company
WHERE Id IN
(
SELECT F1 FROM dbo.funGetSplitStr(@Ids, ',')
);
END;
EXEC dbo.proTest @Ids = '1,3';