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';