Можно ли запускать динамические сценарии SQL, включающие объявление переменных?
Пример:
Важная заметка: этот пример предназначен только для демонстрации механизма, который мне нужно реализовать. Показанный расчет для простоты прост.
Мне нужно вернуть минимальное значение между 4 переданными значениями, поэтому программно я создаю строку, содержащую следующий код:
DECLARE @_1 INT = 12 ;
DECLARE @_2 INT = 22 ;
DECLARE @_3 INT = 32 ;
DECLARE @_4 INT = 42 ;
DECLARE @_Min = NULL ;
SET @_Min = @_1 ;
IF (@_2 < @_Min) SET @_Min = @_2 ;
IF (@_3 < @_Min) SET @_Min = @_3 ;
IF (@_4 < @_Min) SET @_Min = @_4 ;
SELECT @_Min ;
Опять же, все это содержится в строковой переменной (скажем, @_Command).
Чтобы выполнить это и получить результат расчета, я бы выполнил следующую команду:
EXECUTE sp_executesql @_l_Command ,
N'@_l_Result FLOAT OUTPUT' ,
@_l_Result = @_l_Result OUTPUT ;
При запуске я получаю сообщение об ошибке:
Msg 156, Level 15, State 1, Line 1 Incorrect syntax near the keyword 'DECLARE'.
Очевидно, я делаю что-то синтаксически неправильно, но не могу понять, что это могло быть.
Ваш лучший друг: PRINT @DynamicSQLVariable;. Если вы не можете запустить SQL, распечатанный из оператора PRINT, то и sp_executesql не сможет. если вы получаете синтаксическую ошибку, то причина не в том, что вы «что-то не можете сделать» в динамическом SQL; дело в том, что синтаксис динамического SQL неверен.
@Larnu, я был совершенно уверен, что можно объявить переменные (я делал такие вещи, используя другие СУБД, такие как MySQL и Oracle), поэтому я сначала предположил, что проблема где-то в синтаксисе.
@FDavidov Я не говорил, что это невозможно? Попробуйте, например: DECLARE @SQL nvarchar(MAX) = 'DECLARE @i int = 1; SELECT @i AS i;'; EXEC (@SQL); работает нормально. Я представлял вам PRINT, и вы должны отлаживать SQL, который он выводит.
@ Ларну, все в порядке. Тест с использованием вывода PRINT, который я, конечно же, выполнил перед тем, как опубликовать свой вопрос. См. Ответ Naeemaei ниже.
Я не хочу намекать, что вы не пытались отладить с помощью PRINT, однако, если бы вы это сделали, можно было бы ожидать, что вы заметили бы, что пропустили объявление вашего типа данных для переменной @_Min. Как отметил @Faraz. :)
@ Ларну, все в порядке. Я не понял это так, как ты имел в виду. Мы все совершаем ошибки, независимо от того, сколько мы знаем. Иногда наши ошибки машут руками перед нашими глазами, и мы почему-то их не видим. Это случается со мной, со всеми. Спасибо за время, потраченное на это дело. Ваше здоровье!!!!





Да, вы можете объявлять переменные в динамическом запросе.
укажите тип переменной @_Min в запросе
Я запускаю ваш запрос без ошибок
DECLARE @_l_Result NVARCHAR(MAX)
DECLARE @_l_Command NVARCHAR(MAX)='
DECLARE @_1 INT = 12 ;
DECLARE @_2 INT = 22 ;
DECLARE @_3 INT = 32 ;
DECLARE @_4 INT = 42 ;
DECLARE @_Min int = NULL ;
SET @_Min = @_1 ;
IF (@_2 < @_Min) SET @_Min = @_2 ;
IF (@_3 < @_Min) SET @_Min = @_3 ;
IF (@_4 < @_Min) SET @_Min = @_4 ;
SELECT @_Min as res ;'
EXECUTE sp_executesql @_l_Command ,
N'@_l_Result FLOAT OUTPUT' ,
@_l_Result = @_l_Result OUTPUT ;
или же
EXECUTE sp_executesql @_l_Command
Хороший!!! Я проверю, где была моя ошибка, используя ваш пример в качестве основы, и дам вам знать (правда, на следующей неделе). А пока спасибо.
Что ж, Naeemaei, не только это работает, но я теперь возвращаю больше, чем по значению (выходам). Действительно отличная помощь !! (и, конечно же, ты получил мой голос).
Вы можете использовать эту команду для отображения созданного запроса на вкладке сообщений: ---> PRINT @_l_Command
Помимо установки типа переменной для @ _Min, если вам нужно передать значения, вы также должны передать входы как отдельные входы при выполнении sp_executesql, как показано ниже
DECLARE @_l_Command nVarchar(max),@Params nVarchar(max)
SET @_l_Command='SET @_Min = @_1 ;
IF (@_2 < @_Min) SET @_Min = @_2 ;
IF (@_3 < @_Min) SET @_Min = @_3 ;
IF (@_4 < @_Min) SET @_Min = @_4 ;
SELECT @_Min ;'
SET @Params='@_1 INT,@_2 INT,@_3 INT,@_4 INT,@_Min INT'
EXECUTE sp_executesql @_l_Command,@Params,12,22,32,42,NULL
Поскольку у меня есть фактические значения входных параметров вычислений, нет смысла добавлять их в список параметров sp_executesql, поскольку они могут быть установлены как назначенные при создании команды. Таким образом, оператор EXECUTE sp_executesql может быть обобщен для любого типа вычислений независимо от количества входов (которое может быть от 1 до 100).
Отсутствует тип данных в DECLARE @_Min = NULL;