web-dev-qa-db-ja.com

動的SQLを使用してビューを作成する

動的データベース作成スクリプトを作成しようとしています。

多くのステップがあり、このデータベースを頻繁に作成するため、スクリプトは次のようになります。

 DECLARE @databaseName nvarchar(100) = 'DatabaseName'
 EXEC('/*A lot of database creation code built off of @databaseName*/')

@databaseNameで作成したい1つのビューを除いて、これはすべてうまくいきます。

このビューを作成するために4つの異なる方法を試しましたが、成功しませんでした。

  1. 私が最初に考えたのは、データベースコンテキストを設定してから、1つのスクリプトでビューを作成することでした。残念ながら、これは機能しませんでした。これは、CREATE VIEWがクエリブロックの最初のステートメントである必要があるためです( details )。

    --Result: Error message, "'CREATE VIEW' must be the first statement in a query batch"
    EXEC 
    ('
        USE [' + @databaseName + ']
        CREATE VIEW
    ')
    
  2. (1)回避するために、CREATE VIEWEXECの最初のコマンドになるようにコンテキストを個別に設定しようとしました。これはビューを作成しましたが、@databaseNameではなく現在のコンテキスト内で作成しました。 USEEXECを呼び出すことの効果は、そのEXECステートメントの終わりまでしか持続しないようです( details )。

    --Result: The view is created in the currently active database rather than @databaseName
    EXEC ('USE [' + @databaseName + ']')
    EXEC ('CREATE VIEW')
    
  3. 次に、すべてを1つのスクリプトに戻そうとしましたが、新しいクエリブロックの最初のコマンドをCREATE VIEWにするために、GOコマンドを含めました。 GOEXECスクリプト内で許可されていないため、これは失敗しました( details )。

    --Result: Error message, "Incorrect syntax near 'GO'"
    EXEC 
    ('
        USE [' + @databaseName + ']
        GO
        CREATE VIEW
    ')
    
  4. 最後に、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は私を助けることができませんでした。

8
Mark Rucker

これを行うには、動的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
13
DaveShaw

二重ネストの代わりに、別のアプローチは、動的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は十分に混乱し、二重ネストを追加するとさらに複雑になるため、このアプローチを好みます。

1
Dave