【问题标题】:Stored procedure EXEC vs sp_executesql difference?存储过程 EXEC 与 sp_executesql 的区别?
【发布时间】:2013-01-21 05:53:53
【问题描述】:

我写了两个存储过程,一个是sp_executesql,另一个没有 sp_executesql 两者都正确执行相同的结果,我没有明白这里有什么区别

EXEC (@SQL) 与 EXEC sp_executesql @SQL, N'@eStatus varchar(12)', @eStatus = @Status

而 EXEC(@SQL) 是如何容易发生 SQL 注入的,而 sp_executesql @SQL......不是吗?

下面没有 sp_executesql 的存储过程

ALTER proc USP_GetEmpByStatus
(
@Status varchar(12)
)
AS
BEGIN
DECLARE @TableName AS sysname = 'Employee'
Declare @Columns as sysname = '*'
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + @TableName + ' where Status=' + char(39) + @Status + char(39)
print (@SQL)
EXEC (@SQL)
END

EXEC USP_GetEmpByStatus 'Active'

下面的存储过程用 sp_executesql

create proc USP_GetEmpByStatusWithSpExcute
(
@Status varchar(12)
)
AS
BEGIN
DECLARE @TableName AS sysname = 'JProCo.dbo.Employee'
Declare @Columns as sysname = '*'
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + @TableName + ' where Status=' + char(39) + @Status + char(39)
print @SQL
exec sp_executesql @SQL, N'@eStatus varchar(12)', @eStatus = @Status
END

EXEC USP_GetEmpByStatusWithSpExcute 'Active'

【问题讨论】:

标签: sql sql-server sql-server-2008 stored-procedures sql-server-2012


【解决方案1】:

您的 sp_executesql SQL 应该是;

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
            @TableName + ' where Status=@eStatus'

这将允许您使用@eStatus 作为参数调用 sp_executesql,而不是将其嵌入到 SQL 中。这将带来@eStatus 可以包含任何字符的优势,并且如果需要安全,它将被数据库自动正确转义。

将其与 EXEC 所需的 SQL 进行对比;

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
            @TableName + ' where Status=' + char(39) + @Status + char(39)

...@Status 中嵌入的 char(39) 将使您的 SQL 无效,并可能产生 SQL 注入的可能性。例如,如果 @Status 设置为 O'Reilly,则生成的 SQL 将是;

select acol,bcol,ccol FROM myTable WHERE Status='O'Reilly'

【讨论】:

  • 为什么 where 子句没有用 ' 括起来?
  • @user1095881 如果您用引号将@eStatus 括起来,它将使用字符串 '@eStatus' 在数据库中搜索,如果您使用不带引号的@eStatus,则 将被使用。例如,如果@eStatus 是'test',INSERT INTO myTable VALUES (@eStatus) 将插入字符串'test',而INSERT INTO myTable VALUES ('@eStatus') 将插入字符串'@eStatus'。
  • 我认为这在第一个代码示例中缺少结束 '
  • 另一个区别是当你在动态 sql 中使用临时表时,sp_executesql 使用缓存计划,而 exec 不使用它
【解决方案2】:

使用sp_executesql,您不必像那样构建查询。你可以这样声明:

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
@TableName + ' where Status=@eStatus'

这样,如果您的@Status 值来自用户,您可以使用@eStatus 而不必担心转义'。 sp_executesql 使您能够以字符串形式将变量放入查询中,而不是使用连接。所以你不必担心。

列和表变量仍然相同,但不太可能直接来自用户。

【讨论】:

    【解决方案3】:

    使用 Exec 您的 T-Sql 语句字符串中不能有 占位符

    sp_executesql 为您提供具有占位符并在运行时

    传递实际值的优势

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      • 2021-10-04
      相关资源
      最近更新 更多