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

92

Je me demandais s'il y avait un moyen de le faire 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?

StealthRT
la source

Réponses:

96

C'est possible, mais cela nécessite l'utilisation de SQL dynamique.
Je recommande de lire La malédiction et les bénédictions du 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 simplement une instruction SQL, composée sous forme de chaîne avant d'être exécutée. Ainsi, la concaténation de chaînes habituelle se produit. Le SQL dynamique est requis chaque fois que vous voulez faire quelque chose dans la syntaxe SQL qui n'est pas autorisé, comme:

  • un seul paramètre pour représenter une liste de valeurs séparées par des virgules pour une clause IN
  • une variable pour représenter à 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 / preparestatement afin que vous n'ayez pas à vous soucier des échappements entre guillemets simples / etc pour les attaques par injection SQL.

Poneys OMG
la source
Je pense que c'est la réponse la plus correcte. J'ai également utilisé SQL Server 2005 récemment, et l'utilisation d'une variable pour le remplacement de la chaîne de requête comme le souhaite l'OP n'est pas possible (génère des erreurs de syntaxe). Les variables ne peuvent pas inclure à la fois la syntaxe et les types de données, comme le dit @Ponies. Le SQL dynamique est le moyen de créer des requêtes dans SQL Server via des chaînes. N'oubliez pas de faire attention à vos citations et types! La chaîne que vous exécutez nécessite que certains types, comme datetime ou int, soient convertis ou castés pour la concaténation de chaînes.
RoboBear
52
DECLARE @theDate DATETIME
SET @theDate = '2010-01-01'

Modifiez ensuite votre requête pour utiliser cette logique:

AND 
(
    tblWO.OrderDate > DATEADD(MILLISECOND, -1, @theDate) 
    AND tblWO.OrderDate < DATEADD(DAY, 1, @theDate)
)
chasseur
la source
2
Attendre. Cela ne peut pas être la réponse si la question indique clairement deux dates différentes. Comment l'avez-vous codé à la fin @StealthRT? Où est la date «2010-08-31» dans la réponse? En outre, la question demande clairement si vous pouvez utiliser des variables DECLARE pour remplacer du code dans une autre instruction SELECT. La bonne réponse est ci-dessous.
Fandango68
2

Utiliser EXEC

Vous pouvez utiliser l'exemple suivant pour créer 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

En utilisant cette approche, vous pouvez vous assurer que les valeurs de données transmises à la requête sont les types de données corrects et ne pas utiliser plus de guillemets.

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

Somnath Muluk
la source
1

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

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, je viens donc d'ajouter ce commentaire.

DavidG
la source
Cela ne répond pas à la question. Une fois que vous aurez une réputation suffisante, vous pourrez commenter n'importe quel message ; au lieu de cela, fournissez des réponses qui ne nécessitent pas de clarification de la part du demandeur . - De l'avis
Sam M
Merci Sam. Je mettrai à jour mon commentaire avec des détails une fois que j'aurai implémenté ce que suggère Erland Sommarskog. Je vais également le citer par son nom, car il mérite le crédit pour la réponse.
DavidG