基于Status列添加rownum:统计CLOSED前的CANCELLED次数
如何修正SQL查询实现特定的rownum统计逻辑?
需求说明
现有包含id、time、status列的表,需添加rownum字段,规则如下:
CANCELLED状态的记录:rownum为当前连续CANCELLED序列内的递增序号(从1开始)CLOSED状态的记录:- 紧邻在一组
CANCELLED之后的第一条CLOSED,rownum取该组CANCELLED的总条数 - 该组后续的
CLOSED记录,rownum为0
- 紧邻在一组
- 其他状态(如
ACTIVE)的记录:rownum取最近一组CANCELLED的最后序号
预期输出
| id | time | status | rownum |
|---|---|---|---|
| 5069640_17a678bf | 2023-07-06 06:08:50.5209 +00:00 | CANCELLED | 1 |
| 5069640_17a678bf | 2023-07-06 06:51:37.8891 +00:00 | CLOSED | 1 |
| 5069640_17a678bf | 2023-07-06 06:52:19.7796 +00:00 | CANCELLED | 1 |
| 5069640_17a678bf | 2023-07-06 06:54:13.3729 +00:00 | CLOSED | 1 |
| 5069640_17a678bf | 2023-07-06 06:54:49.5915 +00:00 | CANCELLED | 1 |
| 5069640_17a678bf | 2023-07-06 06:55:57.6069 +00:00 | CANCELLED | 2 |
| 5069640_17a678bf | 2023-07-06 07:18:07.9313 +00:00 | CANCELLED | 3 |
| 5069640_17a678bf | 2023-07-06 07:46:09.6142 +00:00 | CLOSED | 3 |
| 5069640_17a678bf | 2023-07-06 07:54:32.5347 +00:00 | CLOSED | 0 |
| 5069640_17a678bf | 2023-07-06 07:55:58.4408 +00:00 | CLOSED | 0 |
| 5069640_17a678bf | 2023-07-06 08:06:02.2827 +00:00 | CANCELLED | 1 |
| 5069640_17a678bf | 2023-07-06 08:09:23.001 +00:00 | CANCELLED | 2 |
| 5069640_17a678bf | 2023-07-06 08:13:08.2036 +00:00 | CLOSED | 2 |
| 5069640_17a678bf | 2023-07-06 08:43:31.1047 +00:00 | CANCELLED | 1 |
| 5069640_17a678bf | 2023-07-06 10:04:46.8257 +00:00 | ACTIVE | 1 |
现有查询及问题
原查询语句
WITH CTE AS ( SELECT v.BasketId, v.StoreId, x.person_id, v.VBasket, v.CreatedAt, FORMAT(v.CreatedAt, 'yyyy-MM-dd') AS CreatedDate, v.Status, ROW_NUMBER() OVER (PARTITION BY x.person_id, v.Status ORDER BY v.CreatedAt) AS rn FROM [Basket] v CROSS APPLY OPENJSON(v.TBasket) WITH ( data NVARCHAR(MAX) AS JSON ) j1 CROSS APPLY OPENJSON(j1.data, '$.person_ids') WITH ( person_id NVARCHAR(MAX) '$' ) x WHERE x.person_id = '5069640_17a678bf' ), CTE2 AS ( SELECT BasketId, StoreId, person_id, VBasket, CreatedAt, CreatedDate, Status, CASE WHEN Status = 'CANCELLED' THEN ROW_NUMBER() OVER (PARTITION BY person_id, Status ORDER BY CreatedAt) ELSE 1 END AS rownum FROM CTE ) SELECT person_id, CreatedAt , Status, rownum FROM CTE2 ORDER BY CreatedAt;
当前输出(不符合预期)
| id | time | status | rownum |
|---|---|---|---|
| 5069640_17a678bf | 2023-07-06 06:08:50.5209 +00:00 | CANCELLED | 1 |
| 5069640_17a678bf | 2023-07-06 06:51:37.8891 +00:00 | CLOSED | 1 |
| 5069640_17a678bf | 2023-07-06 06:52:19.7796 +00:00 | CANCELLED | 2 |
| 5069640_17a678bf | 2023-07-06 06:54:13.3729 +00:00 | CLOSED | 1 |
| 5069640_17a678bf | 2023-07-06 06:54:49.5915 +00:00 | CANCELLED | 3 |
| 5069640_17a678bf | 2023-07-06 06:55:57.6069 +00:00 | CANCELLED | 4 |
| 5069640_17a678bf | 2023-07-06 07:18:07.9313 +00:00 | CANCELLED | 5 |
| 5069640_17a678bf | 2023-07-06 07:46:09.6142 +00:00 | CLOSED | 1 |
| 5069640_17a678bf | 2023-07-06 07:54:32.5347 +00:00 | CLOSED | 1 |
| 5069640_17a678bf | 2023-07-06 07:55:58.4408 +00:00 | CLOSED | 1 |
| 5069640_17a678bf | 2023-07-06 08:06:02.2827 +00:00 | CANCELLED | 6 |
| 5069640_17a678bf | 2023-07-06 08:09:23.001 +00:00 | CANCELLED | 7 |
| 5069640_17a678bf | 2023-07-06 08:13:08.2036 +00:00 | CLOSED | 1 |
| 5069640_17a678bf | 2023-07-06 08:43:31.1047 +00:00 | CANCELLED | 8 |
| 5069640_17a678bf | 2023-07-06 10:04:46.8257 +00:00 | ACTIVE | 1 |
更新1后的输出(仍不符合预期)
| id | time | status | rownum |
|---|---|---|---|
| 5069640_17a678bf | 2023-07-06 06:08:50.5209 +00:00 | CANCELLED | 1 |
| 5069640_17a678bf | 2023-07-06 06:51:37.8891 +00:00 | CLOSED | 1 |
| 5069640_17a678bf | 2023-07-06 06:52:19.7796 +00:00 | CANCELLED | 3 |
| 5069640_17a678bf | 2023-07-06 06:54:13.3729 +00:00 | CLOSED | 3 |
| 5069640_17a678bf | 2023-07-06 06:54:49.5915 +00:00 | CANCELLED | 6 |
| 5069640_17a678bf | 2023-07-06 06:55:57.6069 +00:00 | CANCELLED | 10 |
| 5069640_17a678bf | 2023-07-06 07:18:07.9313 +00:00 | CANCELLED | 15 |
| 5069640_17a678bf | 2023-07-06 07:46:09.6142 +00:00 | CLOSED | 15 |
| 5069640_17a678bf | 2023-07-06 07:54:32.5347 +00:00 | CLOSED | 15 |
| 5069640_17a678bf | 2023-07-06 07:55:58.4408 +00:00 | CLOSED | 15 |
| 5069640_17a678bf | 2023-07-06 08:06:02.2827 +00:00 | CANCELLED | 21 |
| 5069640_17a678bf | 2023-07-06 08:09:23.001 +00:00 | CANCELLED | 28 |
| 5069640_17a678bf | 2023-07-06 08:13:08.2036 +00:00 | CLOSED | 28 |
| 5069640_17a678bf | 2023-07-06 08:43:31.1047 +00:00 | CANCELLED | 36 |
| 5069640_17a678bf | 2023-07-06 10:04:46.8257 +00:00 | ACTIVE | 36 |
修正后的SQL查询
WITH BaseData AS ( SELECT x.person_id AS id, v.CreatedAt AS time, v.Status AS status, -- 生成分组:将连续的CANCELLED,以及紧随其后的非CANCELLED记录归为同一组 SUM(CASE WHEN LAG(v.Status, 1, '') OVER (ORDER BY v.CreatedAt) != v.Status AND (v.Status = 'CANCELLED' OR LAG(v.Status, 1, '') OVER (ORDER BY v.CreatedAt) = 'CANCELLED') THEN 1 ELSE 0 END) OVER (ORDER BY v.CreatedAt) AS group_id FROM [Basket] v CROSS APPLY OPENJSON(v.TBasket) WITH ( data NVARCHAR(MAX) AS JSON ) j1 CROSS APPLY OPENJSON(j1.data, '$.person_ids') WITH ( person_id NVARCHAR(MAX) '$' ) x WHERE x.person_id = '5069640_17a678bf' ), GroupStats AS ( SELECT id, time, status, group_id, -- 组内CANCELLED记录的递增序号 ROW_NUMBER() OVER (PARTITION BY group_id, status ORDER BY time) AS cancel_seq, -- 组内CANCELLED记录的总数量 COUNT(CASE WHEN status = 'CANCELLED' THEN 1 END) OVER (PARTITION BY group_id) AS total_cancels, -- 组内所有记录的递增序号,用于判断是否为CANCELLED之后的第一条CLOSED ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY time) AS group_seq FROM BaseData ) SELECT id, time, status, CASE WHEN status = 'CANCELLED' THEN cancel_seq WHEN status = 'CLOSED' THEN CASE WHEN group_seq = 1 THEN total_cancels ELSE 0 END ELSE COALESCE(total_cancels, 0) END AS rownum FROM GroupStats ORDER BY time;
逻辑说明
- BaseData CTE:通过
LAG函数检测状态切换,将连续的CANCELLED序列,以及紧随其后的非CANCELLED记录划分为同一分组,确保每组对应一个CANCELLED序列及其后续关联记录。 - GroupStats CTE:在每个分组内,完成三个统计:
- 给
CANCELLED记录分配组内递增序号cancel_seq - 统计组内
CANCELLED的总数量total_cancels - 给组内所有记录分配递增序号
group_seq,用于识别是否为分组内第一条记录
- 给
- 最终SELECT:通过CASE语句实现规则:
CANCELLED记录直接使用组内序号cancel_seqCLOSED记录:分组第一条(即刚从CANCELLED切换的记录)取total_cancels,其余取0- 其他状态记录取最近分组的
total_cancels(
相关产品推荐
相关产品推荐

