我正在編寫一個腳本,該腳本在執行時將在給定DB列表中刪除任何表,如果DB名稱+表名稱組合不存在一個名爲CleanUpTableList的表。所有數據庫駐留在同一臺服務器上。我正在使用SQL Server 2014.嘗試使用遊標循環更改數據庫,但數據庫不會更改
我想通過創建一個外部遊標循環來循環訪問數據庫名稱列表和一個內部遊標循環,該遊標循環在給定數據庫中引入表名稱列表沒有在CleanUpTableList中找到並刪除這些表。但是,似乎外層循環無法更改數據庫。該腳本只能訪問X次啓動數據庫的相關表,其中X是外部遊標中的許多數據庫名稱條目。因此,舉例來說,如果我開始在數據庫1,我在我的外光標有三個數據庫名稱條目,而不是得到:
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
...這是不是真的是我想要的,所以我假設在外部循環中有什麼不妥。我知道通常的數據庫更改命令是
USE Database1;
GO
但我無法弄清楚如何用EXEC()做到這一點。它一直告訴我在GO附近有一個語法錯誤,我假設因爲GO不能和'USE Database1;'在同一行上,並且我不知道如何在使用EXEC()時創建新行。我試着用
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
任何建議表示讚賞。
我正在嘗試僅爲服務器上選定的幾個數據庫執行此操作。只涉及明確指定的數據庫是非常重要的,因爲服務器上的其他數據庫在CleanUpTableList中沒有任何條目,因此通過此腳本放置它們會導致意外的表刪除。 我假設我可以使用語句的db_id()部分顯式標識這些數據庫?像 'EXECUTE master.sys.sp_MSforeachdb'USE [?];如果db_id()IN(1,2,3)返回; drop table dbo.sometable' –
針對您的特定場景查看已更新 – TheGameiswar