J'ai écrit deux procédures stockées dont une avec sp_executesql
et d'autres n'ont pas sp_executesql les deux exécutent correctement les mêmes résultats, je n'ai pas compris quelle est la différence ici entre
EXEC (@SQL) vs EXEC sp_executesql @SQL, N '@ eStatus varchar (12)', @eStatus = @Status
et comment EXEC (@SQL) est sujet à l'injection SQL et sp_executesql @SQL ...... ne l'est pas?
Procédure stockée ci-dessous sans 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'
Procédure stockée ci-dessous avec 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'
Votre sp_executesql SQL devrait probablement l'être;
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' +
@TableName + ' where Status=@eStatus'
Cela vous permettra d'appeler sp_executesql avec @eStatus comme paramètre au lieu de l'intégrer dans le SQL. Cela donnera l'avantage que @eStatus peut contenir tous les caractères et il sera correctement correctement échappé automatiquement par la base de données si nécessaire pour être sécurisé.
Comparez cela au SQL requis pour EXEC ;
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' +
@TableName + ' where Status=' + char(39) + @Status + char(39)
... où un caractère (39) intégré dans @Status rendra votre SQL invalide et créera éventuellement une possibilité d'injection SQL. Par exemple, si @Status est défini sur O'Reilly
, votre SQL résultant serait;
select acol,bcol,ccol FROM myTable WHERE Status='O'Reilly'
Outre l'utilisation, il existe quelques différences importantes:
sp_executesql
permet de paramétrer les instructions Par conséquent, il est plus sûr que EXEC
en termes d'injection SQL
sp_executesql
peut tirer parti des plans de requête mis en cache. La chaîne TSQL n'est générée qu'une seule fois, après quoi chaque fois qu'une même requête est appelée avec sp_executesql
, SQL Server récupère le plan de requête du cache et le réutilise
Les tables temporaires créées dans EXEC
ne peuvent pas utiliser le mécanisme de mise en cache des tables temporaires
Avec sp_executesql
, vous n'avez pas besoin de construire votre requête comme ça. Vous pouvez le déclarer comme ceci:
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' +
@TableName + ' where Status=@eStatus'
De cette façon, si votre @Status
la valeur provient d'un utilisateur que vous pouvez utiliser @eStatus
et ne pas avoir à vous soucier de vous échapper '
. sp_executesql vous donne la possibilité de mettre des variables dans votre requête sous forme de chaîne, au lieu d'utiliser la concaténation. Vous avez donc moins à vous soucier.
Les variables de colonne et de table sont toujours les mêmes, mais il est moins probable qu'elles proviennent directement d'un utilisateur.
Avec Exec Vous ne pouvez pas avoir un espace réservé dans votre chaîne d'instruction T-Sql.
sp_executesql vous donne l'avantage d'avoir un espace réservé et de passer la valeur réelle à runtime