web-dev-qa-db-fra.com

Déclarer une variable pour une chaîne de requête

Je me demandais s'il y avait un moyen de faire cela dans MS SQL Server 2005:

  DECLARE @theDate varchar(60)
  SET @theDate = '''2010-01-01'' AND ''2010-08-31 23:59:59'''

  SELECT    AdministratorCode, 
            SUM(Total) as theTotal, 
            SUM(WOD.Quantity) as theQty, 
            AVG(Total) as avgTotal, 
            (SELECT SUM(tblWOD.Amount)
                FROM tblWOD
                JOIN tblWO on tblWOD.OrderID = tblWO.ID
                WHERE tblWO.Approved = '1' 
                AND tblWO.AdministratorCode = tblWO.AdministratorCode
                AND tblWO.OrderDate BETWEEN @theDate
            )
 ... etc

Est-ce possible?

75
StealthRT

C'est possible, mais cela nécessite l'utilisation de SQL dynamique.
Je recommande de lire La malédiction et les bénédictions de SQL dynamique avant de continuer ...

DECLARE @theDate varchar(60)
SET @theDate = '''2010-01-01'' AND ''2010-08-31 23:59:59'''

DECLARE @SQL VARCHAR(MAX)  
SET @SQL = 'SELECT AdministratorCode, 
                   SUM(Total) as theTotal, 
                   SUM(WOD.Quantity) as theQty, 
                   AVG(Total) as avgTotal, 
                  (SELECT SUM(tblWOD.Amount)
                     FROM tblWOD
                     JOIN tblWO on tblWOD.OrderID = tblWO.ID
                    WHERE tblWO.Approved = ''1''
                      AND tblWO.AdministratorCode = tblWO.AdministratorCode
                      AND tblWO.OrderDate BETWEEN '+ @theDate +')'

EXEC(@SQL)

Le SQL dynamique est juste une instruction SQL, composée comme une chaîne avant d'être exécutée. Donc, la concaténation de chaînes habituelle se produit. Le SQL dynamique est requis chaque fois que vous souhaitez utiliser une syntaxe SQL non autorisée, telle que:

  • un seul paramètre pour représenter une liste de valeurs séparées par des virgules pour une clause IN
  • une variable représentant à la fois la valeur et la syntaxe SQL (IE: l'exemple que vous avez fourni)

EXEC sp_executesql vous permet d'utiliser les paramètres bind/Preparstatement afin que vous n'ayez pas à vous préoccuper d'échapper aux guillemets simples/etc. pour les attaques par injection SQL.

79
OMG Ponies
DECLARE @theDate DATETIME
SET @theDate = '2010-01-01'

Puis changez votre requête pour utiliser cette logique:

AND 
(
    tblWO.OrderDate > DATEADD(MILLISECOND, -1, @theDate) 
    AND tblWO.OrderDate < DATEADD(DAY, 1, @theDate)
)
46
hunter

Utiliser EXEC

Vous pouvez utiliser l'exemple suivant pour générer une instruction SQL.

DECLARE @sqlCommand varchar(1000)
DECLARE @columnList varchar(75)
DECLARE @city varchar(75)
SET @columnList = 'CustomerID, ContactName, City'
SET @city = '''London'''
SET @sqlCommand = 'SELECT ' + @columnList + ' FROM customers WHERE City = ' + @city
EXEC (@sqlCommand)

Utilisation de sp_executesql

Avec cette approche, vous pouvez vous assurer que les valeurs de données transmises à la requête correspondent aux types de données corrects et éviter l'utilisation de guillemets supplémentaires.

DECLARE @sqlCommand nvarchar(1000)
DECLARE @columnList varchar(75)
DECLARE @city varchar(75)
SET @columnList = 'CustomerID, ContactName, City'
SET @city = 'London'
SET @sqlCommand = 'SELECT ' + @columnList + ' FROM customers WHERE City = @city'
EXECUTE sp_executesql @sqlCommand, N'@city nvarchar(75)', @city = @city

Référence

2
Somnath Muluk

Je soulignerai que dans l'article lié à la réponse la mieux notée La malédiction et les bénédictions de SQL dynamique l'auteur indique que la réponse est de ne pas utiliser de SQL dynamique. Faites défiler presque jusqu'à la fin pour voir cela.

De l'article: "La méthode correcte consiste à décompresser la liste dans une table avec une fonction définie par l'utilisateur ou une procédure stockée."

Bien sûr, une fois que la liste est dans une table, vous pouvez utiliser une jointure. Je ne pouvais pas commenter directement la réponse la mieux notée, alors je viens d'ajouter ce commentaire.

0
DavidG