13

test.sqlなどのスクリプトファイルがあります。:r test.sqlを使用して、sqlcmdモードでcaller.sqlなどの別のスクリプトからこれを呼び出したいと思います。これは正常に機能しますが、test.sqlでスクリプト変数を使用したいと思います。caller.sqlからtest.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には何が必要ですか?MSSQL2005を使用しています

4

6 に答える 6

6

There is a LIMITED workaround (I've only tested it on SS2008R2):

SIMPLE version - if you're willing to live without :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

Note:

  • Since T-SQL variables don't work across batches, you cannot start another batch (with GO) and so cannot switch to robust error handling with :on error exit. Therefore, you have to do your own error handling in the remainder of the script - which is non-trivial; see SQL Server - stop or break execution of a SQL script
  • If you remove the :on error ignore in order to make the script work in SSMS in regular mode, be sure that when you invoke that script with sqlcmd.exe that you do NOT specify the -b option, as that will prevent the entire script from running if the referenced scripting variable does not exist.
  • By effectively turning the scripting variable into a regular T-SQL variable, you cannot use the value in places where T-SQL expects literals, such as the name of a database in a CREATE DATABASE statement.
  • If the scripting variable is not defined, the following warning is printed to stderr: 'variableName' scripting variable not defined.

ROBUST version - much more cumbersome, but supports :on error exit, which is advisable:

-- 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 + ']';

Note:

  • The above works both when invoked from sqlcmd.exe and in SSMS in regular mode - assuming you use no other SQLCMD commands in the script. Sadly, SSMS in SQLCMD mode always refuses to run a script that references a non-existent scripting variable.
  • The use of SET CONTEXT_INFO is required, because values need to be passed across batch boundaries, which can't be done with T-SQL variables. Multiple batches are needed to switch back to robust error handling.
  • The code above only supports a single scripting variable, and, due to use of SET CONTEXT_INFO, its length is limited to 128 bytes = 64 Unicode characters; it's conceivable to use other workarounds, though, such as temporary tables.
  • By effectively turning the scripting variable into a regular T-SQL variable, you cannot use the value in places where T-SQL expects literals, such as the name of a database in a CREATE DATABASE statement.
  • If the scripting variable is not defined, the following warning is printed to stderr: 'variableName' scripting variable not defined.
于 2011-12-13T06:38:06.587 に答える
2

おそらく、次の 3 つのオプションのいずれかです。

  • コマンドラインオプション経由v
  • :SETVARこの章で後述するコマンドを使用して
  • を実行する前に環境変数を定義しますSQLCMD

vオプションの使用

スクリプト内: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/から

于 2010-09-19T19:03:58.027 に答える
0

WindowsコマンドpromtからSQLCMDを実行している場合は、SQLCMDステートメントの最後に「2>nul」を追加します。これにより、出力の最初のSQLCMDの苦情がなくなります。

例:sqlcmd -S DatabaseServer -E -d MyDatabase -i MyScript -v Variable1 = Value1 2> nul

于 2012-06-13T17:07:03.613 に答える
0

変数を取得して変数に代入し、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;
于 2011-05-03T20:49:45.097 に答える
0

私にとってリモートで実用的だったのは、システム環境変数をデフォルトに設定し、必要に応じてその値を SQLCMD -v でオーバーライドすることです。

于 2012-11-27T00:08:40.507 に答える