【问题标题】:cursor loop - >while (@@FETCH_STATUS=0) not going into loop游标循环 - >while (@@FETCH_STATUS=0) 不进入循环
【发布时间】:2016-12-06 12:58:34
【问题描述】:

我有以下代码:

declare @prefix varchar(50)
set @prefix = 'schema1'

declare @TablesAndIdentifiers table (TableT0 varchar(50), TableX0 varchar(50), IdentifierT0 varchar(50), IdentifierX0 varchar(50))
insert into @TablesAndIdentifiers(TableT0, TableX0, IdentifierT0, IdentifierX0)
values 
 ('table1', 'table2', 'external_Id', 'Key Details | External Id')
declare @TableT varchar(50)
declare @TableX varchar(50)
declare @IdentifierT varchar(50)
declare @IdentifierX varchar(50)

------------------------------------------OUTER LOOP------------------------------------------
declare @OuterCursor cursor
set @OuterCursor = cursor for select * from @TablesAndIdentifiers
open @OuterCursor
fetch next from @OuterCursor into @TableT, @TableX, @IdentifierT, @IdentifierX
while(@@FETCH_STATUS = 0)
begin

declare @ColList2 table (ColListT varchar(50), ColListX varchar(50))
    insert into @ColList2(ColListT,ColListX)
    select ColListT, ColListX
    from (
    select COLUMN_NAME as ColListT, row_number() over (order by table_name) as r from INFORMATION_SCHEMA.Columns
    where table_name = @TableT and COLUMN_NAME!=@IdentifierT) a
    full outer join
    (select COLUMN_NAME as ColListX, row_number() over (order by table_name) as r from INFORMATION_SCHEMA.Columns
    where table_name = @TableX and COLUMN_NAME!=@IdentifierX) b
    on a.r = b.r

    --Declare and set variables containing the query which will insert the mismatch columns into a new table
    --@sqlfull is a concatenation of @sqlpre, @sql, @sqlpost, @sqlwhere, @sqlpregroup, @sqlgroupstatement, @sqlpostgroup
    --The reason for this is that @sql is the only part of the query we want to be contained in the loop - the others should run outside of the loop
    declare @sqlpre varchar(max)
    declare @sql varchar(max)
    declare @sqlpost varchar(max)
    declare @sqlgroupstatement varchar(max)
    declare @sqlpostgroup varchar(max)
    declare @sqlfull varchar(max)

    set @sqlpre = 'select * from (select '
    set @sql = ''
    set @sqlpost =  @IdentifierT + ' from '+@prefix+'.dbo.' +@TableX +' x inner join '+@prefix+'.dbo.' +@TableT + ' t on t.' +@IdentifierT + ' = x.[' + @IdentifierX +'])dt1 group by '
    set @sqlgroupstatement = ''
    set @sqlpostgroup = ' ' + @IdentifierT


declare @Cursor cursor, @ColListTvar varchar(100), @ColListXvar varchar(100)
        set @Cursor = cursor for select * from @ColList2
        open @Cursor
        fetch next from @Cursor into @ColListTvar,@ColListXvar
        Print 'Before While => ' + CAST(@@FETCH_STATUS  AS varchar(32))
        while (@@FETCH_STATUS = 0)
        begin
        Print 'Inside while -=> ' + CAST(@@FETCH_STATUS  AS varchar(32))
        set @sql = @sql + 'case when t.' +@ColListTvar + ' != x.[' +@ColListXvar + '] then 1 else null end as ' + @ColListTvar+'_mismatch, '
        set @sqlgroupstatement = @sqlgroupstatement + @ColListTvar+'_mismatch, '
        fetch next from @Cursor into @ColListTvar,@ColListXvar
        end
    close @Cursor
    Print 'After While => ' + CAST(@@FETCH_STATUS  AS varchar(32))
    set @sqlfull = concat(@sqlpre,@sql,@sqlpost,@sqlgroupstatement,@sqlpostgroup)
    print(@sqlfull)
    --exec(@sqlfull)


    declare @ColListMismatch varchar(max)
        select @ColListMismatch = coalesce(@ColListMismatch+'_count,' ,'') + column_name
        from INFORMATION_SCHEMA.COLUMNS where table_name = 'mismatches_' + @TableT and COLUMN_NAME!=@IdentifierT
        -- The last column in the list won't get a '_count' in its name (but it needs it as the rest of the code assumes this is the naming convention)
        -- See below for workaround to get round this

    --Create table variable containing the list of mismatch columns (in which we want to count the non-nulls - non-null implies there has been a mismatch)
    declare @ColListMismatchTable table (ColListM varchar(50))
        insert into @ColListMismatchTable(ColListM)
        select ColListM
        from (select [COLUMN_NAME] as ColListM from INFORMATION_SCHEMA.Columns
        where table_name = 'mismatches_'+@TableT and COLUMN_NAME!=@IdentifierT)dt1

    --Declare variables for use in queries
    declare @sqlpre2 varchar(max)
    declare @sqlloop varchar(max)
    declare @sqlpost2 varchar(max)
    declare @sqlfull2 varchar(max)
    -- Select counts from the transformation layer table and the XPLAN table; also select the count of the table produced as a result of the inner join between the two
    -- If the migration has functioned correctly, these three counts should all be the same
    set @sqlpre2 = 'select countXPLAN, countTransfLayer, countXPLAN-countTransfLayer as CountDiff, countMatchedIdentifiers, ' 
    -- As mentioned above, the       "+ @ColListMismatch + '_count into "     part of the below is necessary to append the _count to the last variable
    + @ColListMismatch + '_count into '+@prefix+'.[dbo].report_' + @TableT + ' from '
    set @sqlloop = ''
    set @sqlpost2 = ' select * from ((select count(*) as countTransfLayer from '+@prefix+'.dbo.'+@TableT+')dt1 cross join (select count(*) as countXPLAN from '+@prefix+'.dbo.['+@TableX+'])dt2 cross join  (select count(*) as countMatchedIdentifiers from '+@prefix+'.dbo.mismatches_'+@TableT+')dt4)' 

