考虑以下代码:
DECLARE @db sysname;
DECLARE @filename varchar(260);
DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY
FOR
SELECT d.name
FROM sys.databases d;
OPEN cur;
FETCH NEXT FROM cur INTO @db
WHILE @@FETCH_STATUS = 0
BEGIN
SET @filename = 'C:\temp\create_database_' + @db + '.txt';
:setvar c @filename
:out $(c)
PRINT $(c);
FETCH NEXT FROM cur INTO @db
END
CLOSE cur;
DEALLOCATE cur;
我期望在 中创建多个文件C:\temp
,每个数据库一个,但没有创建任何文件,SQL Server 也没有报告错误。
我尝试使用 SQLCMD 模式在 SSMS 中运行它,我也尝试从 sqlcmd.exe 运行它
以
SQLCMD
这种方式使用对我来说是新的,让我在互联网上搜索示例。在研究了SQL Server Management Studio: Hacking SQLCMD Mode中的信息并思考了
SQLCMD
变量的局限性之后,我对您的问题采取了稍微不同的方法。我的解决方案可能无法完全回答您关于为什么:OUT
无法按预期工作的问题,但无论如何我都会提供它。我的完整脚本在我的答案的末尾,但这里有一些带有解释的片段。
我首先将输出重定向到我的本地用户临时目录
现在,我们调用游标来读取数据库列表。我正在使用该
PRINT
命令生成操作系统echo
命令来创建单个数据库创建文件。整个游标执行的输出被写入我的用户临时文件夹中的 DBScript.txt 文件。执行上述操作后,DBScript.txt 文件现在包含这些命令(每个命令开头的双键将告知
SQLCMD
将这些命令作为操作系统命令执行):现在,回到原始脚本,我们将
SQLCMD
输出恢复到标准输出并执行 DBScript.txt 中的命令当我查看我的 C:\Temp 目录时,我现在有以下单个文件:
这是完整的脚本:
使用 sqlcmd 模式执行此操作的方法是编写一个脚本,该脚本编写一个脚本,然后执行这些脚本,所以这是一种稍微不同的思考方式,有点像 Inception 或 Borges,梦中的梦:
好的,我想我从这里得到答案
我想在这里引用它
确实如此,换句话说,在运行 t-sql 之前首先评估您的
:setvar
和:out
,这也解释了为什么下面显示的我的简单 t-sql 会给出错误消息你看,错误信息有“无法将输出重定向到@filename”和“c:\windows\system32\@filename”,这是因为,当评估:out时,它不知道@filename的值,所以它只是将文字字符串
@filename
用于 :out 目的,这将自动默认为“c:\windows\system32\”的默认路径