2016-09-20 13 views
1

実行時にDB名+テーブル名のコンボが存在しない場合、指定されたDBのリスト内のテーブルを削除しますCleanUpTableListという名前のテーブルすべてのDBは同じサーバー上にあります。私はSQL Server 2014を使用しています。カーソルループを使用してデータベースを変更しようとしましたが、データベースは変更されません

DB名のリストを循環する外部カーソルループと、指定されたデータベース内のテーブル名のリストをプルインする内部カーソルループを作成することで、これを実行しようとしています。 CleanUpTableListに見つからず、それらのテーブルを削除します。しかし、外部ループがデータベースを変更できないようです。スクリプトは開始データベースの関連するテーブルにX回だけアクセスしますが、Xは多くのデータベース名のエントリが外部カーソルにあります。私はDatabase1をして開始し、私は私の外側のカーソルに3つのデータベース名のエントリを持って、代わりに取得するのであれば、例えば、:

DROP TABLE Database1..TableB 
DROP TABLE Database1..TableC 
DROP TABLE Database2..TableE 
DROP TABLE Database2..TableF 
DROP TABLE Database3..TableH 
DROP TABLE Database3..TableI 

私が取得:

DROP TABLE Database1..TableB 
DROP TABLE Database1..TableC 
DROP TABLE Database1..TableB 
DROP TABLE Database1..TableC 
DROP TABLE Database1..TableB 
DROP TABLE Database1..TableC 

...されていません本当に私が欲しいものなので、外側のループで何かが間違っていると仮定しています。私は通常のDB変更コマンドがあることを知っています

USE Database1; 
GO 

しかし、私はEXEC()でそれを行う方法を理解することができませんでした。それは、GOが「USE Database1;」と同じ行にあることができないため、EXEC()を使用するときに新しい行を作る方法がわからないために、GOの近くで構文エラーが発生していると私は思い出しました。私は

SET @ChangeDB = 'USE ' + @DatabaseName + ';' 
EXEC(@ChangeDB + CHAR(13) + 'GO') 

SET @ChangeDB ='USE ' + @DatabaseName + ';' +CHAR(13) + 'GO' 
EXEC(@ChangeDB) 

を使用してみましたが、これらはまた、構文エラーが返されました。

DB /表作成スクリプト:

CREATE DATABASE Database1; 
CREATE DATABASE Database2; 
CREATE DATABASE Database3; 
CREATE DATABASE Database4; 

CREATE TABLE Database1.dbo.TableA (Column1 INT, Column2 INT); 
CREATE TABLE Database1.dbo.TableB (Column1 INT, Column2 INT); 
CREATE TABLE Database1.dbo.TableC (Column1 INT, Column2 INT); 

CREATE TABLE Database2.dbo.TableD (Column1 INT, Column2 INT); 
CREATE TABLE Database2.dbo.TableE (Column1 INT, Column2 INT); 
CREATE TABLE Database2.dbo.TableF (Column1 INT, Column2 INT); 

CREATE TABLE Database3.dbo.TableG (Column1 INT, Column2 INT); 
CREATE TABLE Database3.dbo.TableH (Column1 INT, Column2 INT); 
CREATE TABLE Database3.dbo.TableI (Column1 INT, Column2 INT); 

CREATE TABLE Database4.dbo.CleanUpTableList (DBName VARCHAR(20), TableName VARCHAR(20)); 

INSERT INTO Database4..CleanUpTableList VALUES ('Database1','TableA') 
INSERT INTO Database4..CleanUpTableList VALUES ('Database2','TableD') 
INSERT INTO Database4..CleanUpTableList VALUES ('Database3', 'TableG') 

クリーンアップスクリプト:

DECLARE @fetch_database_cursor INT 
DECLARE @DatabaseName VARCHAR(50) 

DECLARE DatabaseList CURSOR FOR 

    select name from sys.databases 
    where 
    name IN ('Database1','Database2', 'Database3' 
      ) 

