我有一个脚本文件,例如TEST.SQL。我想用sqlcmd模式中的另一个脚本调用caller.sql来调用它:r test.sql。这工作正常,但我想在test.sql中使用脚本变量。当我从caller.sql调用test.sql时,我可以设置脚本变量,一切都很好。但是,我想使用脚本值的默认值,以便如果调用者没有设置变量,或者我直接运行test.sql(而不是来自caller.sql),那么脚本变量默认为设置值。 / p>
我尝试过诸如
之类的事情begin try
select '$(grip)'
select 'grip value was found'
end try
begin catch
select 'grip value was missing'
end catch
但我收到以下消息: 发生了致命的脚本错误。 未定义可变夹点。
我在test.sql中需要什么才能处理调用者传递的“抓取”?我正在使用MS SQL 2005
答案 0 :(得分:4)
有一个有限的解决方法(我只在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
注意:
:on error exit
切换到强大的错误处理。
因此,你必须在脚本的其余部分进行自己的错误处理 - 这是非常重要的;见SQL Server - stop or break execution of a SQL script :on error ignore
以使脚本在常规模式下在SSMS中工作,请确保在使用sqlcmd.exe调用该脚本时未指定-b选项,因为如果引用的脚本变量不存在,则阻止整个脚本运行。: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 + ']';
注意:
SET CONTEXT_INFO
,因为需要跨批处理边界传递值,这不能通过T-SQL变量完成。需要多个批次才能切换回强大的错误处理。SET CONTEXT_INFO
,其长度限制为128个字节= 64个Unicode字符;但是可以想象使用其他解决方法,例如临时表。CREATE DATABASE
语句中的数据库名称。 答案 1 :(得分:2)
也许这三个选项中的一个:
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
答案 2 :(得分:0)
检索变量并分配给变量,如果它通过SET语句,则分配给它。 catch将处理默认值。这适用于我在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;
答案 3 :(得分:0)
如果您从Windows Command promt运行SQLCMD,请在SQLCMD语句末尾添加“2&gt; nul”。这将消除输出开始时的SQLCMD投诉。
示例:sqlcmd -S DatabaseServer -E -d MyDatabase -i MyScript -v Variable1 = Value1 2&gt; NUL
答案 4 :(得分:0)
对我来说远程实用的结果是将系统环境变量设置为默认值,然后使用SQLCMD -v覆盖该值。
答案 5 :(得分:0)
设置上下文是一个原始而有趣的想法。当我读到您在解析VarBinary时遇到的问题时,我认为也许临时表会满足需要。 经过一番努力之后(然后记得您的评论SSMS总是会出错:(当脚本变量未定义时),我得到了这个版本。我通常不喜欢Name-Value解决方案,但是性能并不是真正的问题,因此在这里发布它以定义和测试每个可选参数所需的样板为代价,提供了极大的灵活性。 我使用SSMS 17在SQL2008R2上进行了测试。
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"