You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server存储过程中如何在WHERE条件中传递数组参数

解决SQL Server存储过程处理逗号分隔字符串IN查询的问题

我来帮你搞定这个问题——你当前的存储过程没法正确解析逗号分隔的字符串,因为IN (@RigNameValue)会把整个"ABC,DEF"当成单个匹配值,而不是拆分成"ABC"和"DEF"两个独立的条件。下面给你几种实用的解决方案,按推荐程度排序:


方法1:使用内置的STRING_SPLIT函数(推荐,SQL Server 2016+)

SQL Server 2016及以上版本提供了内置的字符串拆分函数STRING_SPLIT,可以直接把逗号分隔的字符串拆成一行行的结果集,完美适配IN查询。修改后的存储过程如下:

ALTER PROCEDURE [dbo].[BookedChemicalsLists] 
    @RigNameValue VARCHAR(50) = null 
AS 
BEGIN 
    SET NOCOUNT ON; 

    SELECT * 
    FROM [BookedChemicals] 
    WHERE 
        -- 当参数为null时返回所有数据,否则匹配拆分后的RigName
        (@RigNameValue IS NULL 
        OR RigName IN (SELECT value FROM STRING_SPLIT(@RigNameValue, ',')))
END

说明:STRING_SPLIT会将输入的字符串按指定分隔符(这里是逗号)拆分,返回一个包含value列的表,IN子查询会遍历这个表的所有值来匹配RigName。


方法2:自定义字符串拆分函数(兼容SQL Server 2016之前版本)

如果你用的是更早的SQL Server版本,没有STRING_SPLIT,可以自己写一个表值函数来拆分字符串:

首先创建拆分函数:

CREATE FUNCTION dbo.SplitString
(
    @InputString NVARCHAR(MAX), -- 要拆分的字符串
    @Delimiter NVARCHAR(5)      -- 分隔符
)
RETURNS @OutputTable TABLE (Value NVARCHAR(MAX))
AS
BEGIN
    DECLARE @StartIndex INT, @EndIndex INT

    SET @StartIndex = 1
    -- 确保字符串末尾有分隔符,避免最后一个值被遗漏
    IF SUBSTRING(@InputString, LEN(@InputString), 1) <> @Delimiter
    BEGIN
        SET @InputString = @InputString + @Delimiter
    END

    WHILE CHARINDEX(@Delimiter, @InputString) > 0
    BEGIN
        SET @EndIndex = CHARINDEX(@Delimiter, @InputString)
        
        -- 截取当前分隔符前的子串并插入结果表
        INSERT INTO @OutputTable(Value)
        SELECT SUBSTRING(@InputString, @StartIndex, @EndIndex - @StartIndex)
        
        -- 截取剩余字符串继续循环
        SET @InputString = SUBSTRING(@InputString, @EndIndex + 1, LEN(@InputString))
    END

    RETURN
END

然后修改存储过程调用这个函数:

ALTER PROCEDURE [dbo].[BookedChemicalsLists] 
    @RigNameValue VARCHAR(50) = null 
AS 
BEGIN 
    SET NOCOUNT ON; 

    SELECT * 
    FROM [BookedChemicals] 
    WHERE 
        (@RigNameValue IS NULL 
        OR RigName IN (SELECT Value FROM dbo.SplitString(@RigNameValue, ',')))
END

方法3:动态SQL(不推荐,需注意SQL注入)

如果以上两种方法都不适用,也可以用动态SQL拼接查询语句,但必须做好参数化来避免SQL注入风险:

安全的参数化动态SQL版本

ALTER PROCEDURE [dbo].[BookedChemicalsLists] 
    @RigNameValue VARCHAR(50) = null 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @SQL NVARCHAR(MAX)
    DECLARE @ParamDefinition NVARCHAR(MAX) = '@RigNames VARCHAR(50)'

    -- 基础查询语句
    SET @SQL = 'SELECT * FROM [BookedChemicals] WHERE 1=1 '

    -- 如果参数不为空,拼接IN条件(用STRING_SPLIT保证安全)
    IF @RigNameValue IS NOT NULL
    BEGIN
        SET @SQL = @SQL + 'AND RigName IN (SELECT value FROM STRING_SPLIT(@RigNames, '',''))'
    END

    -- 执行参数化的动态SQL
    EXEC sp_executesql @SQL, @ParamDefinition, @RigNames = @RigNameValue
END

非参数化版本(不推荐,有注入风险)

如果必须用字符串拼接的方式,一定要对输入做转义,但还是不建议:

ALTER PROCEDURE [dbo].[BookedChemicalsLists] 
    @RigNameValue VARCHAR(50) = null 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @SQL NVARCHAR(MAX)
    SET @SQL = 'SELECT * FROM [BookedChemicals] WHERE 1=1 '

    IF @RigNameValue IS NOT NULL
    BEGIN
        -- 把逗号替换为'','',拼接成('ABC','DEF')的格式
        SET @SQL = @SQL + 'AND RigName IN (''' + REPLACE(@RigNameValue, ',', ''',''') + ''')'
    END

    EXEC sp_executesql @SQL
END

总结

  • 优先选择STRING_SPLIT,它是官方内置函数,性能和安全性都有保障;
  • 旧版本SQL Server用自定义拆分函数;
  • 动态SQL尽量用参数化版本,避免直接拼接用户输入,防止SQL注入。

内容的提问来源于stack exchange,提问作者Nabeel Mahmood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:12:33