2015-12-11 3 views
6

Итак, я пытаюсь сделать процедуры в разных базах данных. Я не должен знать имя базы данных. Я попытался сделать курсоры вложенности, первый из которых получил имена баз данных динамическим способом, а другой - для создания/изменения процедур; Я использовал EXISTS для создания процедур и NOT 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: Я использовал Nesting Cursors, но из-за их катастрофического исполнения, я был бы признателен за другие пути!

Cheers!

+0

Строка, которую вы должны выполнить exec sp_executesql cmd, не будет сохранена для остальной части сеанса относительно этого запуска cmd. Вот почему вы все еще в мастерской, то есть «USE dbname» отправляется, а затем забывается. –

+0

И кажется немного странным, что вам не разрешено знать имена баз данных. Если у вас есть доступ к мастеру и вы можете выполнить этот фрагмент кода, это будет подразумеваться ... :) –

+0

@NickPfitzner Я попробовал использовать + DBName, но это не сработало, поэтому я переключился на это. Что ты предлагаешь? –

ответ

1

Вместо того, чтобы использовать курсор, попробуйте использовать оператор while и итерации по таблице переменных 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

Это сработало отлично! Бесконечно благодарен! –

+0

Но где я должен добавить свою процедуру? –

+0

Я бы сделал это в том же самом выражении, что и вторая динамическая переменная @ Sql2. Вы можете использовать команду PRINT вместо EXEC, чтобы увидеть, как выглядит оператор, прежде чем вы будете использовать инструкцию EXEC. Вы можете использовать результирующий набор из EXEC в другую таблицу переменных и в случае необходимости вставлять вложенное. Я опубликую обновление. – Mike

Смежные вопросы