2015-12-11 13 views
6

異なるデータベースでプロシージャを作成しようとしています。私はデータベースの名前を知っているはずがありません。私は動的な方法でデータベースの名前を取得するための最初のものと、プロシージャを作成/変更するための入れ子のカーソルを作成しようとしました。私はプロシージャを作成するためにEXISTSを使用し、それらを変更するためにEXISTSは使用しませんでした。しかし、何らかの形でデータベースは「マスター」に固執し、それは他のものにループしません。私は内側のネストカーソルに問題があることを知っていますが、これが何であるか分かりません。 は、ここに私のコードです:カーソルを使用して異なるデータベース内でプロシージャを作成する方法

DECLARE GetDatabases CURSOR 
FOR 
    SELECT name 
    FROM sys.databases 
OPEN GetDatabases 
DECLARE @DBName NVARCHAR(100) 
DECLARE @cmd NVARCHAR(Max) 

FETCH NEXT 
FROM GetDatabases 
INTO @DBName 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    set @cmd='use ' + @DBName 
    print @cmd 
    exec sp_executesql @cmd 
    FETCH NEXT 
    FROM GetDatabases 
    INTO @DBName 
     DECLARE AutoProc CURSOR 
     FOR 
      SELECT TABLE_SCHEMA,TABLE_NAME 
      FROM INFORMATION_SCHEMA.TABLES 
      WHERE TABLE_TYPE='BASE TABLE' 
     OPEN AutoProc 
     DECLARE @TableName NVARCHAR(100) 
     DECLARE @TableSchema NVARCHAR(100) 

     FETCH NEXT 
     FROM AutoProc 
     INTO @TableSchema,@TableName 

     WHILE @@FETCH_STATUS = 0 
     BEGIN 
     IF EXISTS(SELECT * FROM sys.objects WHERE type = 'P' AND OBJECT_ID = OBJECT_ID('@TableName')) 
      exec('ALTER PROCEDURE USP_SELECT_'[email protected]+' AS 
      BEGIN 
      SELECT * 
      FROM '[email protected]+'.'[email protected]+' 
      END ;') 
     IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND OBJECT_ID = OBJECT_ID('@TableName')) 
      exec('CREATE PROCEDURE USP_SELECT_'[email protected]+' AS 
      BEGIN 
      SELECT * 
      FROM '[email protected]+'.'[email protected]+' 
      END ;') 
      FETCH NEXT 
      FROM AutoProc 
      INTO @TableSchema,@TableName 
     END 
     CLOSE AutoProc 
     DEALLOCATE AutoProc 
END 
CLOSE GetDatabases 
DEALLOCATE GetDatabases 

PS:私はそれがすべてのSQLサーバのユーザのデータベースに適用することができるように「一般的」な手順を記述しようとしているので、私は、データベースの名前を知ることになっていませんよ、私だけではない。

P.S2:ネスティングカーソルを使用しましたが、その悲惨なパフォーマンスのために、私は他の方法にも感謝します!

乾杯!

+0

exec sp_executesql cmdを実行する必要がある行は、そのcmdの実行に対して残りのセッションでは保持されません。そのため、あなたはまだマスターになっています。つまり、「USE dbname」が送信されてから忘れられています。 –

+0

それはデータベース名を知ることが許されていないというのはちょっと変わったようです。もしあなたがマスターにアクセスしてそのコードを実行できるのであれば、それは暗黙のうちに.... :) –

+0

@NickPfitzner私は 'use + DBName'を試みましたが、うまくいきませんでした。何を指示してるんですか? –

答えて

1

カーソルを使用する代わりに、whileステートメントを使用し、一時変数テーブルを反復処理してみてください。

DECLARE @Databases TABLE 
(
    ID int IDENTITY(1,1), 
    DatabaseName varchar(100) 
) 


INSERT INTO @Databases 
SELECT name FROM sys.databases 

DECLARE @Idx int = (select count(*) from @Databases) 

WHILE(@Idx > 0) 
    BEGIN 

    DECLARE @CurrentDatabase varchar(100) = (select DatabaseName from @Databases where @Idx = ID) 

    DECLARE @SchemaData TABLE 
    (
    ID int IDENTITY(1,1), 
    Table_Schema varchar(20), 
    Table_Name varchar(255) 
    ) 

    DECLARE @Sql varchar(max) = 'SELECT [TABLE_SCHEMA],[TABLE_NAME] FROM [' + @CurrentDatabase + '].[INFORMATION_SCHEMA].[TABLES]'  

    INSERT INTO @SchemaData 
     EXEC (@Sql) 

    DECLARE @SchemaIdx int = (select count(*) from @SchemaData) 

    WHILE(@SchemaIdx > 0) 
     BEGIN 

     DECLARE @CurrentSchema varchar(20), @CurrentTable varchar(255) 

     SELECT @CurrentSchema = Table_Schema, @CurrentTable = Table_Name from  @SchemaData where ID = @SchemaIdx 

     DECLARE @Sql2 varchar(max) = 
      'IF EXISTS(SELECT * FROM sys.objects WHERE type = ''P'' AND OBJECT_ID = OBJECT_ID(' + @CurrentTable + ')) 
      exec(''ALTER PROCEDURE USP_SELECT_'+ @CurrentTable + ' AS 
      BEGIN 
      SELECT * 
      FROM '+ @CurrentSchema + '.'+ @CurrentTable + ' 
      END ;'')' 

     PRINT @Sql2 

     SET @SchemaIdx = @SchemaIdx - 1; 
    END 



    SET @Idx = @Idx - 1; 
END 
+0

すごくうまくいった!感謝万円! –

+0

しかし、どこに手続きを追加すればよいですか? –

+0

2番目の動的@ Sql2変数と同じwhile文でこれを実行します。 EXECの代わりにPRINTコマンドを使用すると、実際にEXECステートメントを使用する前にそのステートメントの外観を確認できます。 EXECの結果セットを別の変数テーブルに使用し、必要に応じてネストされたwhileを実行できます。私は更新を投稿します。 – Mike

関連する問題