而循环作为光标

时间:2017-05-19 09:23:32

标签: sql-server tsql while-loop cursor

我的案例是一个典型的研究案例,可以通过光标构造轻松解决但我的问题是为什么我的陈述只在下面提到的情况下才正确?声音越多,声明就越糟糕。也许,我使用的临时表完全不需要?绝对地,我的概念存在逻辑错误。

一般来说,我有一张表MJ_IDT,其中:

  1. identity_col是数据类型int identity(1,1)
  2. data_col是数据类型int,它允许空值

    identity_col data_col 1 AAAAA 2 CCCCC 3 BBBBB 5 ddddd

  3. 我想准备一个while循环,它的任务是找到所有刹车并用适当的值填充它,在这种情况下将是一对4 NULL。

    我另外创建一个临时表#mj_id,在我的sql语句中使用如下。

    id  id_col
    1   1
    2   2
    3   3
    4   5
    

    我的SQL查询:

    CREATE TABLE #mj_id
    (
        id int identity(1,1),
        id_col int NULL
    )
    
    INSERT INTO #mj_id (id_col)
    SELECT identity_col FROM MJ_IDT
    
    DECLARE 
        @counter_next   int = 1,
        @incremental    int = 1,
        @counter_prev   int = 0;
    
    WHILE EXISTS (SELECT top 1 1 FROM #mj_id 
                  WHERE id = @counter_next) 
      AND @counter_next < (SELECT MAX(identity_col) FROM MJ_IDT)
    BEGIN   
        IF (SELECT id_col FROM #mj_id 
            WHERE id = @counter_next) - @counter_prev > @incremental
        BEGIN
            SET IDENTITY_INSERT MJ_IDT ON;
    
            INSERT INTO MJ_IDT (identity_col)
            VALUES (@counter_next);
    
            SET @counter_prev = (SELECT id_col FROM #mj_id 
                                 WHERE id = @counter_next);
            SET @counter_next = @counter_next + @incremental;
    
            SET IDENTITY_INSERT MJ_IDT OFF;
        END
        ELSE
           SET @counter_prev = (SELECT id_col FROM #mj_id 
                                WHERE id = @counter_next);
           SET @counter_next = @counter_next + @incremental;
        END
    

    它适用于这种情况,但当我的表MJ_IDT为:

    1   AAAAA
    2   CCCCC
    3   BBBBB
    5   ddddd
    6   ggggg
    8   ggggg
    

    它不起作用。你能帮我填一下身份栏吗?

1 个答案:

答案 0 :(得分:1)

需要注意的重要注意事项:

从您的问题来看,您似乎正在尝试识别并纠正自动生成的identity值中的差距。这是毫无意义的努力,因为identity值不能保证是连续的,只是唯一的。

您问题的实际答案:

您不需要光标或循环,只需要一个数字表到join,这将为您填补空白。您可以使用计数表构建其中一个:

declare @MJ_IDT table (identity_col int, data_col nvarchar(10));
insert into @MJ_IDT values(1,'AAAAA'),(2,'CCCCC'),(3,'BBBBB'),(5,'ddddd');

              -- Create table with 10 rows in it:
with t(t) as (select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1)
              -- Cross join this table to exponentially increase the number of rows,
              -- then return the row_number of enough rows to cover up to your max ID:
    ,n(n) as (select top (select max(identity_col) from @MJ_IDT) row_number() over (order by (select null))
              from t t1,t t2,t t3,t t4,t t5,t t6
             )
select n.n as identity_col
        ,m.data_col
from n
    left join @MJ_IDT m
        on(n.n = m.identity_col)
order by n.n;

输出:

+--------------+----------+
| identity_col | data_col |
+--------------+----------+
|            1 | AAAAA    |
|            2 | CCCCC    |
|            3 | BBBBB    |
|            4 | NULL     |
|            5 | ddddd    |
+--------------+----------+