将形式为" GUID1,GUID2,GUID3 ..."的字符串插入TSQL的IN语句中

时间:2020-03-06 14:21:57  来源:igfitidea点击:

我的数据库中有一个存储过程,看起来像这样

ALTER PROCEDURE [dbo].[GetCountingAnalysisResults] 
    @RespondentFilters varchar
AS
BEGIN

@RespondentFilters = '''8ec94bed-fed6-4627-8d45-21619331d82a, 114c61f2-8935-4755-b4e9-4a598a51cc7f'''

DECLARE @SQL nvarchar(600)

SET @SQL = 
   'SELECT *
    FROM Answer
    WHERE Answer.RespondentId IN ('+@RespondentFilters+'''))
    GROUP BY ChosenOptionId'

exec sp_executesql @SQL

END

它可以编译和执行,但是以某种方式它不会给我带来很好的结果,就像IN语句不起作用一样。请,如果有人知道该问题的解决方案,请帮助我。

解决方案

看来我们在@RespondentFilters周围没有右引号

'8ec94bed-fed6-4627-8d45-21619331d82a, 114c61f2-8935-4755-b4e9-4a598a51cc7f'

由于GUID会进行字符串比较,因此无法正常工作。

最好的选择是使用一些代码将列表分成多个值。

像这样的东西:

-- This would be the input parameter of the stored procedure, if you want to do it that way, or a UDF
declare @string varchar(500)
set @string = 'ABC,DEF,GHIJK,LMNOPQRS,T,UV,WXY,Z'

declare @pos int
declare @piece varchar(500)

-- Need to tack a delimiter onto the end of the input string if one doesn't exist
if right(rtrim(@string),1)  ','
 set @string = @string  + ','

set @pos =  patindex('%,%' , @string)
while @pos  0
begin
 set @piece = left(@string, @pos - 1)

 -- You have a piece of data, so insert it, print it, do whatever you want to with it.
 print cast(@piece as varchar(500))

 set @string = stuff(@string, 1, @pos, '')
 set @pos =  patindex('%,%' , @string)
end

雷蒙·雷沃伦(Raymond Lewallen)被盗的代码

我认为我们也需要在字符串内加上引号。尝试:

@RespondentFilters = '''8ec94bed-fed6-4627-8d45-21619331d82a'',''114c61f2-8935-4755-b4e9-4a598a51cc7f'''

我们也可以考虑将@RespondentFilters解析为一个临时表。

我们需要在列表中的每个GUID周围加上单引号

@RespondentFilters = '''8ec94bed-fed6-4627-8d45-21619331d82a'', ''114c61f2-8935-4755-b4e9-4a598a51cc7f'''

我们绝对应该看一下将GUID列表拆分为一个表并与该表联接的情况。我们应该可以在线上找到大量关于表值函数的示例,该函数将输入字符串拆分为表。

否则,存储过程很容易受到SQL注入的攻击。考虑@RespondentFilters的以下值:

@RespondentFilters = '''''); SELECT * FROM User; /*'

查询将更安全地解析(即验证)参数值并加入:

SELECT *
FROM Answer
WHERE Answer.RespondentId IN (SELECT [Item] FROM dbo.ParseList(@RespondentFilters))
GROUP BY ChosenOptionId

或者

SELECT *
FROM Answer
INNER JOIN dbo.ParseList(@RespondentFilters) Filter ON Filter.Item = Answer.RespondentId
GROUP BY ChosenOptionId

由于我们不是在处理动态SQL(sp_executesql会缓存查询计划,但我不确定它是否可以将查询准确地标识为参数化查询,因为它在其中包含可变的项目列表),因此效率也稍高一些IN子句)。

罐大家为ansewers。他们都帮了很多忙。我已经通过编写split函数解决了这个问题,并且效果很好。我本来可以做的只是一点点开销,但是我们知道,截止日期就在眼前:)