计算没有间隙的岛屿的大小
Count size of islands with no gaps
我的数据有 3 列; ID、名称、值
ID 是像行数一样的序号
我在数据中显示了 3 个不同的名称,但可能有 10 个以上
有 2 个 VALUE
我想以 'local' 方式对 NAME 和 VALUE 进行分组,return 这些 'local' 组的大小。这似乎是 Islands and Gaps 场景的一个版本,但没有重复值的 Gaps and Islands。我已经尝试了各种解决 Islands and Gaps 的方法,但到目前为止,没有真正的进展。
我尝试部分解决方案的失败尝试之一(Itzik Ben-Gan 的工作变体):
WITH A
AS (SELECT ROW_NUMBER() OVER (ORDER BY id) RN,
NAME,
VALUE
FROM #data
WHERE NAME LIKE '%Joe%'),
T
AS (
SELECT ROW_NUMBER() OVER (ORDER BY RN) - RN AS Grp,
RN
FROM A
WHERE VALUE = 0)
SELECT MIN(T.RN) AS [From],
MAX(T.RN) AS [To],
MAX(T.RN) - MIN(T.RN) AS [Length]
FROM T
GROUP BY Grp
ORDER BY MIN(T.RN);
输出如下:
NAME
VALUE
Count
Joe
0
15
Joe
1
3
Joe
0
5
Joe
1
19
Sue
1
23
Sue
0
17
Sue
1
4
Mary
0
16
Mary
1
10
Mary
0
7
Mary
1
19
Mary
0
3
数据是这样的:
ID
NAME
VALUE
1
Joe
0
2
Joe
0
3
Joe
0
4
Joe
0
5
Joe
0
6
Joe
0
7
Joe
0
8
Joe
0
9
Joe
0
10
Joe
0
11
Sue
1
12
Sue
1
13
Sue
1
14
Sue
1
15
Sue
1
16
Sue
1
17
Sue
1
18
Sue
1
19
Sue
1
20
Sue
1
21
Sue
1
22
Sue
1
23
Sue
1
24
Sue
1
25
Sue
1
26
Sue
1
27
Mary
0
28
Mary
0
29
Mary
0
30
Mary
0
31
Mary
0
32
Mary
0
33
Mary
0
34
Mary
0
35
Joe
0
36
Joe
0
37
Joe
0
38
Joe
0
39
Joe
0
40
Joe
1
41
Joe
1
42
Joe
1
43
Joe
0
44
Joe
0
45
Joe
0
46
Joe
0
47
Joe
0
48
Joe
1
49
Joe
1
50
Mary
0
51
Mary
0
52
Mary
0
53
Mary
0
54
Mary
0
55
Mary
0
56
Mary
0
57
Mary
0
58
Mary
1
59
Mary
1
60
Mary
1
61
Mary
1
62
Mary
1
63
Mary
1
64
Mary
1
65
Mary
1
66
Mary
1
67
Mary
1
68
Mary
0
69
Sue
1
70
Sue
1
71
Sue
1
72
Sue
1
73
Sue
1
74
Sue
1
75
Sue
1
76
Sue
0
77
Sue
0
78
Sue
0
79
Sue
0
80
Sue
0
81
Sue
0
82
Sue
0
83
Sue
0
84
Mary
0
85
Mary
0
86
Mary
0
87
Mary
0
88
Mary
0
89
Mary
0
90
Mary
1
91
Mary
1
92
Mary
1
93
Mary
1
94
Mary
1
95
Mary
1
96
Mary
1
97
Mary
1
98
Mary
1
99
Mary
1
100
Mary
1
101
Sue
0
102
Sue
0
103
Sue
0
104
Sue
0
105
Sue
0
106
Sue
0
107
Sue
0
108
Sue
0
109
Sue
0
110
Sue
1
111
Sue
1
112
Sue
1
113
Sue
1
114
Joe
1
115
Joe
1
116
Joe
1
117
Joe
1
118
Joe
1
119
Joe
1
120
Joe
1
121
Joe
1
122
Joe
1
123
Joe
1
124
Mary
1
125
Mary
1
126
Mary
1
127
Mary
1
128
Mary
1
129
Mary
1
130
Mary
1
131
Mary
1
132
Mary
0
133
Mary
0
134
Mary
0
135
Joe
1
136
Joe
1
137
Joe
1
138
Joe
1
139
Joe
1
140
Joe
1
141
Joe
1
DROP TABLE IF EXISTS #data;
CREATE TABLE #data
(
ID INT,
NAME VARCHAR(50),
VALUE INT
);
INSERT INTO #data values
(1 ,'Joe', 0 ),
(2 ,'Joe', 0 ),
(3 ,'Joe', 0 ),
(4 ,'Joe', 0 ),
(5 ,'Joe', 0 ),
(6 ,'Joe', 0 ),
(7 ,'Joe', 0 ),
(8 ,'Joe', 0 ),
(9 ,'Joe', 0 ),
(10 ,'Joe', 0 ),
(11 ,'Sue', 1 ),
(12 ,'Sue', 1 ),
(13 ,'Sue', 1 ),
(14 ,'Sue', 1 ),
(15 ,'Sue', 1 ),
(16 ,'Sue', 1 ),
(17 ,'Sue', 1 ),
(18 ,'Sue', 1 ),
(19 ,'Sue', 1 ),
(20 ,'Sue', 1 ),
(21 ,'Sue', 1 ),
(22 ,'Sue', 1 ),
(23 ,'Sue', 1 ),
(24 ,'Sue', 1 ),
(25 ,'Sue', 1 ),
(26 ,'Sue', 1 ),
(27 ,'Mary', 0 ),
(28 ,'Mary', 0 ),
(29 ,'Mary', 0 ),
(30 ,'Mary', 0 ),
(31 ,'Mary', 0 ),
(32 ,'Mary', 0 ),
(33 ,'Mary', 0 ),
(34 ,'Mary', 0 ),
(35 ,'Joe', 0 ),
(36 ,'Joe', 0 ),
(37 ,'Joe', 0 ),
(38 ,'Joe', 0 ),
(39 ,'Joe', 0 ),
(40 ,'Joe', 1 ),
(41 ,'Joe', 1 ),
(42 ,'Joe', 1 ),
(43 ,'Joe', 0 ),
(44 ,'Joe', 0 ),
(45 ,'Joe', 0 ),
(46 ,'Joe', 0 ),
(47 ,'Joe', 0 ),
(48 ,'Joe', 1 ),
(49 ,'Joe', 1 ),
(50 ,'Mary', 0 ),
(51 ,'Mary', 0 ),
(52 ,'Mary', 0 ),
(53 ,'Mary', 0 ),
(54 ,'Mary', 0 ),
(55 ,'Mary', 0 ),
(56 ,'Mary', 0 ),
(57 ,'Mary', 0 ),
(58 ,'Mary', 1 ),
(59 ,'Mary', 1 ),
(60 ,'Mary', 1 ),
(61 ,'Mary', 1 ),
(62 ,'Mary', 1 ),
(63 ,'Mary', 1 ),
(64 ,'Mary', 1 ),
(65 ,'Mary', 1 ),
(66 ,'Mary', 1 ),
(67 ,'Mary', 1 ),
(68 ,'Mary', 0 ),
(69 ,'Sue', 1 ),
(70 ,'Sue', 1 ),
(71 ,'Sue', 1 ),
(72 ,'Sue', 1 ),
(73 ,'Sue', 1 ),
(74 ,'Sue', 1 ),
(75 ,'Sue', 1 ),
(76 ,'Sue', 0 ),
(77 ,'Sue', 0 ),
(78 ,'Sue', 0 ),
(79 ,'Sue', 0 ),
(80 ,'Sue', 0 ),
(81 ,'Sue', 0 ),
(82 ,'Sue', 0 ),
(83 ,'Sue', 0 ),
(84 ,'Mary', 0 ),
(85 ,'Mary', 0 ),
(86 ,'Mary', 0 ),
(87 ,'Mary', 0 ),
(88 ,'Mary', 0 ),
(89 ,'Mary', 0 ),
(90 ,'Mary', 1 ),
(91 ,'Mary', 1 ),
(92 ,'Mary', 1 ),
(93 ,'Mary', 1 ),
(94 ,'Mary', 1 ),
(95 ,'Mary', 1 ),
(96 ,'Mary', 1 ),
(97 ,'Mary', 1 ),
(98 ,'Mary', 1 ),
(99 ,'Mary', 1 ),
(100 ,'Mary', 1),
(101 ,'Sue', 0),
(102 ,'Sue', 0),
(103 ,'Sue', 0),
(104 ,'Sue', 0),
(105 ,'Sue', 0),
(106 ,'Sue', 0),
(107 ,'Sue', 0),
(108 ,'Sue', 0),
(109 ,'Sue', 0),
(110 ,'Sue', 1),
(111 ,'Sue', 1),
(112 ,'Sue', 1),
(113 ,'Sue', 1),
(114 ,'Joe', 1),
(115 ,'Joe', 1),
(116 ,'Joe', 1),
(117 ,'Joe', 1),
(118 ,'Joe', 1),
(119 ,'Joe', 1),
(120 ,'Joe', 1),
(121 ,'Joe', 1),
(122 ,'Joe', 1),
(123 ,'Joe', 1),
(124 ,'Mary', 1),
(125 ,'Mary', 1),
(126 ,'Mary', 1),
(127 ,'Mary', 1),
(128 ,'Mary', 1),
(129 ,'Mary', 1),
(130 ,'Mary', 1),
(131 ,'Mary', 1),
(132 ,'Mary', 0),
(133 ,'Mary', 0),
(134 ,'Mary', 0),
(135 ,'Joe', 1),
(136 ,'Joe', 1),
(137 ,'Joe', 1),
(138 ,'Joe', 1),
(139 ,'Joe', 1),
(140 ,'Joe', 1),
(141 ,'Joe', 1);
-- first find the changes
WITH breaks AS
(
SELECT ID, NAME, VALUE,
IIF(LAG(VALUE, 1) OVER (PARTITION BY Name ORDER BY ID) != VALUE, 1, 0) AS NewGrp
FROM #data
),
-- then count how many breaks we have passed
grouped AS
(
SELECT ID, NAME, VALUE, SUM(NewGrp) OVER (PARTITION BY Name ORDER BY ID) grp
FROM breaks
)
-- group by that count
SELECT NAME, VALUE, COUNT(*)
FROM grouped
GROUP BY NAME, VALUE, grp
ORDER BY NAME, MIN(ID)
我的数据有 3 列; ID、名称、值 ID 是像行数一样的序号 我在数据中显示了 3 个不同的名称,但可能有 10 个以上 有 2 个 VALUE
我想以 'local' 方式对 NAME 和 VALUE 进行分组,return 这些 'local' 组的大小。这似乎是 Islands and Gaps 场景的一个版本,但没有重复值的 Gaps and Islands。我已经尝试了各种解决 Islands and Gaps 的方法,但到目前为止,没有真正的进展。
我尝试部分解决方案的失败尝试之一(Itzik Ben-Gan 的工作变体):
WITH A
AS (SELECT ROW_NUMBER() OVER (ORDER BY id) RN,
NAME,
VALUE
FROM #data
WHERE NAME LIKE '%Joe%'),
T
AS (
SELECT ROW_NUMBER() OVER (ORDER BY RN) - RN AS Grp,
RN
FROM A
WHERE VALUE = 0)
SELECT MIN(T.RN) AS [From],
MAX(T.RN) AS [To],
MAX(T.RN) - MIN(T.RN) AS [Length]
FROM T
GROUP BY Grp
ORDER BY MIN(T.RN);
输出如下:
NAME | VALUE | Count |
---|---|---|
Joe | 0 | 15 |
Joe | 1 | 3 |
Joe | 0 | 5 |
Joe | 1 | 19 |
Sue | 1 | 23 |
Sue | 0 | 17 |
Sue | 1 | 4 |
Mary | 0 | 16 |
Mary | 1 | 10 |
Mary | 0 | 7 |
Mary | 1 | 19 |
Mary | 0 | 3 |
数据是这样的:
ID | NAME | VALUE |
---|---|---|
1 | Joe | 0 |
2 | Joe | 0 |
3 | Joe | 0 |
4 | Joe | 0 |
5 | Joe | 0 |
6 | Joe | 0 |
7 | Joe | 0 |
8 | Joe | 0 |
9 | Joe | 0 |
10 | Joe | 0 |
11 | Sue | 1 |
12 | Sue | 1 |
13 | Sue | 1 |
14 | Sue | 1 |
15 | Sue | 1 |
16 | Sue | 1 |
17 | Sue | 1 |
18 | Sue | 1 |
19 | Sue | 1 |
20 | Sue | 1 |
21 | Sue | 1 |
22 | Sue | 1 |
23 | Sue | 1 |
24 | Sue | 1 |
25 | Sue | 1 |
26 | Sue | 1 |
27 | Mary | 0 |
28 | Mary | 0 |
29 | Mary | 0 |
30 | Mary | 0 |
31 | Mary | 0 |
32 | Mary | 0 |
33 | Mary | 0 |
34 | Mary | 0 |
35 | Joe | 0 |
36 | Joe | 0 |
37 | Joe | 0 |
38 | Joe | 0 |
39 | Joe | 0 |
40 | Joe | 1 |
41 | Joe | 1 |
42 | Joe | 1 |
43 | Joe | 0 |
44 | Joe | 0 |
45 | Joe | 0 |
46 | Joe | 0 |
47 | Joe | 0 |
48 | Joe | 1 |
49 | Joe | 1 |
50 | Mary | 0 |
51 | Mary | 0 |
52 | Mary | 0 |
53 | Mary | 0 |
54 | Mary | 0 |
55 | Mary | 0 |
56 | Mary | 0 |
57 | Mary | 0 |
58 | Mary | 1 |
59 | Mary | 1 |
60 | Mary | 1 |
61 | Mary | 1 |
62 | Mary | 1 |
63 | Mary | 1 |
64 | Mary | 1 |
65 | Mary | 1 |
66 | Mary | 1 |
67 | Mary | 1 |
68 | Mary | 0 |
69 | Sue | 1 |
70 | Sue | 1 |
71 | Sue | 1 |
72 | Sue | 1 |
73 | Sue | 1 |
74 | Sue | 1 |
75 | Sue | 1 |
76 | Sue | 0 |
77 | Sue | 0 |
78 | Sue | 0 |
79 | Sue | 0 |
80 | Sue | 0 |
81 | Sue | 0 |
82 | Sue | 0 |
83 | Sue | 0 |
84 | Mary | 0 |
85 | Mary | 0 |
86 | Mary | 0 |
87 | Mary | 0 |
88 | Mary | 0 |
89 | Mary | 0 |
90 | Mary | 1 |
91 | Mary | 1 |
92 | Mary | 1 |
93 | Mary | 1 |
94 | Mary | 1 |
95 | Mary | 1 |
96 | Mary | 1 |
97 | Mary | 1 |
98 | Mary | 1 |
99 | Mary | 1 |
100 | Mary | 1 |
101 | Sue | 0 |
102 | Sue | 0 |
103 | Sue | 0 |
104 | Sue | 0 |
105 | Sue | 0 |
106 | Sue | 0 |
107 | Sue | 0 |
108 | Sue | 0 |
109 | Sue | 0 |
110 | Sue | 1 |
111 | Sue | 1 |
112 | Sue | 1 |
113 | Sue | 1 |
114 | Joe | 1 |
115 | Joe | 1 |
116 | Joe | 1 |
117 | Joe | 1 |
118 | Joe | 1 |
119 | Joe | 1 |
120 | Joe | 1 |
121 | Joe | 1 |
122 | Joe | 1 |
123 | Joe | 1 |
124 | Mary | 1 |
125 | Mary | 1 |
126 | Mary | 1 |
127 | Mary | 1 |
128 | Mary | 1 |
129 | Mary | 1 |
130 | Mary | 1 |
131 | Mary | 1 |
132 | Mary | 0 |
133 | Mary | 0 |
134 | Mary | 0 |
135 | Joe | 1 |
136 | Joe | 1 |
137 | Joe | 1 |
138 | Joe | 1 |
139 | Joe | 1 |
140 | Joe | 1 |
141 | Joe | 1 |
DROP TABLE IF EXISTS #data;
CREATE TABLE #data
(
ID INT,
NAME VARCHAR(50),
VALUE INT
);
INSERT INTO #data values
(1 ,'Joe', 0 ),
(2 ,'Joe', 0 ),
(3 ,'Joe', 0 ),
(4 ,'Joe', 0 ),
(5 ,'Joe', 0 ),
(6 ,'Joe', 0 ),
(7 ,'Joe', 0 ),
(8 ,'Joe', 0 ),
(9 ,'Joe', 0 ),
(10 ,'Joe', 0 ),
(11 ,'Sue', 1 ),
(12 ,'Sue', 1 ),
(13 ,'Sue', 1 ),
(14 ,'Sue', 1 ),
(15 ,'Sue', 1 ),
(16 ,'Sue', 1 ),
(17 ,'Sue', 1 ),
(18 ,'Sue', 1 ),
(19 ,'Sue', 1 ),
(20 ,'Sue', 1 ),
(21 ,'Sue', 1 ),
(22 ,'Sue', 1 ),
(23 ,'Sue', 1 ),
(24 ,'Sue', 1 ),
(25 ,'Sue', 1 ),
(26 ,'Sue', 1 ),
(27 ,'Mary', 0 ),
(28 ,'Mary', 0 ),
(29 ,'Mary', 0 ),
(30 ,'Mary', 0 ),
(31 ,'Mary', 0 ),
(32 ,'Mary', 0 ),
(33 ,'Mary', 0 ),
(34 ,'Mary', 0 ),
(35 ,'Joe', 0 ),
(36 ,'Joe', 0 ),
(37 ,'Joe', 0 ),
(38 ,'Joe', 0 ),
(39 ,'Joe', 0 ),
(40 ,'Joe', 1 ),
(41 ,'Joe', 1 ),
(42 ,'Joe', 1 ),
(43 ,'Joe', 0 ),
(44 ,'Joe', 0 ),
(45 ,'Joe', 0 ),
(46 ,'Joe', 0 ),
(47 ,'Joe', 0 ),
(48 ,'Joe', 1 ),
(49 ,'Joe', 1 ),
(50 ,'Mary', 0 ),
(51 ,'Mary', 0 ),
(52 ,'Mary', 0 ),
(53 ,'Mary', 0 ),
(54 ,'Mary', 0 ),
(55 ,'Mary', 0 ),
(56 ,'Mary', 0 ),
(57 ,'Mary', 0 ),
(58 ,'Mary', 1 ),
(59 ,'Mary', 1 ),
(60 ,'Mary', 1 ),
(61 ,'Mary', 1 ),
(62 ,'Mary', 1 ),
(63 ,'Mary', 1 ),
(64 ,'Mary', 1 ),
(65 ,'Mary', 1 ),
(66 ,'Mary', 1 ),
(67 ,'Mary', 1 ),
(68 ,'Mary', 0 ),
(69 ,'Sue', 1 ),
(70 ,'Sue', 1 ),
(71 ,'Sue', 1 ),
(72 ,'Sue', 1 ),
(73 ,'Sue', 1 ),
(74 ,'Sue', 1 ),
(75 ,'Sue', 1 ),
(76 ,'Sue', 0 ),
(77 ,'Sue', 0 ),
(78 ,'Sue', 0 ),
(79 ,'Sue', 0 ),
(80 ,'Sue', 0 ),
(81 ,'Sue', 0 ),
(82 ,'Sue', 0 ),
(83 ,'Sue', 0 ),
(84 ,'Mary', 0 ),
(85 ,'Mary', 0 ),
(86 ,'Mary', 0 ),
(87 ,'Mary', 0 ),
(88 ,'Mary', 0 ),
(89 ,'Mary', 0 ),
(90 ,'Mary', 1 ),
(91 ,'Mary', 1 ),
(92 ,'Mary', 1 ),
(93 ,'Mary', 1 ),
(94 ,'Mary', 1 ),
(95 ,'Mary', 1 ),
(96 ,'Mary', 1 ),
(97 ,'Mary', 1 ),
(98 ,'Mary', 1 ),
(99 ,'Mary', 1 ),
(100 ,'Mary', 1),
(101 ,'Sue', 0),
(102 ,'Sue', 0),
(103 ,'Sue', 0),
(104 ,'Sue', 0),
(105 ,'Sue', 0),
(106 ,'Sue', 0),
(107 ,'Sue', 0),
(108 ,'Sue', 0),
(109 ,'Sue', 0),
(110 ,'Sue', 1),
(111 ,'Sue', 1),
(112 ,'Sue', 1),
(113 ,'Sue', 1),
(114 ,'Joe', 1),
(115 ,'Joe', 1),
(116 ,'Joe', 1),
(117 ,'Joe', 1),
(118 ,'Joe', 1),
(119 ,'Joe', 1),
(120 ,'Joe', 1),
(121 ,'Joe', 1),
(122 ,'Joe', 1),
(123 ,'Joe', 1),
(124 ,'Mary', 1),
(125 ,'Mary', 1),
(126 ,'Mary', 1),
(127 ,'Mary', 1),
(128 ,'Mary', 1),
(129 ,'Mary', 1),
(130 ,'Mary', 1),
(131 ,'Mary', 1),
(132 ,'Mary', 0),
(133 ,'Mary', 0),
(134 ,'Mary', 0),
(135 ,'Joe', 1),
(136 ,'Joe', 1),
(137 ,'Joe', 1),
(138 ,'Joe', 1),
(139 ,'Joe', 1),
(140 ,'Joe', 1),
(141 ,'Joe', 1);
-- first find the changes
WITH breaks AS
(
SELECT ID, NAME, VALUE,
IIF(LAG(VALUE, 1) OVER (PARTITION BY Name ORDER BY ID) != VALUE, 1, 0) AS NewGrp
FROM #data
),
-- then count how many breaks we have passed
grouped AS
(
SELECT ID, NAME, VALUE, SUM(NewGrp) OVER (PARTITION BY Name ORDER BY ID) grp
FROM breaks
)
-- group by that count
SELECT NAME, VALUE, COUNT(*)
FROM grouped
GROUP BY NAME, VALUE, grp
ORDER BY NAME, MIN(ID)