如何在SQL Server中将列表作为变量传入WHERE IN子句
嘿,这个问题我天天见!你之所以用变量后返回空集,核心原因是SQL Server把你的@keys和@values当成了单个完整的字符串,而不是逗号分隔的多个独立值——打个比方,它会去匹配[key] = 'material, type',而不是分别匹配material和type,自然找不到结果啦。
下面给你几种靠谱的解决方案,按推荐度从高到低排序:
1. 使用STRING_SPLIT函数(SQL Server 2016及以上版本)
这是官方推荐的最简洁方案,STRING_SPLIT可以直接把CSV字符串拆分成一张包含单个值的临时表,完美适配IN子句。注意要加上TRIM处理掉逗号前后的空格(比如你示例里general purpose前面的空格):
DECLARE @keys NVARCHAR(MAX) = 'material, type' DECLARE @values NVARCHAR(MAX) = 'nylon/latex, general purpose' SELECT * FROM items WHERE [key] IN (SELECT TRIM(value) FROM STRING_SPLIT(@keys, ',')) AND value IN (SELECT TRIM(value) FROM STRING_SPLIT(@values, ','))
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 TRIM(SUBSTRING(@InputString, @StartIndex, @EndIndex - @StartIndex)) SET @InputString = SUBSTRING(@InputString, @EndIndex + 1, LEN(@InputString)) END RETURN END
使用方式和STRING_SPLIT类似:
DECLARE @keys NVARCHAR(MAX) = 'material, type' DECLARE @values NVARCHAR(MAX) = 'nylon/latex, general purpose' SELECT * FROM items WHERE [key] IN (SELECT Value FROM dbo.SplitString(@keys, ',')) AND value IN (SELECT Value FROM dbo.SplitString(@values, ','))
3. 动态SQL(谨慎使用,注意SQL注入风险)
如果前两种方法都不适用,也可以用动态SQL拼接成原始的查询语句,但一定要注意SQL注入风险,如果参数来自用户输入,必须严格处理:
DECLARE @keys NVARCHAR(MAX) = 'material, type' DECLARE @values NVARCHAR(MAX) = 'nylon/latex, general purpose' DECLARE @sql NVARCHAR(MAX) -- 转义字符串中的单引号,避免语法错误和注入 SET @keys = REPLACE(@keys, '''', '''''') SET @values = REPLACE(@values, '''', '''''') -- 拼接成原始的IN子句格式 SET @sql = 'SELECT * FROM items WHERE [key] IN (''' + REPLACE(@keys, ',', ''',''') + ''') AND value IN (''' + REPLACE(@values, ',', ''',''') + ''')' EXEC sp_executesql @sql
⚠️ 注意:如果@keys或@values是用户可控的输入,这种方法存在注入风险,优先推荐前两种方案。
总的来说,如果你用的是SQL Server 2016及以后,直接用STRING_SPLIT是最简洁安全的;老版本就用自定义拆分函数;动态SQL尽量少用,除非万不得已,而且一定要做好安全校验。
内容的提问来源于stack exchange,提问作者ang
相关产品推荐
相关产品推荐

