2015-12-11 15 views
6

Così sto cercando di rendere le procedure in database diversi. Non dovrei conoscere il nome dei database. Ho cercato di creare dei cursori di nesting, il primo per ottenere i nomi dei database in modo dinamico e l'altro per creare/modificare le procedure; Ho usato EXISTS per creare procedure e NON ESISTE per alterarle. Ma in qualche modo il database rimane in "master" e non si sovrappone mai agli altri. So che c'è un problema con il mio cursore nesting interno, anche se non ho idea di cosa sia. Ecco il mio codice:Come creare procedure In diversi database con il cursore

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: io non dovrei conoscere il nome del database perché sto cercando di scrivere una procedure di "Generali" in modo che possa applicarsi a tutti i database sql i-server degli utenti non solo mio

P.S2: Ho usato Nesting cursori, ma a causa della loro prestazione disastrosa, apprezzerei altri modi!

Cheers!

+0

La linea si deve exec cmd sp_executesql non terrà per il resto della sessione rispetto a quella serie di cmd. Questo è il motivo per cui sei ancora un master, il "USE dbname" viene inviato e poi dimenticato. –

+0

E sembra un po 'strano che non ti sia permesso conoscere i nomi dei database. Se si ha accesso a maestro, e può eseguire quel pezzo di codice, che è una specie di implicita .... :) –

+0

@NickPfitzner ho provato 'uso + DBName', ma non ha funzionato, quindi sono passato ad usare quello. Che cosa suggerisci? –

risposta

1

Invece di usare un cursore, provare a utilizzare un ciclo while, e l'iterazione di un tavolo variabile 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

Ha funzionato alla grande! Grazie mille! –

+0

Ma dove dovrei aggiungere la mia procedura? –

+0

Lo farei nella stessa istruzione while di una seconda variabile dinamica @ Sql2. È possibile utilizzare il comando PRINT invece di EXEC per vedere come apparirà la dichiarazione prima di utilizzare effettivamente l'istruzione EXEC. È possibile utilizzare il set di risultati da EXEC in un'altra tabella di variabili e fare un annidato mentre, se necessario. Posterò un aggiornamento – Mike

Problemi correlati