我用sp_executesql
编写了两个存储过程,其他没有sp_executesql
两者正在执行相同的结果,我没有得到
EXEC(@SQL)vs 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'
答案 0 :(得分:18)
除了用法之外,还有一些重要的区别:
UPDATE
允许参数化语句
因此,就SQL注入而言,它比MERGE INTO MYTABLE A USING
(
SELECT Y, Z, X
FROM MYTABLE_TEMP T
JOIN (SELECT X FROM TABLE_X
WHERE COLUMN_N = '81205' GROUP BY 1) S ON S.X = T.X
) B
ON (A.Y = B.Y) AND (A.X = B.X)
WHEN MATCHED THEN UPDATE SET /*remove the A.*/ LOAD_DS = B.LOAD_DS
WHEN NOT MATCHED THEN INSERT VALUES (B.Y, B.Z, B.X, B.LOAD_DS );
更安全
sp_executesql
可以利用缓存的查询计划。
TSQL字符串只构建一次,之后每次使用EXEC
调用相同的查询时,SQL Server从缓存中检索查询计划并重新使用
在sp_executesql
中创建的临时表不能使用临时表缓存机制
答案 1 :(得分:17)
您的 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'
答案 2 :(得分:4)
使用sp_executesql
,您无需像这样构建查询。您可以这样声明:
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' +
@TableName + ' where Status=@eStatus'
这样,如果您的@Status
值来自用户,则可以使用@eStatus
,而不必担心转义'
。 sp_executesql使您能够以字符串形式将变量放入查询中,而不是使用串联。所以你不必担心。
列和表变量仍然相同,但不太可能直接来自用户。
答案 3 :(得分:2)
使用 Exec 您的T-Sql语句字符串中不能有占位符。
sp_executesql的 为您提供占位符的优势,并在运行时
中传递实际值