Оголосіть змінну для рядка запиту


92

Мені було цікаво, чи є спосіб зробити це в 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

Чи можливо це зробити?


Відповіді:


96

Це можливо, але для цього потрібно використовувати динамічний SQL.
Я рекомендую прочитати Прокляття та благословення динамічного 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)

Динамічний SQL - це просто оператор SQL, складений у вигляді рядка перед виконанням. Тож відбувається звичайна конкатенація рядків. Динамічний SQL потрібен щоразу, коли ви хочете зробити щось у синтаксисі SQL, що заборонено, наприклад:

  • один параметр, який представляє список значень, розділених комами, для речення IN
  • змінна, що представляє як значення, так і синтаксис SQL (IE: приклад, який ви надали)

EXEC sp_executesql дозволяє використовувати параметри прив'язки / підготовленого звіту, щоб вам не довелося турбуватися про те, щоб уникати одинарних лапок / тощо для атак SQL-ін'єкції.


Я думаю, це найбільш правильна відповідь. Нещодавно я також використовую SQL Server 2005, і використання змінної для заміни рядка запиту, як OP, неможливо (генерує синтаксичні помилки). Змінні не можуть включати як синтаксис, так і типи даних, як говорить @Ponies. Динамічний SQL - це спосіб побудови запитів у SQL Server за допомогою рядків. Тільки пам’ятайте, будьте обережні щодо своїх пропозицій та типів! Рядок, який ви виконуєте, вимагає, щоб деякі типи, такі як datetime або int, були перетворені або передані для конкатенації рядків.
RoboBear

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

Потім змініть свій запит, щоб використовувати таку логіку:

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

2
Тримайся. Це не може бути відповіддю, якщо у питанні чітко вказані дві різні дати. Як ви врешті кодували це @StealthRT? Де у відповіді дата „31.08.2010“? Крім того, питання чітко задає питання, чи можна використовувати змінні DECLARE для підстановки коду в інший оператор SELECT. Правильна відповідь - нижче.
Fandango68

2

Використання EXEC

Ви можете використовувати наступний приклад для побудови оператора 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)

Використовуючи sp_executesql

За допомогою цього підходу ви можете переконатися, що значення даних, що передаються у запит, є правильними типами даних і уникати використання більшої кількості лапок.

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

Довідково


1

Я зазначу, що у статті, на яку посилається найвища оцінка відповіді «Прокляття та благословення динамічного SQL», автор стверджує, що відповідь полягає не у використанні динамічного SQL. Прокрутіть майже до кінця, щоб побачити це.

Зі статті: "Правильним методом є розпакування списку в таблиці з визначеною користувачем функцією або збереженою процедурою".

Звичайно, як тільки список буде в таблиці, ви можете використовувати об'єднання. Я не міг коментувати безпосередньо найвищу оцінку відповіді, тому я просто додав цей коментар.


Це не дає відповіді на запитання. Отримавши достатню репутацію, ви зможете коментувати будь-яку публікацію ; натомість надайте відповіді, які не вимагають роз’яснень від запитувача . - З огляду
Sam M

Дякую Сем. Я оновлю свій коментар детально, як тільки я застосую те, що пропонує Ерланд Сомарський. Я також буду посилатись на нього по імені, оскільки він заслуговує на визнання відповіді.
DavidG
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.