Проблема контекста T-SQL

Я создал скрипт для сравнения таблиц двух баз данных, чтобы найти различия. Я хочу иметь возможность вручную установить две переменные (по одной для каждой базы данных), и чтобы оператор 'USE' использовал значение переменной для одной из баз данных, но это меняет контекст и работает правильно.

Это то, что я пытаюсь использовать для заполнения переменной (@Use) кодом USE для выполнения

--set @Use = 'USE ' + @NewProdDB + ';SELECT name FROM sys.tables'

--EXEC (@Use)

Это весь запрос:

--========================================================================================================

--  Used to find table values in the test upgrade system database not found the newly upgraded system
--  database. Make sure change the system database names before running the query.

--  Also, select the upgraded database to run against

--========================================================================================================



DECLARE @NewProdDB VARCHAR(100)
DECLARE @TestUpgradeDB VARCHAR(100)
DECLARE @Columns VARCHAR (MAX)
DECLARE @Query VARCHAR(MAX)
DECLARE @ResultsTest VARCHAR(MAX)
DECLARE @SetResultsCursor NVARCHAR(MAX)
DECLARE @Fetcher NVARCHAR(MAX)
DECLARE @Use NVARCHAR(50)
DECLARE @ListOfTables VARCHAR(100)
DECLARE @WTF NVARCHAR(max)
DECLARE @rescanCode nvarchar(max)

/*               Enter Upgraded system DB here        */
SET @NewProdDB = 'zSBSSYS'

/*               Enter Test Upgrade system DB here   */
SET @TestUpgradeDB = 'TESTzSBSSYS'


--set @Use = 'USE ' + @NewProdDB + ';SELECT name FROM sys.tables'

--EXEC (@Use)

SET NOCOUNT ON

set @rescanCode = 'DECLARE recscan CURSOR FOR 
SELECT TABLE_NAME FROM ' + @TestUpgradeDB + '.INFORMATION_SCHEMA.TABLES 
WHERE TABLE_NAME NOT LIKE ''Mbf%'' AND TABLE_TYPE = ''BASE TABLE''
ORDER BY TABLE_NAME' 

exec (@rescanCode)
OPEN recscan 
FETCH NEXT FROM recscan INTO @ListOfTables


WHILE @@fetch_status = 0     
    BEGIN 
        BEGIN TRY


         /* START Table column query */
         Declare @Table varchar(60) 

         set @Table = @ListOfTables

         set @table = (SELECT top 1 name FROM sys.tables where name = @Table)
         DECLARE 
          @sql1 nvarchar(max) = ''
         ,@INTOColumns NVARCHAR(MAX)=''
         ,@Where nvarchar(max) = ''
         ,@ColumnID Int 
         ,@Column Varchar(8000) 
         ,@Type Varchar(8000) 
         ,@Length Int 
         ,@del1 varchar(2) = ','
         ,@CRLF bit = 1
         ,@aliasfield varchar(5) = '[a].'

         DECLARE CSR_Attributes CURSOR FOR
         SELECT 
         [ColumnID] = Col.column_id,
         [Column] = Col.Name,
         [Type] = [types].name,
         [Length] = Col.max_length
         FROM sys.objects Obj, sys.columns Col, sys.types [types]
         WHERE Obj.OBJECT_ID = Col.OBJECT_ID AND Obj.TYPE = 'U'
         AND Col.system_type_id = [types].system_type_id
         AND Obj.name = @table
         AND Col.name <> 'tstamp'
         ORDER BY Obj.name, Col.column_id, Col.name
         OPEN CSR_Attributes
         FETCH NEXT FROM CSR_Attributes INTO @ColumnID, @Column, @Type, @Length
         WHILE @@FETCH_STATUS = 0
         BEGIN 
         set @sql1 += @column + @del1
         set @Where += 'b.' + @column + '=a.' + @column + ' and '
         set @INTOColumns += '@INTOcol,' 
         FETCH NEXT FROM CSR_Attributes INTO @ColumnID, @Column, @Type, @Length
         END
         CLOSE CSR_Attributes
         DEALLOCATE CSR_Attributes

         SET @Columns = SUBSTRING(@sql1,1,len(@sql1)-1) -- get rid of last comma
         SET @Where = SUBSTRING(@Where,1,len(@Where)-4) -- get rid of last 'and'
         SET @INTOColumns = SUBSTRING(@INTOColumns,1,len(@INTOColumns)-1) -- get rid of last comma

         /* END Table column query */

         /*   Create SELECT statement here  */

         SET @ResultsTest='SELECT TOP 1 ' + @Columns + '
         FROM ' + @TestUpgradeDB + '..' + @Table + ' A 
         WHERE NOT EXISTS
         (SELECT ' + @Columns + ' 
         FROM ' + @NewProdDB + '..' + @Table + ' B WHERE ' + @Where + ')'



         SET @SetResultsCursor = 'DECLARE DataReturned CURSOR FOR ' + @ResultsTest  

         exec (@SetResultsCursor)
         OPEN DataReturned

         SET @Fetcher = 'DECLARE @INTOcol NVARCHAR(Max)
         FETCH NEXT FROM DataReturned INTO ' + @INTOColumns

         exec (@Fetcher)

         if @@FETCH_STATUS = 0

             begin

             CLOSE DataReturned

                DEALLOCATE DataReturned

                SET @Query='SELECT ' + @Columns + '
                FROM ' + @TestUpgradeDB + '..' + @Table + ' A WHERE NOT EXISTS
                (SELECT ' + @Columns + ' FROM ' + @NewProdDB + '..' + @Table + ' B WHERE ' + @Where + ')'



                select @Table
                exec (@Query)

            end
        else
            begin

                CLOSE DataReturned
                DEALLOCATE DataReturned
            end


    end try
    begin catch
        --SELECT ERROR_MESSAGE() AS ErrorMessage;  

    end catch

    FETCH NEXT FROM recscan INTO @ListOfTables

end 

CLOSE recscan
DEALLOCATE recscan
SET NOCOUNT OFF

1 ответ

Вы не можете сделать это:

DECLARE @DB varchar(10) = 'beep';
DECLARE @USE varchar(50) = 'USE '+ @DB;
EXEC sp_sqlexec @USE;

SELECT blah FROM bloop

Контекст базы данных используется только во время @USE sql, затем возвращается

Вы можете сделать это:

DECLARE @DB varchar(10) = 'beep';
DECLARE @SQL varchar(50) = 'USE '+@DB+'; SELECT blah FROM bloop;'
EXEC sp_sqlexec @USE;

Кроме того, посмотрите на инструменты данных SQL Server (SSDT)

Он делает именно то, что вы пытаетесь сделать, сравнивает схемы и / или данные между базами данных, и его очень легко использовать.

Другие вопросы по тегам