------------------------------------------SECOND INNER LOOP------------------------------------------
    --Use Cursor to create loop to produce counts for each column in mismatches_*   
    declare @Cursor2 cursor, @ColListMismatchvar varchar(50)
        set @Cursor2 = cursor for select * from @ColListMismatchTable
        open @Cursor2
        fetch next from @Cursor2 into @ColListMismatchvar
        while(@@FETCH_STATUS = 0)
        begin
        -- Select all the counts of non-nulls
        set @sqlloop = @sqlloop + '(select count(*) as '+ @ColListMismatchvar + '_count from mismatches_' + @TableT + ' where ' + @ColListMismatchvar + '=1)dt_' + @ColListMismatchvar + ' cross join '
        fetch next from @Cursor2 into @ColListMismatchvar
        end
        -- Remove variables so that they can be reused by the next data entity
        delete @ColListMismatchTable
        select @ColListMismatch=null
    close @Cursor2
    print('in loop to execute sqlfull2')
    set @sqlfull2 = concat(@sqlpre2,@sqlloop,@sqlpost2)
    print(@sqlfull2)
--  exec(@sqlfull2)
    print('executed sqlfull2')

fetch next from @OuterCursor into @TableT, @TableX, @IdentifierT, @IdentifierX
end
close @OuterCursor

输出是:

(受影响的 1 行)

(0 行受影响)

Before While => -1

While => -1

select * from (select external_Id from schema1.dbo.table22 x inner join schama1.dbo.table1 t on t.external_Id = x.[Key Details | External Id])dt1 group by  external_Id

(0 行受影响)

(0 行受影响) 在循环中执行 sqlfull2..

我面临的代码问题是没有进入下面代码的while循环

declare @Cursor cursor, @ColListTvar varchar(100), @ColListXvar varchar(100)
        set @Cursor = cursor for select * from @ColList2
        open @Cursor
        fetch next from @Cursor into @ColListTvar,@ColListXvar
        Print 'Before While => ' + CAST(@@FETCH_STATUS  AS varchar(32))
        while (@@FETCH_STATUS = 0)
        begin
        Print 'Inside while -=> ' + CAST(@@FETCH_STATUS  AS varchar(32))
        set @sql = @sql + 'case when t.' +@ColListTvar + ' != x.['     +@ColListXvar + '] then 1 else null end as ' + @ColListTvar+'_mismatch, '
        set @sqlgroupstatement = @sqlgroupstatement +     @ColListTvar+'_mismatch, '
        fetch next from @Cursor into @ColListTvar,@ColListXvar
        end
    close @Cursor
    Print 'After While => ' + CAST(@@FETCH_STATUS  AS varchar(32))
    set @sqlfull = concat(@sqlpre,@sql,@sqlpost,@sqlgroupstatement,@sqlpostgroup)
    print(@sqlfull)
    --exec(@sqlfull)

任何建议将不胜感激。

提前致谢。

【问题讨论】:

  • 如果可能简化你的代码
  • deallocateclose 之后。并且不要在循环内声明任何内容 - 本地变量的范围是当前批次,而不是代码块。在脚本的开头声明所有内容。
  • 我从未见过用@ 符号声明为变量的游标。请参阅此处声明光标。 msdn.microsoft.com/en-us/library/ms180169.aspx。我也不会使用Select * 来选择光标。定义从光标进入变量的列。
  • @WEI_DBA @cursor 绝对没问题
  • @IvanStarostin。谢谢!再说一次,我以前从未见过这样声明过。

标签: sql sql-server sql-server-2008 sql-server-2012 sql-server-2008-r2


【解决方案1】:

经过大量分析,我发现了这个问题

select ColListT, ColListX
from (
select COLUMN_NAME as ColListT, row_number() over (order by table_name) as r          from INFORMATION_SCHEMA.Columns
where table_name = @TableT and COLUMN_NAME!=@IdentifierT) a
full outer join
(select COLUMN_NAME as ColListX, row_number() over (order by table_name) as  r from INFORMATION_SCHEMA.Columns
where table_name = @TableX and COLUMN_NAME!=@IdentifierX) b
on a.r = b.r

如果我使用内部联接而不是完全外部联接,它会起作用。

2 个表中的列数存在问题,其中一个表的列比另一个少,这就是它无法正常工作的原因。

【讨论】:

    猜你喜欢
    • 2015-03-08
    • 1970-01-01
    • 2016-04-24
    • 2012-08-26
    • 2021-03-26
    • 1970-01-01
    • 2016-07-08
    • 1970-01-01
    • 2023-03-10
    相关资源
    最近更新 更多