次のコードを検討してください。
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
にデータベースごとに1つずつ、複数のファイルが作成されることを期待していますが、何も作成されず、SQL Serverからエラーが報告されません。
SQLCMDモードを使用してSSMSでこれを実行しようとしました。また、sqlcmd.exeから実行しようとしました
Sqlcmdモードでこれを行う方法は、スクリプトをスクリプト化するスクリプトをスクリプト化してから、それらのスクリプトを実行することです。これは、InceptionやBorgesのような、夢の中の夢という、少し異なる考え方です。
-- Script a script which scripts a script
SET NOCOUNT ON
GO
:out d:\temp\temp.sql
GO
SELECT REPLACE( ':out d:\temp\@database.sql
-- Do some work here
PRINT ''select ''''@database''''''
GO
-- Return stdout to normal
:out STDOUT
GO
', '@database', name ) AS [--sql]
--C:\temp\create_database_' + name + '.txt'
FROM sys.databases
GO
-- Return stdout to normal
:out STDOUT
GO
-- Now execute your scripted file
:r d:\temp\temp.sql
GO
-- Create another script which executes all thoses scripts ...
:out d:\temp\temp2.sql
GO
SELECT REPLACE( ':r d:\temp\@database.sql
GO
', '@database', name ) AS [--sql]
FROM sys.databases
GO
-- Return stdout to normal
:out STDOUT
GO
-- Execute your script of scripts?
:r d:\temp\temp2.sql
GO
このようにSQLCMD
を使用するのは初めてのことであり、インターネットで例を探すようになりました。
SQL Server Management Studio:Hacking SQLCMD Mode の情報を調査し、SQLCMD
変数の制限について考えた後、問題に対して少し異なるアプローチをとりました。私の解決策は、なぜ:OUT
は期待どおりに動作していませんが、とにかく提供します。
私の完全なスクリプトは私の答えの最後にありますが、ここに説明付きの断片があります。
出力をローカルユーザーの一時ディレクトリにリダイレクトすることから始めました
set nocount on
--Redirect output to user temp folder
--On my computer, this was 'C:\Users\uswsh\AppData\Local\Temp'
:OUT $(TEMP)\DBScript.sql
次に、カーソルを呼び出してデータベースのリストを読み取ります。 PRINT
コマンドを使用してオペレーティングシステムのecho
コマンドを生成し、個々のデータベース作成ファイルを作成しています。カーソル実行全体の出力は、ユーザーの一時フォルダーのDBScript.txtファイルに書き込まれます。
--Declare variables used by cursor
DECLARE @db sysname;
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
PRINT '!!echo nul > C:\temp\create_database_' + @db + '.txt';
FETCH NEXT FROM cur INTO @db
END
CLOSE cur;
DEALLOCATE cur;
go
上記を実行すると、DBScript.txtファイルに次のコマンドが含まれるようになります(各コマンドの先頭にあるダブルバンは、これらをオペレーティングシステムコマンドとして実行するようにSQLCMD
に指示します)。
!!echo nul > C:\temp\create_database_master.txt
!!echo nul > C:\temp\create_database_tempdb.txt
!!echo nul > C:\temp\create_database_model.txt
!!echo nul > C:\temp\create_database_msdb.txt
!!echo nul > C:\temp\create_database_Test.txt
!!echo nul > C:\temp\create_database_AdventureWorks2014.txt
次に、元のスクリプトに戻り、SQLCMD
の出力をstdoutに戻し、DBScript.txtのコマンドを実行します。
--Revert output to stdout
:OUT stdout
--Execute the script you just created that has the !!echo commands
:r $(TEMP)\DBScript.sql
GO
C:\ Tempディレクトリを見ると、次の個別ファイルがあります。
完全なスクリプトは次のとおりです。
set nocount on
--Redirect output to user temp folder
--On my computer, this was 'C:\Users\uswsh\AppData\Local\Temp'
:OUT $(TEMP)\DBScript.sql
--Declare variables used by cursor
DECLARE @db sysname;
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
PRINT '!!echo nul > C:\temp\create_database_' + @db + '.txt';
FETCH NEXT FROM cur INTO @db
END
CLOSE cur;
DEALLOCATE cur;
go
--Revert output to stdout
:OUT stdout
--Execute the script you just created that has the !!echo commands
:r $(TEMP)\DBScript.sql
GO
わかりました、私は here から答えを得ると思います
ここで引用したい
Sqlcmd変数とt-sql変数は、sqlcmdスクリプトの実行の異なる異なるステップで個別に評価されるため、これは不可能です。
これは真実です。別のWordでは、t-sqlが実行される前に:setvar
と:out
が最初に評価されます。また、以下に示す単純なt-sqlがエラーメッセージを表示する理由も説明しています
DECLARE @filename varchar(260)='c:\temp\test.txt';
:setvar c @filename
:out $(c)
PRINT $(c);
ご覧のとおり、エラーメッセージには「出力を@filenameにリダイレクトできません」と「c:\ windows\system32\@filename」が含まれています。これは、:outが評価されるときに@filenameの値がわからないためです。 :outの目的でリテラル文字列@filename
を使用します。これにより、デフォルトで「c:\ windows\system32 \」のデフォルトパスに自動的に設定されます