如何将自引用的复杂游标转换为更高效的 SQL 代码? CTE、交叉应用还是其他?
Posted
技术标签:
【中文标题】如何将自引用的复杂游标转换为更高效的 SQL 代码? CTE、交叉应用还是其他?【英文标题】:How to convert self-referencing complex Cursor to more efficient SQL code? CTE, CROSS-APPLY or something else? 【发布时间】:2017-03-14 15:24:54 【问题描述】:我有以下简化的表结构。实际上 Slot 将是标识,并且该表是在几行之前新生成的,因此该列没有间隙。
Slot SlotGroup EventNum ScheduleGroup
55 55 18 6
56 55 19 7
57 57 13 6
58 57 14 7
59 57 15 7
60 57 15 7
61 57 17 7
62 57 17 7
63 63 16 7
64 63 16 7
65 65 15 6
66 65 15 6
我需要遍历 MyTable 中的每条记录,并检查所有具有较小 Slot 的记录(在同一个 SlotGroup 内)是否具有相同的 ScheduleGroup 但不同的 EventNum:如果是这样,我应该在同一个 SlotGroup 中更新当前插槽之上的 Slot . 结果表应包含:
Slot SlotGroup EventNum ScheduleGroup
...
59 59 15 7
60 59 15 7
61 61 17 7
62 61 17 7
...
63 63 16 7
64 63 16 7
...
由于在两个 SlotGroups 中都有前一行具有相同的 ScheduleGroup 但不同的 EventNum。
我在考虑 CTE 或 CROSS APPLY,但现在我不知道如何开始;您能帮我找到正确的解决方案吗?
目前我使用的代码是这样的,但 MyTable 中可能有数百行,我觉得这不是解决问题的最有效方法。
数据:
DECLARE @MyTable TABLE (
Slot int --identity
, SlotGroup int NULL
, EventNum int NULL
, ScheduleGroup int
)
INSERT INTO @MyTable VALUES(55,55,18,6)
INSERT INTO @MyTable VALUES(56,55,19,7)
INSERT INTO @MyTable VALUES(57,57,13,6)
INSERT INTO @MyTable VALUES(58,57,14,7)
INSERT INTO @MyTable VALUES(59,57,15,7)
INSERT INTO @MyTable VALUES(60,57,15,7)
INSERT INTO @MyTable VALUES(61,61,14,6)
INSERT INTO @MyTable VALUES(62,61,15,7)
INSERT INTO @MyTable VALUES(63,61,16,7)
INSERT INTO @MyTable VALUES(64,61,16,7)
INSERT INTO @MyTable VALUES(65,65,15,6)
INSERT INTO @MyTable VALUES(66,65,15,6)
代码:
-- Go trhough each record in @MyTable and check if all records with a smaller Slot
--(within the same SlotGroup) have have the same ScheduleGroup but different EventNum.
-- If so do an update of the Slots above the current one (within the same SlotGroup)
DECLARE @nStartSlot int--Will be set later within the loop
DECLARE @nCurScheduleGroup int
DECLARE @nCurEventNum int
DECLARE @nCurSlotGroup int
DECLARE @nCurSlot int
DECLARE mtCur CURSOR FOR
SELECT ScheduleGroup, EventNum, SlotGroup, Slot FROM @MyTable
OPEN mtCur
FETCH NEXT FROM mtCur INTO @nCurScheduleGroup, @nCurEventNum, @nCurSlotGroup, @nCurSlot
WHILE @@FETCH_STATUS = 0
BEGIN
--Only the records with smaller Slot then the current one but within the same SlotGroup
--are interesting. therefore get the lowest Slot from the SAME SlotGroup.
--(important if the current records is in a new SlotGroup based on the time splitting)
IF NOT EXISTS (SELECT 1
FROM @MyTable mt
WHERE mt.Slot = ISNULL(@nStartSlot, 0)
AND mt.SlotGroup = @nCurSlotGroup
)
BEGIN
SELECT @nStartSlot = MIN(Slot)
FROM @MyTable mt
WHERE mt.SlotGroup = @nCurSlotGroup
END
--Update all records above the current records but within the same SlotGroup,
--if we find a new EventNum (but ScheduleGroup) in the current SlotGroup.
IF EXISTS (SELECT 1
FROM @MyTable mt
WHERE mt.Slot >= @nStartSlot
AND mt.Slot <= @nCurSlot
AND mt.ScheduleGroup = @nCurScheduleGroup
AND mt.EventNum != @nCurEventNum
)
BEGIN
UPDATE mt
SET SlotGroup = @nCurSlot
FROM @MyTable mt
WHERE mt.Slot >= @nCurSlot
AND mt.SlotGroup = @nCurSlotGroup
SELECT @nStartSlot = @nCurSlot
END
FETCH NEXT FROM mtCur INTO @nCurScheduleGroup, @nCurEventNum, @nCurSlotGroup, @nCurSlot
END
CLOSE mtCur
DEALLOCATE mtCur
--编辑-- 应转换的其他数据集
来源 1
Slot SlotGroup EventNum ScheduleGroup
16 13 3 778
17 17 10 778
18 17 10 778
19 17 9 778
20 17 9 778
结果 1
Slot SlotGroup EventNum ScheduleGroup
...
19 19 9 778
20 19 9 778
来源 2
Slot SlotGroup EventNum ScheduleGroup
39 39 10 778
40 39 10 778
41 39 9 778
42 39 10 778
结果 2
Slot SlotGroup EventNum ScheduleGroup
39 39 10 778
40 39 10 778
41 41 9 778
42 42 10 778
--编辑 2-- 应转换的其他数据集
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
8 8 1 978 8
9 8 2 978 9
10 8 2 977 9
11 8 2 977 9
12 8 1 977 12
13 8 2 978 12
14 8 1 978 14
15 8 2 978 15
16 8 1 978 16
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
17 17 1 331 17
18 17 1 331 17
19 17 1 331 17
20 17 1 331 17
21 17 1 331 17
22 17 1 331 17
23 17 1 331 17
24 17 1 330 17
25 17 1 330 17
26 17 1 330 17
27 17 1 330 17
28 17 1 330 17
29 17 1 330 17
30 17 1 330 17
31 17 2 330 31
32 17 2 330 31
33 17 2 330 31
34 17 2 330 31
35 17 2 330 31
36 17 2 330 31
37 17 2 330 31
38 17 2 331 31
39 17 2 331 31
40 17 2 331 31
41 17 2 331 31
42 17 2 331 31
43 17 2 331 31
44 17 2 331 31
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
32 32 2 492 32
33 32 6 492 33
34 32 5 492 34
35 32 6 492 35
36 32 6 492 35
37 32 6 492 35
38 32 6 493 35
39 32 6 492 35
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
219 219 18 065 219
220 219 16 065 220
221 219 1 246 220
222 219 16 065 220
223 219 18 065 223
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
39 39 10 113 39
40 39 9 113 40
41 39 10 112 40
42 39 9 112 42
43 39 1 241 42
44 39 2 241 44
45 39 2 241 44
46 39 1 241 46
47 39 1 241 46
48 39 2 241 48
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
46 46 14 184 46
47 46 14 183 46
48 46 14 183 46
49 46 1 184 49
50 46 15 183 49
51 46 15 183 49
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
148 148 6 725 148
149 148 5 725 149
150 148 5 725 149
151 148 6 725 151
152 148 6 723 151
153 148 6 724 151
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
150 150 2 221 150
151 150 1 221 151
152 150 2 221 152
153 150 2 221 152
154 150 1 222 152
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
122 122 3 462 122
123 122 2 462 123
124 122 2 463 123
125 122 2 463 123
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
36 36 10 617 36
37 36 9 617 37
38 36 10 618 37
39 36 9 618 39
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
97 97 22 091 97
98 97 22 091 97
99 97 21 091 99
100 97 22 091 100
101 97 14 092 100
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
108 108 22 463 108
109 108 23 460 108
110 108 23 460 108
111 108 22 461 108
112 108 22 461 108
113 113 21 462 113
114 113 21 462 113
115 113 22 463 113
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
156 156 11 462 156
157 156 10 462 157
158 156 10 463 157
159 156 10 463 157
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
20 20 8 283 20
21 21 7 283 21
22 22 9 283 22
23 23 8 283 23
24 24 11 283 24
25 25 10 283 25
26 26 12 283 26
27 26 11 283 27
28 26 4 282 27
29 26 4 282 27
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
105 105 2 418 105
106 106 1 418 106
107 106 1 418 106
108 108 2 418 108
109 106 1 418 109
110 106 1 418 109
111 108 2 418 111
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
57 57 13 776 57
58 57 14 777 57
59 57 15 777 59
60 57 15 777 59
61 61 14 776 61
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
9 9 3 771 9
10 9 3 771 9
11 9 3 771 9
12 9 3 771 9
13 9 1 772 9
14 9 1 772 9
Slot SlotGroup EventNum ScheduleGroup ExpectedSlotGroup
81 81 21 267 81
82 81 22 267 82
83 81 21 267 83
84 81 21 267 83
85 85 22 267 85
86 85 22 267 85
87 85 21 267 87
【问题讨论】:
在这里发布 ddl 和示例数据怎么样?否则没有人能真正提供帮助。 @SeanLange 不幸的是,这就是我所得到的,因为我正在尝试使一些旧的继承代码执行得更好 插槽组总是奇数有什么原因吗?或者当你更新时你会增加 2? @SqlZim 这只是完整数据的一个子集,我也出现过偶数,所以不要依赖这个:) @SqlZim SOURCE 1 我可以使用您的代码解决问题并将“或 NewSlotGroup != slotgroup”添加到最后一个 WHERE 条件 【参考方案1】:使用lead()
和lag()
;with cte as (
select *
, NewSlotGroup = min(slot) over (partition by testset, grp)
from (
select *, grp = sum(sgrp) over (partition by testset order by slot)
from (
select *, sgrp = case
when lag(eventnum) over (partition by testset order by slot) = eventnum
then 0
when lag(eventnum) over (partition by testset, slotgroup order by slot) <> eventnum
and lag(schedulegroup) over (partition by testset, slotgroup order by slot) <> schedulegroup
then 0
else 1
end
from t
) s
) g
)
update cte
set SlotGroup = NewSlotGroup
where SlotGroup != NewSlotGroup;
上述代码与您的新测试集之一冲突,(将光标移到此测试集上与我的结果匹配,而不是expectedslotgroup
。请解释为什么预期的插槽组在类似情况下没有变化时会发生变化其他测试集:
rextester 演示:http://rextester.com/ZOH27910
+---------+------+-----------+----------+---------------+-------------------+----------+
| TestSet | slot | slotgroup | eventnum | schedulegroup | expectedslotgroup | conflict |
+---------+------+-----------+----------+---------------+-------------------+----------+
| 6 | 46 | 46 | 14 | 184 | 46 | |
| 6 | 47 | 46 | 14 | 183 | 46 | |
| 6 | 48 | 46 | 14 | 183 | 46 | |
| 6 | 49 | 46 | 1 | 184 | 49 | X |
| 6 | 50 | 46 | 15 | 183 | 49 | X |
| 6 | 51 | 46 | 15 | 183 | 49 | X |
+---------+------+-----------+----------+---------------+-------------------+----------+
完整结果:
+---------+------+-----------+----------+---------------+-------------------+----------+
| TestSet | slot | slotgroup | eventnum | schedulegroup | expectedslotgroup | conflict |
+---------+------+-----------+----------+---------------+-------------------+----------+
| 1 | 8 | 8 | 1 | 978 | 8 | |
| 1 | 9 | 9 | 2 | 978 | 9 | |
| 1 | 10 | 9 | 2 | 977 | 9 | |
| 1 | 11 | 9 | 2 | 977 | 9 | |
| 1 | 12 | 12 | 1 | 977 | 12 | |
| 1 | 13 | 12 | 2 | 978 | 12 | |
| 1 | 14 | 14 | 1 | 978 | 14 | |
| 1 | 15 | 15 | 2 | 978 | 15 | |
| 1 | 16 | 16 | 1 | 978 | 16 | |
| 2 | 17 | 17 | 1 | 331 | 17 | |
| 2 | 18 | 17 | 1 | 331 | 17 | |
| 2 | 19 | 17 | 1 | 331 | 17 | |
| 2 | 20 | 17 | 1 | 331 | 17 | |
| 2 | 21 | 17 | 1 | 331 | 17 | |
| 2 | 22 | 17 | 1 | 331 | 17 | |
| 2 | 23 | 17 | 1 | 331 | 17 | |
| 2 | 24 | 17 | 1 | 330 | 17 | |
| 2 | 25 | 17 | 1 | 330 | 17 | |
| 2 | 26 | 17 | 1 | 330 | 17 | |
| 2 | 27 | 17 | 1 | 330 | 17 | |
| 2 | 28 | 17 | 1 | 330 | 17 | |
| 2 | 29 | 17 | 1 | 330 | 17 | |
| 2 | 30 | 17 | 1 | 330 | 17 | |
| 2 | 31 | 31 | 2 | 330 | 31 | |
| 2 | 32 | 31 | 2 | 330 | 31 | |
| 2 | 33 | 31 | 2 | 330 | 31 | |
| 2 | 34 | 31 | 2 | 330 | 31 | |
| 2 | 35 | 31 | 2 | 330 | 31 | |
| 2 | 36 | 31 | 2 | 330 | 31 | |
| 2 | 37 | 31 | 2 | 330 | 31 | |
| 2 | 38 | 31 | 2 | 331 | 31 | |
| 2 | 39 | 31 | 2 | 331 | 31 | |
| 2 | 40 | 31 | 2 | 331 | 31 | |
| 2 | 41 | 31 | 2 | 331 | 31 | |
| 2 | 42 | 31 | 2 | 331 | 31 | |
| 2 | 43 | 31 | 2 | 331 | 31 | |
| 2 | 44 | 31 | 2 | 331 | 31 | |
| 3 | 32 | 32 | 2 | 492 | 32 | |
| 3 | 33 | 33 | 6 | 492 | 33 | |
| 3 | 34 | 34 | 5 | 492 | 34 | |
| 3 | 35 | 35 | 6 | 492 | 35 | |
| 3 | 36 | 35 | 6 | 492 | 35 | |
| 3 | 37 | 35 | 6 | 492 | 35 | |
| 3 | 38 | 35 | 6 | 493 | 35 | |
| 3 | 39 | 35 | 6 | 492 | 35 | |
| 4 | 219 | 219 | 18 | 65 | 219 | |
| 4 | 220 | 220 | 16 | 65 | 220 | |
| 4 | 221 | 220 | 1 | 246 | 220 | |
| 4 | 222 | 220 | 16 | 65 | 220 | |
| 4 | 223 | 223 | 18 | 65 | 223 | |
| 5 | 39 | 39 | 10 | 113 | 39 | |
| 5 | 40 | 40 | 9 | 113 | 40 | |
| 5 | 41 | 40 | 10 | 112 | 40 | |
| 5 | 42 | 42 | 9 | 112 | 42 | |
| 5 | 43 | 42 | 1 | 241 | 42 | |
| 5 | 44 | 44 | 2 | 241 | 44 | |
| 5 | 45 | 44 | 2 | 241 | 44 | |
| 5 | 46 | 46 | 1 | 241 | 46 | |
| 5 | 47 | 46 | 1 | 241 | 46 | |
| 5 | 48 | 48 | 2 | 241 | 48 | |
| 6 | 46 | 46 | 14 | 184 | 46 | |
| 6 | 47 | 46 | 14 | 183 | 46 | |
| 6 | 48 | 46 | 14 | 183 | 46 | |
| 6 | 49 | 46 | 1 | 184 | 49 | X |
| 6 | 50 | 46 | 15 | 183 | 49 | X |
| 6 | 51 | 46 | 15 | 183 | 49 | X |
| 7 | 148 | 148 | 6 | 725 | 148 | |
| 7 | 149 | 149 | 5 | 725 | 149 | |
| 7 | 150 | 149 | 5 | 725 | 149 | |
| 7 | 151 | 151 | 6 | 725 | 151 | |
| 7 | 152 | 151 | 6 | 723 | 151 | |
| 7 | 153 | 151 | 6 | 724 | 151 | |
| 8 | 150 | 150 | 2 | 221 | 150 | |
| 8 | 151 | 151 | 1 | 221 | 151 | |
| 8 | 152 | 152 | 2 | 221 | 152 | |
| 8 | 153 | 152 | 2 | 221 | 152 | |
| 8 | 154 | 152 | 1 | 222 | 152 | |
| 9 | 122 | 122 | 3 | 462 | 122 | |
| 9 | 123 | 123 | 2 | 462 | 123 | |
| 9 | 124 | 123 | 2 | 463 | 123 | |
| 9 | 125 | 123 | 2 | 463 | 123 | |
| 10 | 36 | 36 | 10 | 617 | 36 | |
| 10 | 37 | 37 | 9 | 617 | 37 | |
| 10 | 38 | 37 | 10 | 618 | 37 | |
| 10 | 39 | 39 | 9 | 618 | 39 | |
| 11 | 97 | 97 | 22 | 91 | 97 | |
| 11 | 98 | 97 | 22 | 91 | 97 | |
| 11 | 99 | 99 | 21 | 91 | 99 | |
| 11 | 100 | 100 | 22 | 91 | 100 | |
| 11 | 101 | 100 | 14 | 92 | 100 | |
| 12 | 108 | 108 | 22 | 463 | 108 | |
| 12 | 109 | 108 | 23 | 460 | 108 | |
| 12 | 110 | 108 | 23 | 460 | 108 | |
| 12 | 111 | 108 | 22 | 461 | 108 | |
| 12 | 112 | 108 | 22 | 461 | 108 | |
| 12 | 113 | 113 | 21 | 462 | 113 | |
| 12 | 114 | 113 | 21 | 462 | 113 | |
| 12 | 115 | 113 | 22 | 463 | 113 | |
| 13 | 156 | 156 | 11 | 462 | 156 | |
| 13 | 157 | 157 | 10 | 462 | 157 | |
| 13 | 158 | 157 | 10 | 463 | 157 | |
| 13 | 159 | 157 | 10 | 463 | 157 | |
| 14 | 20 | 20 | 8 | 283 | 20 | |
| 14 | 21 | 21 | 7 | 283 | 21 | |
| 14 | 22 | 22 | 9 | 283 | 22 | |
| 14 | 23 | 23 | 8 | 283 | 23 | |
| 14 | 24 | 24 | 11 | 283 | 24 | |
| 14 | 25 | 25 | 10 | 283 | 25 | |
| 14 | 26 | 26 | 12 | 283 | 26 | |
| 14 | 27 | 27 | 11 | 283 | 27 | |
| 14 | 28 | 27 | 4 | 282 | 27 | |
| 14 | 29 | 27 | 4 | 282 | 27 | |
| 15 | 105 | 105 | 2 | 418 | 105 | |
| 15 | 106 | 106 | 1 | 418 | 106 | |
| 15 | 107 | 106 | 1 | 418 | 106 | |
| 15 | 108 | 108 | 2 | 418 | 108 | |
| 15 | 109 | 109 | 1 | 418 | 109 | |
| 15 | 110 | 109 | 1 | 418 | 109 | |
| 15 | 111 | 111 | 2 | 418 | 111 | |
| 16 | 57 | 57 | 13 | 776 | 57 | |
| 16 | 58 | 57 | 14 | 777 | 57 | |
| 16 | 59 | 59 | 15 | 777 | 59 | |
| 16 | 60 | 59 | 15 | 777 | 59 | |
| 16 | 61 | 61 | 14 | 776 | 61 | |
| 17 | 9 | 9 | 3 | 771 | 9 | |
| 17 | 10 | 9 | 3 | 771 | 9 | |
| 17 | 11 | 9 | 3 | 771 | 9 | |
| 17 | 12 | 9 | 3 | 771 | 9 | |
| 17 | 13 | 9 | 1 | 772 | 9 | |
| 17 | 14 | 9 | 1 | 772 | 9 | |
| 18 | 81 | 81 | 21 | 267 | 81 | |
| 18 | 82 | 82 | 22 | 267 | 82 | |
| 18 | 83 | 83 | 21 | 267 | 83 | |
| 18 | 84 | 83 | 21 | 267 | 83 | |
| 18 | 85 | 85 | 22 | 267 | 85 | |
| 18 | 86 | 85 | 22 | 267 | 85 | |
| 18 | 87 | 87 | 21 | 267 | 87 | |
+---------+------+-----------+----------+---------------+-------------------+----------+
【讨论】:
谢谢,非常有趣,但有一个明显的小错误:Slot 59 & 60 应该有 SlotGroup 59 而不是 58,Slot 63 & 64 也是如此。此外,它在更复杂的情况下会失败(多个在同一个 SlotGroup 中跳转)。这似乎是我正在寻找的正确方向,让我们看看我们是否可以让它完美地工作:) @Simone 更新了我的答案,感谢您的澄清。 我仍在努力,但不幸的是,您的解决方案并不完全正确;至少有两种组合仍然存在问题;请检查我编辑的问题 对不起,但我担心这不正确:插槽 42 仍然有插槽组 39,而我的要求是将其设置为 42。我错过了什么吗? 我按照您的提示进行操作,但仍有一些极端情况 :(,添加了它们以上是关于如何将自引用的复杂游标转换为更高效的 SQL 代码? CTE、交叉应用还是其他?的主要内容,如果未能解决你的问题,请参考以下文章