動的データベース作成スクリプトを作成しようとしています。
多くのステップがあり、このデータベースを頻繁に作成するため、スクリプトは次のようになります。
DECLARE @databaseName nvarchar(100) = 'DatabaseName'
EXEC('/*A lot of database creation code built off of @databaseName*/')
@databaseName
で作成したい1つのビューを除いて、これはすべてうまくいきます。
このビューを作成するために4つの異なる方法を試しましたが、成功しませんでした。
私が最初に考えたのは、データベースコンテキストを設定してから、1つのスクリプトでビューを作成することでした。残念ながら、これは機能しませんでした。これは、CREATE VIEW
がクエリブロックの最初のステートメントである必要があるためです( details )。
--Result: Error message, "'CREATE VIEW' must be the first statement in a query batch"
EXEC
('
USE [' + @databaseName + ']
CREATE VIEW
')
(1)回避するために、CREATE VIEW
がEXEC
の最初のコマンドになるようにコンテキストを個別に設定しようとしました。これはビューを作成しましたが、@databaseName
ではなく現在のコンテキスト内で作成しました。 USE
でEXEC
を呼び出すことの効果は、そのEXEC
ステートメントの終わりまでしか持続しないようです( details )。
--Result: The view is created in the currently active database rather than @databaseName
EXEC ('USE [' + @databaseName + ']')
EXEC ('CREATE VIEW')
次に、すべてを1つのスクリプトに戻そうとしましたが、新しいクエリブロックの最初のコマンドをCREATE VIEW
にするために、GO
コマンドを含めました。 GO
がEXEC
スクリプト内で許可されていないため、これは失敗しました( details )。
--Result: Error message, "Incorrect syntax near 'GO'"
EXEC
('
USE [' + @databaseName + ']
GO
CREATE VIEW
')
最後に、CREATE VIEW
コマンドの一部としてターゲットデータベースを指定しようとしました。この場合、CREATE VIEW
がデータベースの作成の一部としてデータベースを指定することを許可していないため、スクリプトは失敗しました( details )。
--Result: Error message, "'CREATE/ALTER VIEW' does not allow specifying the database name as a prefix to the object name"
EXEC ('CREATE VIEW [' + @databaseName + '].[dbo].[ViewName]')
助言がありますか?これは一般的な使用例であるはずですが、Googleは私を助けることができませんでした。
これを行うには、動的SQLステートメントを二重にネストします。
begin tran
declare @sql nvarchar(max) =
N'use [AdventureWorks2012];
exec (''create view Test as select * from sys.databases'')';
exec (@sql);
select * from AdventureWorks2012.sys.views
where name = 'Test'
rollback tran
二重ネストの代わりに、別のアプローチは、動的SQLを実行することだけを目的とするストアドプロシージャを作成することです。
CREATE PROCEDURE [dbo].[util_CreateViewWithDynamicSQL]
@sql nvarchar(max)
AS
BEGIN
SET NOCOUNT ON;
EXECUTE (@sql)
END
上記のストアドプロシージャは再利用できます。ビューを作成する必要があるときはいつでも、ストアドプロシージャを呼び出して、動的SQLを渡すだけです。
EXECUTE util_CreateViewWithDynamicSQL 'create view Test as select * from sys.databases'
動的SQLは十分に混乱し、二重ネストを追加するとさらに複雑になるため、このアプローチを好みます。