SQL 中的序列编号
Sequence Numbering in SQL
我有特定事件的活动列表(A 开始到 H 结束)。这些可以以任何顺序、任意次数发生,也可以重新启动。我需要确定事件中的活动块。
例如:A B C D E F G H B C D H C D E F H E F G H
只开始一次(A)但结束多次
需要对这些活动进行编号以识别集合(结束了多少次)
output: 1 1 1 1 1 1 1 2 2 2 2 3 3 3 3 3 4 4 4 4 5
这有助于我确定事件结束 (H) 5-1 = 4 次
您似乎想要计算给定值之前的 "H" 和 "A" 的数量。这需要有一个指定顺序的列。假设此列名为 id
.
然后,您可以使用 window 函数执行此操作:
select t.*,
sum(case when col = 'H' then 1 else 0 end) over (partition by grp order by id) + 1 as output
from (select t.*,
sum(case when col = 'A' then 1 else 0 end) over (order by id) as grp
from t
) t;
子查询通过累加 "A" 来定义 "activity" 组。然后,外部查询通过计算 "E"s.
的累加和来定义 "event" 组
老实说,我分不清 "H" 是前一个值还是下一个值的一部分。如果是下一个值,则查询可以使用 window 子句或对逻辑稍作调整:
(sum(case when col = 'H' then 1 else 0 end) over (partition by grp order by id) +
(case when col = 'H' then 0 else 1 end)
) as output
如果您的事件是时间上的一系列事件 - 尝试使用 MATCH()
子句及其相关函数 event_name()
、pattern_id()
和 match_id()
。
我刚刚根据您输入的字母创建了一个时间序列,以一小时为间隔,并应用了 MATCH()
子句。如果 PATTERN pat AS ()
子句不可思议地让您想起 grep
表达式,那就是它的工作方式。
只要看看查询的输出 - 想象一下您可以使用 pattern_id
-s 和 match_id
-s 做多少有趣的事情 - 按它们分组,例如,在随后的 SELECT-s ...
WITH
s(tm,event) AS (
SELECT TIME '00:00:00','A'
UNION ALL SELECT TIME '01:00:00','B'
UNION ALL SELECT TIME '02:00:00','C'
UNION ALL SELECT TIME '03:00:00','D'
UNION ALL SELECT TIME '04:00:00','E'
UNION ALL SELECT TIME '05:00:00','F'
UNION ALL SELECT TIME '06:00:00','G'
UNION ALL SELECT TIME '07:00:00','H'
UNION ALL SELECT TIME '08:00:00','B'
UNION ALL SELECT TIME '09:00:00','C'
UNION ALL SELECT TIME '10:00:00','D'
UNION ALL SELECT TIME '11:00:00','H'
UNION ALL SELECT TIME '12:00:00','C'
UNION ALL SELECT TIME '13:00:00','D'
UNION ALL SELECT TIME '14:00:00','E'
UNION ALL SELECT TIME '15:00:00','F'
UNION ALL SELECT TIME '16:00:00','H'
UNION ALL SELECT TIME '17:00:00','E'
UNION ALL SELECT TIME '18:00:00','F'
UNION ALL SELECT TIME '19:00:00','G'
UNION ALL SELECT TIME '20:00:00','H'
)
SELECT
*
, event_name()
, pattern_id()
, match_id()
FROM s
MATCH(
PARTITION BY 1 -- nothing to partition by
ORDER BY tm
DEFINE
START_ev AS (event='A')
, any_ev AS (event NOT IN ('A','H'))
, END_ev AS (event='H')
PATTERN pat AS (start_ev* any_ev+ end_ev)
ROWS MATCH FIRST EVENT
);
tm |event|event_name|pattern_id|match_id
00:00:00|A |START_ev | 1| 1
01:00:00|B |any_ev | 1| 2
02:00:00|C |any_ev | 1| 3
03:00:00|D |any_ev | 1| 4
04:00:00|E |any_ev | 1| 5
05:00:00|F |any_ev | 1| 6
06:00:00|G |any_ev | 1| 7
07:00:00|H |END_ev | 1| 8
08:00:00|B |any_ev | 2| 1
09:00:00|C |any_ev | 2| 2
10:00:00|D |any_ev | 2| 3
11:00:00|H |END_ev | 2| 4
12:00:00|C |any_ev | 3| 1
13:00:00|D |any_ev | 3| 2
14:00:00|E |any_ev | 3| 3
15:00:00|F |any_ev | 3| 4
16:00:00|H |END_ev | 3| 5
17:00:00|E |any_ev | 4| 1
18:00:00|F |any_ev | 4| 2
19:00:00|G |any_ev | 4| 3
20:00:00|H |END_ev | 4| 4
我有特定事件的活动列表(A 开始到 H 结束)。这些可以以任何顺序、任意次数发生,也可以重新启动。我需要确定事件中的活动块。
例如:A B C D E F G H B C D H C D E F H E F G H
只开始一次(A)但结束多次
需要对这些活动进行编号以识别集合(结束了多少次)
output: 1 1 1 1 1 1 1 2 2 2 2 3 3 3 3 3 4 4 4 4 5
这有助于我确定事件结束 (H) 5-1 = 4 次
您似乎想要计算给定值之前的 "H" 和 "A" 的数量。这需要有一个指定顺序的列。假设此列名为 id
.
然后,您可以使用 window 函数执行此操作:
select t.*,
sum(case when col = 'H' then 1 else 0 end) over (partition by grp order by id) + 1 as output
from (select t.*,
sum(case when col = 'A' then 1 else 0 end) over (order by id) as grp
from t
) t;
子查询通过累加 "A" 来定义 "activity" 组。然后,外部查询通过计算 "E"s.
的累加和来定义 "event" 组老实说,我分不清 "H" 是前一个值还是下一个值的一部分。如果是下一个值,则查询可以使用 window 子句或对逻辑稍作调整:
(sum(case when col = 'H' then 1 else 0 end) over (partition by grp order by id) +
(case when col = 'H' then 0 else 1 end)
) as output
如果您的事件是时间上的一系列事件 - 尝试使用 MATCH()
子句及其相关函数 event_name()
、pattern_id()
和 match_id()
。
我刚刚根据您输入的字母创建了一个时间序列,以一小时为间隔,并应用了 MATCH()
子句。如果 PATTERN pat AS ()
子句不可思议地让您想起 grep
表达式,那就是它的工作方式。
只要看看查询的输出 - 想象一下您可以使用 pattern_id
-s 和 match_id
-s 做多少有趣的事情 - 按它们分组,例如,在随后的 SELECT-s ...
WITH
s(tm,event) AS (
SELECT TIME '00:00:00','A'
UNION ALL SELECT TIME '01:00:00','B'
UNION ALL SELECT TIME '02:00:00','C'
UNION ALL SELECT TIME '03:00:00','D'
UNION ALL SELECT TIME '04:00:00','E'
UNION ALL SELECT TIME '05:00:00','F'
UNION ALL SELECT TIME '06:00:00','G'
UNION ALL SELECT TIME '07:00:00','H'
UNION ALL SELECT TIME '08:00:00','B'
UNION ALL SELECT TIME '09:00:00','C'
UNION ALL SELECT TIME '10:00:00','D'
UNION ALL SELECT TIME '11:00:00','H'
UNION ALL SELECT TIME '12:00:00','C'
UNION ALL SELECT TIME '13:00:00','D'
UNION ALL SELECT TIME '14:00:00','E'
UNION ALL SELECT TIME '15:00:00','F'
UNION ALL SELECT TIME '16:00:00','H'
UNION ALL SELECT TIME '17:00:00','E'
UNION ALL SELECT TIME '18:00:00','F'
UNION ALL SELECT TIME '19:00:00','G'
UNION ALL SELECT TIME '20:00:00','H'
)
SELECT
*
, event_name()
, pattern_id()
, match_id()
FROM s
MATCH(
PARTITION BY 1 -- nothing to partition by
ORDER BY tm
DEFINE
START_ev AS (event='A')
, any_ev AS (event NOT IN ('A','H'))
, END_ev AS (event='H')
PATTERN pat AS (start_ev* any_ev+ end_ev)
ROWS MATCH FIRST EVENT
);
tm |event|event_name|pattern_id|match_id
00:00:00|A |START_ev | 1| 1
01:00:00|B |any_ev | 1| 2
02:00:00|C |any_ev | 1| 3
03:00:00|D |any_ev | 1| 4
04:00:00|E |any_ev | 1| 5
05:00:00|F |any_ev | 1| 6
06:00:00|G |any_ev | 1| 7
07:00:00|H |END_ev | 1| 8
08:00:00|B |any_ev | 2| 1
09:00:00|C |any_ev | 2| 2
10:00:00|D |any_ev | 2| 3
11:00:00|H |END_ev | 2| 4
12:00:00|C |any_ev | 3| 1
13:00:00|D |any_ev | 3| 2
14:00:00|E |any_ev | 3| 3
15:00:00|F |any_ev | 3| 4
16:00:00|H |END_ev | 3| 5
17:00:00|E |any_ev | 4| 1
18:00:00|F |any_ev | 4| 2
19:00:00|G |any_ev | 4| 3
20:00:00|H |END_ev | 4| 4