OPEN DatabaseList 
FETCH NEXT FROM DatabaseList INTO @DatabaseName 

/* Keep track of the outer loop FETCH_STATUS in a local variable */ 

SET @fetch_database_cursor = @@FETCH_STATUS 

/* Use outer loop FETCH_STATUS local variable as condition for outer WHILE loop */ 

WHILE @fetch_database_cursor = 0 
BEGIN 

    DECLARE @ChangeDB VARCHAR(2500) 
    DECLARE @TableName VARCHAR(50) 
    DECLARE @ExecuteSQL VARCHAR(2500) 
    DECLARE @fetch_table_cursor INT 

    /* Change DB here */ 

    SET @ChangeDB = 'USE ' + @DatabaseName 
    EXEC(@ChangeDB) 

    /* Declare inner cursor */ 

    DECLARE TableList CURSOR FOR 
     select table_name 
     from information_schema.tables 
     WHERE TABLE_TYPE = 'BASE TABLE' 
     AND table_name NOT IN (
      SELECT TableName 
      FROM Database4..CleanUpTableList 
      WHERE DBName = @DatabaseName 
      ) 
     ORDER BY table_name 

    OPEN TableList 
    FETCH NEXT FROM TableList INTO @TableName 

    /* Store inner cursor fetch_status in local variable */ 

    SET @fetch_table_cursor = @@FETCH_STATUS 

    /* Use inner cursor fetch_status local variable as condition for inner WHILE loop */ 

    WHILE @fetch_table_cursor = 0 

     BEGIN 
      SET @ExecuteSQL = 'DROP TABLE ' [email protected] 
      EXEC(@ExecuteSQL) 
      SELECT @Tablename, 'Has Been Successfully Dropped' 
      FETCH NEXT FROM TableList INTO @TableName 
      SET @[email protected]@FETCH_STATUS 

     END 

    /* Close and deallocate inner cursor */ 

    CLOSE TableList 
    DEALLOCATE TableList 

    FETCH NEXT FROM DatabaseList INTO @DatabaseName 
    SET @fetch_database_cursor = @@FETCH_STATUS 
END 

/* Close and deallocate outer cursor */ 

CLOSE DatabaseList 
DEALLOCATE DatabaseList 

任意の提案が高く評価されている。ここ

は、関連するコードです。コードから

答えて

2

、私はあなたがsp_msforeachdbにより実現することができるすべてのデータベースで同じ操作を、やろうとしていることを理解..

わずか数--allデータベース

EXECUTE master.sys.sp_MSforeachdb 
'USE [?]; 
if db_id()<=4 return; 
drop table dbo.sometable' 

--runデータベース..あなたもまたSp_msforeachdbのいくつかの制限に対処することができますSp_msforeachDBのAaron Bertrandの書き換え使用することができます

EXECUTE master.sys.sp_MSforeachdb 
'USE [?]; 
if db_name(db_id()) in (''master'',''tempdb'') --your dbnames 
Begin 
select db_name() --your query 
end' 

Making a more reliable and flexible sp_MSforeachdb

+0

これは、サーバー上の少数のデータベースでのみ実行しようとしています。サーバー上の他のデータベースにはCleanUpTableListのエントリがないため、このスクリプトを実行すると意図しないテーブルの削除が発生するため、明示的に指定されたデータベースのみが関係することは非常に重要です。 ステートメントのdb_id()セクションを使用してこれらのデータベースを明示的に識別できると思いますか?同様に 'EXECUTE master.sys.sp_MSforeachdb 'USE [?]; db_id()IN(1,2,3)が返された場合、ドロップテーブルdbo.sometable '' –

+0

あなたの特定のシナリオの更新を参照 – TheGameiswar

0

Useデータベースステートメントを実行する代わりに、dropステートメントのdatabase.dbo.tablenameを完全修飾してみてください。すべてのデータベースとテーブル名があります。

関連する問題