T-SQL将CSV字符串传递给存储过程时出现问题

时间:2010-07-21 12:26:14

标签: tsql

我有一个程序,它返回ID与传递的参数相关联的行,即1,5,7,9

ALTER PROCEDURE [dbo].[get_data]
 @MyCodes as varchar(max) = ''
AS
BEGIN
 DECLARE @query as nvarchar(max)

 set @query = 'SELECT name FROM user WHERE id IN (@p_MyCodes)'

 exec SP_EXECUTESQL @query,
                        N'@p_MyCodes varchar(max)', 
                        @p_MyCodes = @MyCodes
END

该过程会生成错误:将数据类型varchar转换为数字时出错。当我作为参数传递时3,7,5

怎么了?

3 个答案:

答案 0 :(得分:3)

我认为这不会达到你所期望的目标。您得到的错误是因为它无法将字符串'3,7,5'转换为数字(请注意,它不会尝试解析您的个别值)。

获得所需内容的两种方法:

1)创建一个表值函数,它接受一个CSV字符串并返回结果(我确定网上有很多;这是一个相关的问题:Split function equivalent in T-SQL?)。这很好,因为你可以完全摆脱SP_EXECUTESQL sproc调用;您的查询变为:

SELECT name FROM user where id IN (SELECT value FROM dbo.f_Split(@p_MyCodes))

2)将您的设置更改为:

set @query = 'SELECT name FROM user WHERE id in (' + @p_MyCodes + ')'

我不推荐#2,它提供了SQL注入漏洞。

答案 1 :(得分:1)

您无法将ID列表作为参数传递。您可以通过连接:

来创建SQL语句
set @query = 'SELECT name FROM user WHERE id IN (' + @MyCodes + ')'
exec SP_EXECUTESQL @query

但是,这会禁用任何类型的执行计划重用并启用SQL注入

更好的解决方案是将列表拆分为临时表(或表变量)并使用JOIN。去年,我写了一篇关于在T-SQL中拆分字符串的不同方法的博客文章: http://florianreischl.blogspot.com/2009/09/high-performance-string-split-functions.html

答案 2 :(得分:0)

您不能将逗号分隔的字符串与in运算符一起使用,您必须使用实际值。因此,您要么必须拆分字符串并将值放在临时表中,要么将字符串连接到查询中:

set @query = 'SELECT name FROM user WHERE id IN (' + @p_MyCodes + ')'

请注意,这为SQL注入打开了一个潜在的安全漏洞。如果您无法完全控制字符串的来源,则不应该这样做。