将形式为" 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函数解决了这个问题,并且效果很好。我本来可以做的只是一点点开销,但是我们知道,截止日期就在眼前:)