在动态SQL中使用局部变量不起作用

时间:2016-02-03 06:58:13

标签: sql sql-server dynamic-sql

使用参数的静态查询返回一行:

DECLARE @sqltext nvarchar(max)
DECLARE @status varchar(100)
SET @status = 'Active: Complete'

select * from status where StatusTitle = @status and type_id = 800

但是,如下所示在动态SQL查询中使用该参数根本不会返回任何行:

SET @sqltext = 'SELECT s.StatusID
FROM   [Status] s
WHERE  (
( s.StatusTitle ='' + @status + '' )
AND s.[type_id] = 800  )'

EXECUTE sp_executesql @sqltext

我知道WHERE子句有问题。我无法弄清楚如何纠正它。

3 个答案:

答案 0 :(得分:5)

您需要将@status格式化为语句。使用sp_executesql执行语句会创建新范围,而另一个范围的局部变量将不可见。

在您的陈述中,您可以通过在@status周围添加额外的引号来解决此问题。但是为了防止SQL注入,首先需要在@status中用两个单引号替换单引号。

SET @status=REPLACE(@status,'''','''''');
SET @sqltext = 'SELECT s.StatusID
FROM   [Status] s
WHERE  (
( s.StatusTitle =''' + @status + ''' )
AND s.[type_id] = 800  )'

EXECUTE sp_executesql @sqltext;

更好的是为sp_executesql提供INPUT参数。这样就不需要额外的引号和内容,并且可以通过这种方式保证防止SQL注入。

SET @sqltext = 'SELECT s.StatusID
FROM   [Status] s
WHERE  (
( s.StatusTitle = @status )
AND s.[type_id] = 800  )'

EXECUTE sp_executesql @sqltext, N'@status VARCHAR(100)', @status;

答案 1 :(得分:3)

这也将使您免于sql注入

DECLARE @sqltext nvarchar(max)
DECLARE @status varchar(100)
SET @status = 'Active: Complete'
SET @sqltext = 'SELECT s.StatusID
FROM   [Status] s
WHERE  (
( s.StatusTitle = @status )
AND s.[type_id] = 800  )'

DECLARE @params NVARCHAR(99)
SET @params = '@status nvarchar(99)'

EXECUTE sp_executesql @sqltext, @params, @status

答案 2 :(得分:1)

您在查询中错过了一对单引号,因此您的查询应该类似于

SET @sqltext = 'SELECT s.StatusID
FROM   [Status] s
WHERE  (
( s.StatusTitle =''' + @status + ''' )
AND s.[type_id] = 800  )'

EXECUTE(@sqltext)

如果您正在使用execute sp_executesql(强制语句缓存),那么您必须使用以下查询

SET @sqltext = 'SELECT s.StatusID
FROM   [Status] s
WHERE  (
( s.StatusTitle = @status )
AND s.[type_id] = 800  )'

EXECUTE sp_executesql @sqltext, N'@status NVARCHAR(100)', @status;

最佳做法是使用sp_executesql,然后可以限制sql注入

注意:

sp_executesql的优点

1.允许语句参数化。

2.具有强类型变量/参数 - 这可以减少注入并提供一些性能优势!

3.创建首次执行计划(类似于存储过程),后续执行重用此计划

注意2:问题已经有了可行的答案,我希望使用execute也是一种方法而且没有提到的答案,所以我也在答案中包含了这个