2015-12-11 34 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數據庫名稱」被髮送,然後被遺忘。 –

+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

我會在第二個動態@Sql2變量的while語句中執行此操作。在實際使用EXEC語句之前,可以使用PRINT命令而不是EXEC來查看語句的外觀。如果需要,您可以使用EXEC的結果集到另一個變量表中並進行嵌套。我會發布更新。 – Mike

相關問題