Zadeklaruj zmienną dla ciągu zapytania


92

Zastanawiałem się, czy można to zrobić w 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

Czy to się da zrobić?


Odpowiedzi:


97

Jest to możliwe, ale wymaga użycia dynamicznego SQL. Przed kontynuowaniem
polecam przeczytanie Klątwy i błogosławieństwa dynamicznego SQL ...

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)

Dynamiczny SQL to po prostu instrukcja SQL, złożona jako łańcuch przed wykonaniem. Tak więc następuje zwykłe konkatenowanie ciągów. Dynamiczny SQL jest wymagany, gdy chcesz zrobić coś w składni SQL, co jest niedozwolone, na przykład:

  • pojedynczy parametr reprezentujący listę wartości oddzielonych przecinkami dla klauzuli IN
  • zmienna reprezentująca zarówno wartość, jak i składnię SQL (IE: podany przykład)

EXEC sp_executesql pozwala na użycie parametrów bind / readystatement, dzięki czemu nie musisz martwić się o unikanie pojedynczych cudzysłowów / itp. w przypadku ataków typu SQL injection.


Myślę, że to najbardziej poprawna odpowiedź. Ostatnio używam SQL Server 2005 i używanie zmiennej do zastępowania ciągu zapytania, tak jak chce tego OP, nie jest możliwe (generuje błędy składniowe). Zmienne nie mogą zawierać zarówno składni, jak i typów danych, jak mówi @Ponies. Dynamiczny SQL to sposób tworzenia zapytań w SQL Server za pomocą ciągów. Pamiętaj tylko, aby uważać na swoje cytaty i typy! Wykonywany ciąg wymaga konwersji lub rzutowania niektórych typów, takich jak datetime lub int, w celu połączenia ciągów.
RoboBear

52
DECLARE @theDate DATETIME
SET @theDate = '2010-01-01'

Następnie zmień zapytanie, aby używać tej logiki:

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

2
Wytrzymać. To nie może być odpowiedź, jeśli pytanie wyraźnie wskazuje dwie różne daty. Jak ostatecznie zakodowałeś to @StealthRT? Gdzie w odpowiedzi jest data „2010-08-31”? Ponadto pytanie wyraźnie dotyczy tego, czy można użyć zmiennych DECLARE, aby zastąpić kod inną instrukcją SELECT. Prawidłowa odpowiedź znajduje się poniżej.
Fandango68

2

Korzystanie z EXEC

Możesz użyć następującego przykładu do zbudowania instrukcji 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)

Korzystanie z sp_executesql

Korzystając z tego podejścia, możesz upewnić się, że wartości danych przekazywane do zapytania są poprawnymi typami danych i uniknąć używania większej liczby cudzysłowów.

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

Odniesienie


1

Zwrócę uwagę, że w artykule, do którego link znajduje się w najwyżej ocenianej odpowiedzi The Curse and Blessings of Dynamic SQL, autor stwierdza, że ​​odpowiedzią nie jest używanie dynamicznego SQL. Przewiń prawie do końca, aby to zobaczyć.

Z artykułu: „Poprawną metodą jest rozpakowanie listy do tabeli zawierającej funkcję zdefiniowaną przez użytkownika lub procedurę składowaną”.

Oczywiście, gdy lista znajduje się w tabeli, możesz użyć złączenia. Nie mogłem bezpośrednio skomentować najwyżej ocenionej odpowiedzi, więc właśnie dodałem ten komentarz.


To nie daje odpowiedzi na pytanie. Gdy zdobędziesz wystarczającą reputację , będziesz mógł komentować każdy post ; zamiast tego udziel odpowiedzi, które nie wymagają wyjaśnień od pytającego . - Z recenzji
Sam M

Dzięki, Sam. Zaktualizuję swój komentarz szczegółami, gdy wdrożę sugestie Erlanda Sommarskoga. Będę również odnosił się do niego po imieniu, ponieważ zasługuje na uznanie za odpowiedź.
DavidG,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.