Значение переменной сценария sql по умолчанию - PullRequest
8 голосов
/ 19 сентября 2010

У меня есть файл сценария, например Test.sql. Я хочу вызвать это из другого скрипта, скажем, caller.sql, в режиме sqlcmd, используя: r test.sql. Это прекрасно работает, но я хочу использовать переменную сценария в test.sql. Когда я вызываю test.sql из caller.sql, я могу установить переменную скриптинга, и все хорошо. Однако я хочу использовать значение по умолчанию для значения сценария, чтобы, если вызывающая сторона не установила переменную или если я запускаю test.sql напрямую (не из caller.sql), тогда переменной сценария по умолчанию присваивается значение.

Я пробовал такие вещи, как

begin try
 select '$(grip)'
 select 'grip value was found'
end try
begin catch
 select 'grip value was missing'
end catch

но я просто получаю следующее сообщение: Произошла фатальная ошибка скриптинга. Переменная рукоятка не определена.

Что мне нужно в test.sql, чтобы он мог справиться с передачей 'grip' вызывающей стороне или нет? Я использую MS SQL 2005

Ответы [ 6 ]

4 голосов
/ 13 декабря 2011

Есть ОГРАНИЧЕННЫЙ обходной путь (я только проверял это на SS2008R2):

ПРОСТАЯ версия - если вы готовы жить без :on error exit / sqlcmd.exe -b:

:on error ignore -- Ensures that sqlcmd.exe will not fail when referencing an undefined scripting variable. Remove this if you want your script to work in SSMS in regular mode, too.
Declare @valueOrDefault as nvarchar(max)= N'$(value)';    
if @valueOrDefault = N'$' + N'(value)' set @valueOrDefault = N'default value'; -- Test if there is a value and, if not, assign a default; note the splitting of the reference string to avoid expansion.

-- use @valueOrDefault from now on

Примечание:

  • Поскольку переменные T-SQL не работают между пакетами, вы не можете запустить другой пакет (с помощью GO) и поэтому не можете переключиться на надежную обработку ошибок с помощью :on error exit. Следовательно, вы должны выполнить свою собственную обработку ошибок в оставшейся части скрипта - что нетривиально ; см. SQL Server - остановить или прервать выполнение сценария SQL
  • Если вы удалите :on error ignore, чтобы скрипт работал в SSMS в обычном режиме, убедитесь, что при запуске этого скрипта с помощью sqlcmd.exe вы НЕ указываете параметр -b, так как это предотвратит весь сценарий запускается, если указанная переменная сценария не существует.
  • Эффективно превращая переменную сценария в обычную переменную T-SQL, вы не можете использовать это значение в местах, где T-SQL ожидает литералы, например, в имени базы данных в операторе CREATE DATABASE.
  • Если переменная сценария не определена, в stderr выводится следующее предупреждение: Переменная сценария variableName не определена.

ROBUST версия - гораздо более громоздкая, но поддерживает :on error exit, что целесообразно:

-- Store the default value in the context info (session-level storage accessible across batches that holds up to 128 bytes).
declare @binDefaultValue varbinary(128)= CAST(N'default value' AS varbinary(128));
set CONTEXT_INFO @binDefaultValue;
go -- Make the set CONTEXT_INFO statement take effect.

-- If the scripting variable has a value, store ITS value in the context info instead.
:on error ignore -- Temporarily ignore errors so that accessing a non-existent scripting variable doesn't abort the entire script.
    declare @value as nvarchar(max) = N'$(value)'; -- Try to access the scripting variable; thanks to :on error ignore this will only give a warning.
    if @value <> N'$' + N'(value)' -- Test if there is a value; note the splitting of the reference string to avoid expansion.
    begin
    -- We have a scripting-variable value: Store it in the context info (replacing the default value).
        declare @binValue as varbinary(128) = cast(@value as varbinary(128));
        set CONTEXT_INFO @binValue;
    end
go -- End batch here, so we can switch back to :on error exit (requires a new batch).

:on error exit -- New batch: switch back to robust error handling.
-- End the batch here, so that SSMS in *regular* mode - which will fail on the line above - continues processing below.
-- Note that when run by sqlcmd.exe the subsequent batches will inherit :on error exit.
go

-- Retrieve the value or default value from the context info...
declare @valueOrDefault as nvarchar(max) = convert(nvarchar(max), CONTEXT_INFO(), 0);
-- ... and remove trailing null characters. ?? Is there an easier way to do this?
declare @pos as int = 0;
while @pos < LEN(@valueOrDefault)
begin
    set @pos=@pos+1
    if UNICODE(substring(@valueOrDefault, @pos, 1)) = 0  break;
end
if @pos > 0 set @valueOrDefault = left(@valueOrDefault, @pos - 1);

