sqlserver拆分字符串成列_SQL Server解惑——查询条件IN中能否使用变量

本文探讨了在SQL Server中如何在查询条件IN中使用变量,以及当需要拆分字符串成列时的不同解决方案,包括动态SQL、临时表或表变量、STRING_SPLIT函数和XML函数的应用。通过示例展示了潜在的问题和正确的处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  在SQL Server的查询条件中,能否在IN里面使用变量呢?如果可以的话,有没有需要注意的地方或一些限制呢?在回答这个问题前,我们先来看看这个例子:

IF EXISTS (SELECT 1 FROM sys.objects WHERE name='TEST' AND type='U')
BEGIN
 DROP TABLE TEST;
END
GO
CREATE TABLE TEST ( ID INT, NAME VARCHAR(16) );
GO

INSERT INTO dbo.TEST
SELECT 1, 'a'  UNION ALL
SELECT 2, 'b'  UNION ALL
SELECT 3, 'c'  UNION ALL
SELECT 4, 'a,b'UNION ALL
SELECT 5, '''b'',''c''' UNION ALL
SELECT 6, '''b';
GO
113bc4eb92fe11a4f48f22adf7c8b2c4.png

如下所示,如果查询条件里面,变量只有一个值,此时SQL是正常的。

DECLARE @name VARCHAR(16);
SET @name='a';

SELECT * FROM TEST WHERE name IN (@name);
GO

DECLARE @name VARCHAR(16);
SET @name='a,b';

SELECT * FROM TEST WHERE name IN (@name);
GO

  如果我们想在查询条件IN里面输入多个值呢?假如有这样的一个需求,一个变量里面包含b和c的值,现在用'b|c’作为条件传入,对其进行拆分为变量'b'和'c', 想查出name=b 和name=c的记录,如下截图所示,SQL其实并没有按你所“设想/预想”的查出对应记录,而是将ID=5的记录查出来了

DECLARE @name1 VARCHAR(16);
DECLARE @name2 VARCHAR(16);
SET @name1='b|c';
SET @name2=REPLACE(@name1,'|',''',''')
SELECT @name2

SELECT * FROM TEST WHERE name IN (('''' + @name2 + ''''));
0df42e0116342bbbe3a9dda4a9edb41d.png

下面这个SQL也是同样的结果。

DECLARE @name1 VARCHAR(16);
DECLARE @name2 VARCHAR(16);
SET @name1='b|c';
SET @name2='''' + REPLACE(@name1,'|',''',''') +''''
SELECT @name2

SELECT * FROM TEST WHERE name IN (@name2 );

  为什么出现了这样的结果呢?查了大量的官方文档,没有看到关于这个问题的介绍和解释。如果一定要解释上面现象的情况的话,那么是因为SELECT * FROM TEST WHERE name IN (@name2 ); 其实转化为了SELECT * FROM TEST WHERE name =@name2; 也就是说,上面SQL并不会按你所“设想”的逻辑运算。而是做了一个转换,为什么说是这样的一个转换呢?当然这也是一个猜想,上面构造的例子也是为了侧面验证这个猜想,另外,上面两个SQL实际执行计划的参数列表(Parameter List)也侧面印证了这个猜想(如下截图所示)。如果执行计划解析成我们想要的结果,那么Parameter List应该是'b' 和‘c'

6b148dffb76ceb732f2272cd53f61798.png
7e139bd75c042784bec1ea0f48679765.png

解决方案:

1:使用动态SQL

使用动态SQL解决问题,似乎没啥好说的,如下例子所示:

DECLARE @sql_cmd NVARCHAR(max);
DECLARE @name VARCHAR(16);

SET @name='b|c';
SET @sql_cmd='SELECT * FROM TEST WHERE name IN (''' + REPLACE(@name,'|',''',''') +''');'

EXEC sp_executesql @sql_cmd;
c7f250afe3d582e8b5a2930b45af05bd.png
2:使用临时表或表变量

以这个例子来说,就是将字符串拆分,放入临时表或表变量,然后关联表也好,在IN里面使用子查询也OK。

3:借助STRING_SPLIT()
DECLARE @name VARCHAR(16);

SET @name='b|c';
SELECT *FROM  test WHERE name IN (SELECT value FROM STRING_SPLIT(@name, '|'))
303a1e76eceac77839c8a3031b1610bf.png

注意:STRING_SPLIT函数只有较高版本才支持,SQL Server 2017或SQL Server 2016部分版本支持。

4:借助XML函数来解决问题
DECLARE @name VARCHAR(16);
DECLARE @xml_para XML;

SET @name = 'b|c';
SET @xml_para = CAST(( '' + REPLACE(@name, '|', '') + '' ) AS XML);


SELECT  *
FROM    dbo.TEST
WHERE   NAME IN ( SELECT    A.value('.', 'varchar(max)') AS [Column]
                  FROM      @xml_para.nodes('A') AS FN ( A ) );
a6e957fe0b4b194704ae391da9df9450.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值