Change Database within a Cursor

  • Hi,

    I like to backup the stored procedures' code used in my databases. So I created this Script:

    /*

    IF OBJECT_ID('[Monitor].[dbo].[Procedurecode]') IS NOT NULL DROP TABLE [Monitor].[dbo].[Procedurecode];

    */

    DECLARE

    @db nvarchar(50),

    @strSQL nvarchar (100)

    IF CURSOR_STATUS('global','cur1')>=-1 BEGIN DEALLOCATE cur1 END

    DECLARE cur1 CURSOR FOR

    SELECT name FROM sys.databases

    WHERE name not in ('Reporter1','Reporter1TempDB','ReportServer','ReportServerTempDB','sysutility_mdw','tempdb')

    OPEN cur1

    WHILE @@FETCH_STATUS = 0

    BEGIN

    SET @strSQL ='USE ' + @db

    EXEC sp_executesql @strSQL

    IF CURSOR_STATUS('global','cur2')>=-1 BEGIN DEALLOCATE cur2 END

    IF OBJECT_ID('[Monitor].[dbo].[Procedurecode]') IS NULL CREATE TABLE [Monitor].[dbo].[Procedurecode] (DB nvarchar(128), ROUTINE_NAME varchar(max), ROUTINE_DEFINITION varchar(max), LAST_ALTERED datetime, INSERT_DATE date)

    DECLARE

    @routine_name varchar(max),

    @routine_definition varchar(max),

    @last_altered datetime

    DECLARE cur2 CURSOR FOR

    SELECT ROUTINE_NAME, ROUTINE_DEFINITION, LAST_ALTERED

    FROM information_schema.routines

    WHERE routine_type = 'PROCEDURE'

    OPEN cur2

    FETCH NEXT FROM cur2 INTO @routine_name, @routine_definition, @last_altered

    WHILE @@FETCH_STATUS = 0

    BEGIN

    INSERT INTO [Monitor].[dbo].[Procedurecode] (DB, ROUTINE_NAME, ROUTINE_DEFINITION, LAST_ALTERED, INSERT_DATE)

    VALUES (DB_NAME(), @routine_name, @routine_definition, @last_altered, CONVERT (date, GETDATE()))

    FETCH NEXT FROM cur2 INTO @routine_name, @routine_definition, @last_altered

    END

    CLOSE cur2

    DEALLOCATE cur2

    END

    FETCH NEXT FROM cur1 INTO @db

    CLOSE cur1

    DEALLOCATE cur1

    Problem is (and I seem not to be the only one with tis) described here:

    "If the executed string contains a USE statement that changes the database context, the change to the database context only lasts until sp_executesql or the EXECUTE statement has finished running." There is nothing magical in SQL server that knows you intend a series of dynamic sql commands to be part of a single job running in a single context. You have to build the entire string for the job you want to execute."

    ms-help://MS.SQLCC.v10/MS.SQLSVR.v10.en/s10de_1devconc/html/01c64ab0-9227-475a-a59a-ed80f9333042.htm

    So I only get the SPs of the current database. Do you have any ideas how to solve this problem anyway?

    Thanks in advance!

  • ratloser99 36160 (8/21/2015)


    Hi,

    I like to backup the stored procedures' code used in my databases. So I created this Script:

    /*

    IF OBJECT_ID('[Monitor].[dbo].[Procedurecode]') IS NOT NULL DROP TABLE [Monitor].[dbo].[Procedurecode];

    */

    DECLARE

    @db nvarchar(50),

    @strSQL nvarchar (100)

    IF CURSOR_STATUS('global','cur1')>=-1 BEGIN DEALLOCATE cur1 END

    DECLARE cur1 CURSOR FOR

    SELECT name FROM sys.databases

    WHERE name not in ('Reporter1','Reporter1TempDB','ReportServer','ReportServerTempDB','sysutility_mdw','tempdb')

    OPEN cur1

    WHILE @@FETCH_STATUS = 0

    BEGIN

    SET @strSQL ='USE ' + @db

    EXEC sp_executesql @strSQL

    IF CURSOR_STATUS('global','cur2')>=-1 BEGIN DEALLOCATE cur2 END

    IF OBJECT_ID('[Monitor].[dbo].[Procedurecode]') IS NULL CREATE TABLE [Monitor].[dbo].[Procedurecode] (DB nvarchar(128), ROUTINE_NAME varchar(max), ROUTINE_DEFINITION varchar(max), LAST_ALTERED datetime, INSERT_DATE date)

    DECLARE

    @routine_name varchar(max),

    @routine_definition varchar(max),

    @last_altered datetime

    DECLARE cur2 CURSOR FOR

    SELECT ROUTINE_NAME, ROUTINE_DEFINITION, LAST_ALTERED

    FROM information_schema.routines

    WHERE routine_type = 'PROCEDURE'

    OPEN cur2

    FETCH NEXT FROM cur2 INTO @routine_name, @routine_definition, @last_altered

    WHILE @@FETCH_STATUS = 0

    BEGIN

    INSERT INTO [Monitor].[dbo].[Procedurecode] (DB, ROUTINE_NAME, ROUTINE_DEFINITION, LAST_ALTERED, INSERT_DATE)

    VALUES (DB_NAME(), @routine_name, @routine_definition, @last_altered, CONVERT (date, GETDATE()))

    FETCH NEXT FROM cur2 INTO @routine_name, @routine_definition, @last_altered

    END

    CLOSE cur2

    DEALLOCATE cur2

    END

    FETCH NEXT FROM cur1 INTO @db

    CLOSE cur1

    DEALLOCATE cur1

    Problem is (and I seem not to be the only one with tis) described here:

    "If the executed string contains a USE statement that changes the database context, the change to the database context only lasts until sp_executesql or the EXECUTE statement has finished running." There is nothing magical in SQL server that knows you intend a series of dynamic sql commands to be part of a single job running in a single context. You have to build the entire string for the job you want to execute."

    ms-help://MS.SQLCC.v10/MS.SQLSVR.v10.en/s10de_1devconc/html/01c64ab0-9227-475a-a59a-ed80f9333042.htm

    So I only get the SPs of the current database. Do you have any ideas how to solve this problem anyway?

    Thanks in advance!

    Flippant answer: use a source control system for your databases.

    Less flippant answer: why are you using a cursor for each proc? Do it in one hit, per database! As for the 'Use' comment, all of your subsequent SQL needs to be part of the same statement.

    @sql = 'use db; [more code here]'

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • okay, I've feared this. Thank you for your reply.

  • OK, and please get rid of cur2:

    insert Monitor.dbo.Procedurecode

    (DB

    ,ROUTINE_NAME

    ,ROUTINE_DEFINITION

    ,LAST_ALTERED

    ,INSERT_DATE

    )

    select db_name()

    ,ROUTINE_NAME

    ,ROUTINE_DEFINITION

    ,LAST_ALTERED

    ,convert (date, getdate())

    from INFORMATION_SCHEMA.ROUTINES

    where ROUTINE_TYPE = 'PROCEDURE'

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • Oh, thanks!

  • Now it works! Definition code in information_schema.routines ist varchar(4000), the definition code might be incomplete. So I needed to use another source.

    If you change @var to 'V', you can backup all your views, with 'TF' you might backup functions, too.

    DECLARE @db nvarchar(20)

    DECLARE @strSQL nvarchar (max)

    DECLARE @table nvarchar(50) = 'Monitor.dbo.Code_Procedures'

    DECLARE @var varchar(3) = 'P'

    DECLARE @strDEL nvarchar(max)

    DECLARE @STR nvarchar (max) = 'IF CURSOR_STATUS(''global'',''cur2'')>=-1 BEGIN DEALLOCATE cur2 END

    --IF OBJECT_ID('''+ @table + ''') IS NOT NULL DROP TABLE '+ @table +'

    IF OBJECT_ID('''+ @table + ''') IS NULL CREATE TABLE '+ @table + '(

    [DB_NAME] nvarchar(128),

    [SCHEMA_NAME] nvarchar(128),

    ROUTINE_NAME varchar(max),

    ROUTINE_DEFINITION varchar(max),

    CREATE_DATE datetime,

    LAST_ALTERED datetime,

    INSERT_DATE date)

    DECLARE

    @db_name nvarchar(128),

    @schema_name nvarchar(128),

    @routine_name varchar(max),

    @routine_definition varchar(max),

    @create_date datetime,

    @last_altered datetime

    DECLARE cur2 CURSOR FOR

    SELECT

    DB_NAME(),

    s.name,

    o.name,

    m.definition,

    o.create_date,

    o.modify_date

    FROM sys.objects o

    INNER JOIN sys.sql_modules m

    ON o.object_id = m.object_id

    INNER JOIN sys.schemas s

    ON s.schema_id = o.schema_id

    WHERE o.type = '''+ @var +'''

    OPEN cur2

    FETCH NEXT FROM cur2 INTO

    @db_name,

    @schema_name,

    @routine_name,

    @routine_definition,

    @create_date,

    @last_altered

    WHILE @@FETCH_STATUS = 0

    BEGIN

    INSERT INTO '+ @table + ' (

    [DB_NAME],

    [SCHEMA_NAME],

    ROUTINE_NAME,

    ROUTINE_DEFINITION,

    CREATE_DATE,

    LAST_ALTERED,

    INSERT_DATE)

    VALUES (

    @db_name,

    @schema_name,

    @routine_name,

    @routine_definition,

    @create_date,

    @last_altered,

    CONVERT (date, GETDATE()))

    FETCH NEXT FROM cur2 INTO

    @db_name,

    @schema_name,

    @routine_name,

    @routine_definition,

    @create_date,

    @last_altered

    END

    CLOSE cur2

    DEALLOCATE cur2'

    IF CURSOR_STATUS('global','cur1')>=-1 BEGIN DEALLOCATE cur1 END

    DECLARE cur1 CURSOR FOR

    SELECT name FROM sys.databases

    WHERE name not in ('Reporter1','Reporter1TempDB','ReportServer','ReportServerTempDB','sysutility_mdw','tempdb','master','model','msdb')

    OPEN cur1

    FETCH NEXT FROM cur1 INTO @db

    WHILE @@FETCH_STATUS = 0

    BEGIN

    SET @strSQL = 'USE ' + @db +'; ' + @STR

    EXEC sp_executesql @strSQL

    FETCH NEXT FROM cur1 INTO @db

    END

    CLOSE cur1

    DEALLOCATE cur1

    /*

    SET @strDEL = 'DELETE FROM ' + @table + ' WHERE [INSERT_DATE] < CONVERT (date, GETDATE()-30)'

    EXEC sp_executesql @strDEL

    */

Viewing 6 posts - 1 through 5 (of 5 total)

You must be logged in to reply to this topic. Login to reply