sql-server - sql脚本变量默认值

标签 sql-server sql-server-2005 sqlcmd

我有一个脚本文件,例如测试.sql。我想从另一个脚本调用它,比如 caller.sql,在 sqlcmd 模式下使用 :r test.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 中需要什么,以便它可以处理调用者传递或不传递的“grip”?我正在使用 MS SQL 2005

最佳答案

有一个有限的解决方法(我只在 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 - stop or break execution of a SQL script
  • 如果您删除 :on errorignore 以使脚本在 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 命令。遗憾的是,SQLCMD 模式下的 SSMS 始终拒绝运行引用不存在的脚本变量的脚本。
  • 需要使用SET CONTEXT_INFO,因为值需要跨批处理边界传递,而 T-SQL 变量无法做到这一点。需要多个批处理才能切换回强大的错误处理。
  • 上面的代码仅支持单个脚本变量,并且由于使用SET CONTEXT_INFO,其长度限制为128字节= 64个Unicode字符;不过,可以想象使用其他解决方法,例如临时表。
  • 通过有效地将脚本变量转换为常规 T-SQL 变量,您无法在 T-SQL 需要文字的地方使用该值,例如 CREATE DATABASE 语句中的数据库名称。
  • 如果未定义脚本变量,则会将以下警告打印到 stderr: “variableName”脚本变量未定义。

关于sql-server - sql脚本变量默认值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3747006/

相关文章:

sql-server - SQL Server 授权/安全问题

c# - SQL Server 2005 SQL 身份验证连接字符串

sql-server - 如何将 sqlcmd 输出设置为批处理变量?

java - 使用Java读取SQLCMD的输出文件

sql-server - 无法让经典 ASP 应用程序连接到数据库

sql-server - SQL Server 和 REAL 数据类型的舍入问题

sql-server-2005 - Management Studio 中 "Connect to Server"的键盘快捷键

sql - 有没有办法从 SQL Server 中的 SQL 查询生成数据库脚本?

sql - 将 nvarchar 值 'CIS100 ' 转换为数据类型 int 时转换失败

xml - T-SQL 2005 : Passing Null Values through XML datatype