2016-09-20 1 views
1

Ich schreibe ein Skript, das bei Ausführung alle Tabellen in einer Liste der angegebenen DBs löscht, wenn das Kombinationsfeld DB-Name + Tabellenname nicht existiert eine Tabelle namens CleanUpTableList. Alle DBs befinden sich auf demselben Server. Ich benutze SQL Server 2014.Der Versuch, Datenbanken mithilfe der Cursorschleife zu ändern, aber die Datenbank ändert sich nicht.

Ich versuche, dies zu tun, indem Sie eine äußere Cursor-Schleife, die durch die Liste der DB-Namen und eine innere Cursor-Schleife, die eine Liste der Tabellennamen innerhalb der angegebenen Datenbank zieht, die sind nicht in CleanUpTableList gefunden und löscht diese Tabellen. Es scheint jedoch, dass die äußere Schleife die Datenbanken nicht ändern kann. Das Skript greift nur X-mal auf die relevanten Tabellen der Startdatenbank zu, wobei X jedoch viele Einträge des Datenbanknamens im äußeren Cursor enthält. So zum Beispiel, wenn ich starten in Database1, und ich habe drei Datenbanknamen Einträge in meinem äußeren Cursor, anstatt sich:

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

ich:

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

... Welche ist nicht wirklich, was ich will, also nehme ich an, dass etwas in der äußeren Schleife nicht stimmt. Ich weiß, dass der üblicher DB Änderungsbefehl

USE Database1; 
GO 

Aber ich war nicht in der Lage, herauszufinden, wie man das mit exec(). Es hat mir gesagt, dass es einen Syntaxfehler in der Nähe von GO gab, ich nehme an, weil GO nicht in der gleichen Zeile wie 'USE Database1;' sein kann, und ich weiß nicht, wie man eine neue Zeile mit EXEC() erstellt. Ich habe versucht,

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

und

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

aber diese auch wieder einen Syntaxfehler verwendet wird. Hier

ist der entsprechende Code:

DB/Tabellenerstellung Script:

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') 

Clean Up Script:

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 

Irgendwelche Vorschläge geschätzt werden.

Antwort

2

aus dem Code, ich verstanden, dass Sie in allen Datenbanken gleiche Operation zu tun versuchen, kann diese durch sp_msforeachdb ..

--alle Datenbanken

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

--run nur wenige umgesetzt werden Datenbanken ..

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

Sie könnten auch Aaron Bertrand ‚s Umschreiben von Sp_msforeachDB verwendet werden, die auch mit einigen Einschränkungen von Sp_msforeachdb umgehen können: Making a more reliable and flexible sp_MSforeachdb

+0

Ich versuche, dies nur für einige wenige Datenbanken auf dem Server zu tun.Es ist sehr wichtig, dass nur die explizit angegebenen Datenbanken betroffen sind, da andere Datenbanken auf dem Server keine Einträge in CleanUpTableList enthalten und somit das Durchlaufen dieses Skripts zu einem unbeabsichtigten Löschen von Tabellen führen würde. Ich nehme an, dass ich diese Datenbanken mithilfe des Abschnitts db_id() der Anweisung explizit identifizieren konnte? Wie 'EXECUTE master.sys.sp_MSforeachdb 'USE [?]; if db_id() IN (1,2,3) zurückgeben; Drop-Tabelle dbo.someable '' –

+0

Siehe aktualisiert für Ihr spezifisches Szenario – TheGameiswar

0

Anstatt zu versuchen, die Anweisung Use database auszuführen, versuchen Sie, die database.dbo.tablename in der drop-Anweisung vollständig zu qualifizieren. Sie haben alle Datenbank- und Tabellennamen.

Verwandte Themen