2015-12-11 29 views
6

Tak więc próbuję tworzyć procedury w różnych bazach danych. Nie powinienem znać nazwy baz danych. Próbowałem tworzyć kursory zagnieżdżające, pierwsze, aby uzyskać nazwy baz danych w dynamiczny sposób, a drugie do tworzenia/zmiany procedur; Użyłem EXISTS do stworzenia procedur, a NOT EXISTS do ich zmiany. Ale jakoś baza danych wbija się w "master" i nigdy nie ma pętli nad innymi. Wiem, że jest jakiś problem z moim wewnętrznym kursorem, ale nie mam pojęcia, co to jest. oto moje kodowanie:Jak tworzyć procedury w różnych bazach danych za pomocą Cursor

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: Nie wolno mi znać nazwy baz danych, ponieważ staram się napisać procedury „Ogólne”, więc może mieć zastosowanie do wszystkich użytkowników baz danych sql-server nie tylko moje.

P.S2: Użyłem Nesting Cursors, ale z powodu ich fatalnego działania, doceniłbym inne sposoby!

Pozdrawiam!

+0

Linia, którą musisz wykonać sp_executesql cmd nie będzie utrzymywać się przez resztę sesji względem TEGO przebiegu cmd. Dlatego nadal jesteś w stanie nadrzędnym, tzn. "USE dbname" jest wysyłane, a następnie zapomniane. –

+0

I wydaje się trochę dziwne, że nie wolno ci znać nazw baz danych. Jeśli masz dostęp do mastera, i możesz wykonać ten fragment kodu, jest to rodzaj domniemanych .... :) –

+0

@NickPfitzner Próbowałem "use + DBName", ale to nie zadziałało, więc przełączyłem się na używanie tego. Co sugerujesz? –

Odpowiedz

1

Zamiast używać kursora, spróbuj użyć instrukcji while i iteruj po tablicy zmiennych temp.

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

To zadziałało świetnie! Stukrotne dzięki! –

+0

Ale gdzie powinienem dodać moją procedurę? –

+0

Zrobiłbym to w tym samym stwierdzeniu while, jako drugiej zmiennej dynamicznej @ Sql2. Możesz użyć polecenia PRINT zamiast EXEC, aby zobaczyć, jak będzie wyglądać ta instrukcja, zanim faktycznie użyjesz instrukcji EXEC. Możesz użyć zestawu wyników z EXEC do innej tabeli zmiennych i zagnieżdżać, jeśli to konieczne. Opublikuję aktualizację. – Mike