寻找光标替换

时间:2016-08-17 13:48:51

标签: sql sql-server

我有2个表#TblFinal#TblData ..我需要根据唯一键TblData将#TblFinal数据与#34 {#{1}}进行比较

  1. 如果#F_U_KEY vs D_U_KEY.中不存在唯一键的#TblData数据,则#TblFinal数据记录将插入到#TblData表中。 TblFinal将为1(默认值),F_COUNTER为默认值

  2. 如果#F_IS_CLEAR中存在唯一键的#TblData数据,那么首先我们从#TblFinal获得密钥F_ID

    < / LI>

    案例A:如果表格的#D_SEV_ID&#34;#TblData&#34;不等于-11

    然后需要更新&#34; F_COUNTER&#34; for table&#34;#TblFinal&#34; for&#34; F_ID&#34;

    案例B:,如果表格#34;#TblData&#34;的D_SEV_ID等于-11

    然后为D_SEV_ID = -11和F_IS_CLEAR = 1的新条目为&#34; F_ID&#34;

    这是我写的光标,需要一些优化的解决方案,因为我的实际#TblFinal拥有庞大的数据和数据比较表&#34; #TblData&#34;总是有100条记录要比较。

    TblFinal

2 个答案:

答案 0 :(得分:0)

由于数据顺序看起来很重要,因此基于集合的方法看起来不适合您。也就是说,有些事情可以让你的查询速度提高50%左右。

  1. 从min(D_ID)循环到max(D_ID),递增1。
  2. 只在#TblFinal中查找一次而不是在exists中查找一次,然后再次查找@FId。另外,确保#TblFinal在F_U_KEY + F_IS_CLEAR + F_SEV_ID上有索引,并且F_ID是聚簇索引的一部分或在INCLUDE子句中。理想情况下,它是聚簇索引中第一个快速更新的字段。
  3. 通过将D_VAL存储在变量中,您可以直接从变量插入#TblFinal,而不必从#TblData再次进行SELECT。
  4. 以下是代码:

    DECLARE @D_ID INT
    DECLARE @FId INT
    DECLARE @D_SEV_ID INT
    DECLARE @D_U_KEY NVARCHAR(200)
    DECLARE @D_VAL NVARCHAR(20)
    
    DECLARE @Min_D_ID INT, @Max_D_ID INT
    SELECT  @Min_D_ID = min(D_ID), @Max_D_ID = max(D_ID) FROM #TblData(NOLOCK)
    
    SELECT @D_ID = @Min_D_ID
    
    WHILE @D_ID <= @Max_D_ID
    BEGIN   
        SELECT @D_SEV_ID = D_SEV_ID, @D_U_KEY = D_U_KEY, @D_VAL = D_VAL FROM #TblData(NOLOCK) WHERE D_ID = @D_ID
    
        IF @D_U_KEY IS NOT NULL
        BEGIN
            SELECT @FId = F_ID FROM #TblFinal(NOLOCK) WHERE F_U_KEY = @D_U_KEY AND F_IS_CLEAR = 0 AND F_SEV_ID <> -11
    
            IF @FId IS NOT NULL
            BEGIN
                IF (@D_SEV_ID <> -11)
                BEGIN
                    UPDATE #TblFinal
                    SET F_COUNTER = F_COUNTER + 1 WHERE F_ID = @FId
                END
                ELSE IF(@D_SEV_ID = -11)
                BEGIN
                    INSERT INTO #TblFinal (F_VAL, F_SEV_ID, F_U_KEY)
                    SELECT  @D_VAL, @D_SEV_ID, @D_U_KEY
    
                    UPDATE #TblFinal
                    SET F_IS_CLEAR = 1 WHERE F_ID = @FId
                END
                ELSE
                BEGIN
                    PRINT 'DO NOTHING'
                END
            END
            ELSE
            BEGIN
                INSERT INTO #TblFinal (F_VAL, F_SEV_ID, F_U_KEY)
                SELECT  @D_VAL, @D_SEV_ID, @D_U_KEY
            END
        END
    
        SELECT @D_ID = @D_ID + 1, @FId = NULL
    END   
    

答案 1 :(得分:0)

你应该能够做到这一点。这是解决这个问题的一种方法。我唯一不理解的部分是F_IS_CLEAR。对此的业务规则有点模糊。如果您需要部分帮助,我需要了解其基本原理。

CREATE TABLE #Output
(F_ID INT IDENTITY(1,1), F_VAL NVARCHAR(20), F_SEV_ID INT, F_U_KEY NVARCHAR(200), F_COUNTER INT DEFAULT(1), F_IS_CLEAR BIT DEFAULT(0))

insert #Output
    select x.D_VAL
    , x.D_SEV_ID
    , x.D_U_KEY
    , x.F_COUNTER
    , x.F_IS_CLEAR
from 
(
    select D_VAL = MIN(D_VAL)
        , D_SEV_ID = MIN(D_SEV_ID)
        , D_U_KEY
        , F_COUNTER = COUNT(*)
        , F_IS_CLEAR = 1
        , SortOrder = 1
    from #TblData d
    where D_ID < (select d2.D_ID from #TblData d2 where d2.D_U_KEY = d.D_U_KEY and d2.D_SEV_ID = -11)
    group by d.D_U_KEY

    UNION ALL

    select D_VAL
        , D_SEV_ID
        , D_U_KEY
        , F_COUNTER = 1
        , F_IS_CLEAR = 0
        , SortOrder = 2
    from #TblData d
    where d.D_SEV_ID = -11

    UNION ALL

    select D_VAL = MIN(D_VAL)
        , D_SEV_ID = MIN(D_SEV_ID)
        , D_U_KEY
        , F_COUNTER = COUNT(*)
        , F_IS_CLEAR = 0
        , SortOrder = 3
    from #TblData d
    where D_ID > (select d2.D_ID from #TblData d2 where d2.D_U_KEY = d.D_U_KEY and d2.D_SEV_ID = -11)
    group by d.D_U_KEY

    UNION ALL

    select D_VAL = MIN(D_VAL)
        , D_SEV_ID = MIN(D_SEV_ID)
        , D_U_KEY
        , F_COUNTER = COUNT(*)
        , F_IS_CLEAR = 0
        , SortOrder = 4
    from #TblData d
    where NOT EXISTS (select d2.D_ID from #TblData d2 where d2.D_U_KEY = d.D_U_KEY and d2.D_SEV_ID = -11)
    group by d.D_U_KEY
) x

order by D_U_KEY, SortOrder

select * from #Output