-- @valueOrDefault now contains the scripting-variable value or default value.
print 'Value or default value: [' + @valueOrDefault + ']';

Примечание:

  • Вышеуказанное работает как при вызове из sqlcmd.exe, так и в SSMS в обычном режиме - при условии, что в сценарии не используются никакие другие команды SQLCMD. К сожалению, SSMS в режиме SQLCMD всегда отказывается запускать сценарий, который ссылается на несуществующую переменную сценария.
  • Требуется использование SET CONTEXT_INFO, поскольку значения должны передаваться через границы пакета, что невозможно сделать с помощью переменных T-SQL. Для возврата к надежной обработке ошибок требуется несколько пакетов.
  • Приведенный выше код поддерживает только переменную сценария single , и из-за использования SET CONTEXT_INFO его длина ограничена 128 байтами = 64 символами Unicode; Впрочем, возможно использовать и другие обходные пути, например временные таблицы.
  • Эффективно превращая переменную сценария в обычную переменную T-SQL, вы не можете использовать это значение там, где T-SQL ожидает литералы, например, имя базы данных в операторе CREATE DATABASE.
  • Если переменная сценария не определена, в stderr выводится следующее предупреждение: Переменная сценария variableName не определена.
2 голосов
/ 19 сентября 2010

Возможно один из этих 3 вариантов:

  • через параметр командной строки v
  • с помощью команды :SETVAR, описанной далее в этой главе
  • byопределение переменной среды перед запуском SQLCMD.

Использование v option

В вашем скрипте: SELECT $(foo) FROM $(bar)
Использование: C:>SQLCMD i c:\someScript.sql -v foo="CustomerName" bar="Customer"

Использование setvar

:setvar foo CustomerName
:setvar bar Customer

С
http://www.sqlcmd.org/sqlcmd-scripting-variables/

0 голосов
/ 09 ноября 2018

Настройка контекста - оригинальная и интересная идея.Когда я прочитал проблемы, с которыми вы столкнулись при разборе VarBinary, я подумал, что временная таблица удовлетворит эту потребность.Немного поработав над этим (а потом вспомнив ваш комментарий о том, что SSMS ВСЕГДА выдает ошибки :( когда переменная сценария не определена), я получил эту версию, работающую. Мне вообще не нравятся решения Name-Value, но производительность на самом деле не такая, и проблема здесьон обеспечивает большую гибкость за счет платы котла, необходимой для определения и тестирования каждого необязательного параметра. Я тестировал на SQL2008R2 с использованием SSMS 17.

Set NoCount On;
If Object_Id('tempdb..#hold', 'U') Is Not Null Drop Table #hold;
Go
Create Table #hold(theKey NVARCHAR(128) Not Null, theValue NVARCHAR(128) Not Null);
Insert #hold(theKey, theValue) Values (N'Type', N'Full');
Select theValue From #hold Where theKey = N'Type'

:on error ignore
    Declare @theValue   NVARCHAR(128) = N'$(BType)';
    If @theValue <> N'$' + N'(BType)'   -- a value was passed in
        Update #hold Set theValue = @theValue Where theKey = N'Type';
Go
:on error exit

Select theValue From #hold Where theKey = N'Type'
Return;
-- sqlcmd -S myServer -E -i thePath\theScript.sql -v BType = "diff"
0 голосов
/ 27 ноября 2012

То, что для меня оказалось практичным удаленно, - это установить системную переменную среды в значение по умолчанию, а затем переопределить это значение, где это необходимо, с помощью SQLCMD -v.

0 голосов
/ 13 июня 2012

Если вы запускаете SQLCMD из командной строки Windows, добавьте «2> nul» в конце оператора SQLCMD.Это устранит жалобы SQLCMD в начале вывода.

Пример: sqlcmd -S DatabaseServer -E -d MyDatabase -i MyScript -v Variable1 = Value1 2> nul

0 голосов
/ 04 мая 2011

Получение переменной и присвоение переменной, если она проваливается через оператор SET, то она назначается.Улов будет обрабатывать значения по умолчанию.Это работает для меня на SQL Server 2005. Я заметил, что это всегда говорит о том, что это не удалось, когда я запускаю его в SQL Management Studio, хотя я думаю, что это работает.Когда я запускаю это через командную строку, используя sqlcmd, это работает без каких-либо сообщений об ошибках.

BEGIN TRY 
    DECLARE @bogusVar VARCHAR(64);
    SET @bogusVar = '' + $(envVar);
    PRINT 'Using values passed from sqlcmd';
END TRY
BEGIN CATCH
    PRINT 'Using default values for script'
    :setvar envVar 'DefaultValue'
END CATCH;
...