基于集合的堆栈更新查询

时间:2018-12-10 21:57:38

标签: sql-server

我有一张表,需要设置两个Flag1Flag2标志值之一。

   Create Table StackUpdateTable
       (Id Int, GroupId Int, Flag1 Bit, Flag2 Bit, Requirements Int)

现在,这是规则:

  1. Requirements将是 1或 2。
  2. Requirements指定必须先设置的Flag1值的数量,然后才能按Flag2的顺序为给定的GroupId设置Id值(上升)。
  3. 一旦设置了Flag2,序列将重新开始(对于每个GroupId

如果有一种方法可以对此表(以及所有新出现的表)进行基于集合的更新,并且可以为每组GroupId记录设置标志,那么我一直在想尽办法

为进一步说明,请考虑以下数据:

Insert Into StackUpdateTable Values
     (1, 100, 0, 0, 1)
    ,(2, 100, 0, 0, 1)
    ,(3, 101, 0, 0, 1)
    ,(4, 102, 0, 0, 2)
    ,(5, 102, 0, 0, 2)
    ,(6, 102, 0, 0, 2)
    ,(7, 103, 1, 0, 1)
    ,(8, 103, 0, 0, 1)
    ,(9, 103, 0, 0, 1)
    ,(10,104, 1, 0, 2)
    ,(11,105, 1, 0, 2)
    ,(12,106, 0, 0, 2)
    ,(13,106, 0, 0, 2)
    ,(14,106, 0, 0, 2)
    ,(15,106, 0, 0, 2)
;

鉴于此数据,这就是生成的更新后的数据的样子

 1 100 1 0 1 <-- Flag1 Set
 2 100 0 1 1 <-- Flag2 Set
 3 101 1 0 1 <-- Flag1 Set
 4 102 1 0 2 <-- 1st Flag1 Set
 5 102 1 0 2 <-- 2nd Flag1 Set
 6 102 0 1 2 <-- Flag2 Set
 7 103 1 0 1 <-- Unchanged
 8 103 0 1 1 <-- Flag2 Set
 9 103 1 0 1 <-- Flag1 Set
10 104 1 0 2 <-- Unchanged
11 104 1 0 2 <-- Unchanged
12 106 1 0 2 <-- 1st Flag1 Set
13 106 1 0 2 <-- 2nd Flag1 Set
14 106 0 1 2 <-- Flag2 Set
15 106 1 0 2 <-- 1st Flag1 Set

如果添加更多数据,那么...

Insert Into StackUpdateTable Values
     (16,100, 0, 0, 1)
    ,(17,103, 0, 0, 1)
    ,(18,106, 0, 0, 2)
;

...然后更新的数据集(按GroupId \ Id顺序应如下所示:

 1 100 1 0 1 <-- Unchanged
 2 100 0 1 1 <-- Unchanged
16 100 1 0 1 <-- Flag1 Set
 3 101 1 0 1 <-- Unchanged
 4 102 1 0 2 <-- Unchanged
 5 102 1 0 2 <-- Unchanged
 6 102 0 1 2 <-- Unchanged
 7 103 1 0 1 <-- Unchanged
 8 103 0 1 1 <-- Unchanged
 9 103 1 0 1 <-- Unchanged
17 103 0 1 1 <-- Flag2 Set
10 104 1 0 2 <-- Unchanged
11 104 1 0 2 <-- Unchanged
12 106 1 0 2 <-- Unchanged
13 106 1 0 2 <-- Unchanged
14 106 0 1 2 <-- Unchanged
15 106 1 0 2 <-- Unchanged
18 106 1 0 2 <-- Flag1 Set

最后,如果应插入以下行:

Insert Into StackUpdateTable Values
     (19,106, 0, 0, 2)
;

然后我期望:

 1 100 1 0 1 <-- Unchanged
 2 100 0 1 1 <-- Unchanged
16 100 1 0 1 <-- Flag1 Set
 3 101 1 0 1 <-- Unchanged
 4 102 1 0 2 <-- Unchanged
 5 102 1 0 2 <-- Unchanged
 6 102 0 1 2 <-- Unchanged
 7 103 1 0 1 <-- Unchanged
 8 103 0 1 1 <-- Unchanged
 9 103 1 0 1 <-- Unchanged
17 103 0 1 1 <-- Flag2 Set
10 104 1 0 2 <-- Unchanged
11 104 1 0 2 <-- Unchanged
12 106 1 0 2 <-- Unchanged
13 106 1 0 2 <-- Unchanged
14 106 0 1 2 <-- Unchanged
15 106 1 0 2 <-- Unchanged
18 106 1 0 2 <-- Flag1 Set
19 106 0 1 2 <-- Flag2 Set

我一直在使用诸如Row_Number() Over (Partition By GroupId Order By Id) As _seq之类的Windowing函数来整理数据,然后再使用几个Lag函数Lag(Flag1, 1, 0) Over (Partition By GroupId Order By Id) As _Calc1等,但我却想尝试处理新记录(值以零开头)。

我认为我也需要开始进行记录计数,但是不确定如何处理-认为我也许可以用_seq做某事,但仍然无处可做。

我想要的是找出每次解析该表时如何执行基于Set的更新。不一定要进行单个更新,实际上我很乐意在组合中删除Temp表,CTE或其他任何东西。我不想要做的一件事就是必须通过IdGroupId来浏览我的方式。

我很愿意听到我的要求无法完成,但是我充满希望!

1 个答案:

答案 0 :(得分:1)

使用注释中的ZLK查询,将其转换为UPDATE语句,每次将记录添加到表后即可运行。

UPDATE s
SET s.Flag1 = CASE WHEN t.RN > 0 THEN 1 ELSE 0 END
    ,s.Flag2 = CASE WHEN t.RN = 0 THEN 1 ELSE 0 END
FROM
(
    SELECT
        *
        ,RN = ROW_NUMBER() OVER ( PARTITION BY GroupID, Requirements ORDER BY ID ) % ( Requirements + 1 )
    FROM StackUpdateTable
) T
INNER JOIN StackUpdateTable s ON s.Id = T.Id