计算 SQL 中值转换之间的行数

Posted

技术标签:

【中文标题】计算 SQL 中值转换之间的行数【英文标题】:Counting the number of rows between transitions of values in SQL 【发布时间】:2021-01-28 21:59:36 【问题描述】:

我有带有 user_id、时间戳和是/否答案的行。我想计算每个 ID 有多少条“NO”(连续行)。

例子:

user_id timestamp response no_streak
1 2021-01-20 13:59:26 YES 0
1 2021-01-20 14:01:27 NO 1
1 2021-01-20 14:03:21 NO 2
1 2021-01-20 14:07:29 NO 3
1 2021-01-20 14:09:22 YES 0
1 2021-01-20 14:11:26 YES 0
1 2021-01-20 14:13:30 NO 1
1 2021-01-20 14:17:26 NO 2
1 2021-01-20 14:19:29 YES 0
1 2021-01-20 14:25:30 NO 1
1 2021-01-20 14:27:23 NO 2
1 2021-01-20 14:31:23 NO 3
1 2021-01-20 14:35:27 NO 4
1 2021-01-20 14:39:24 YES 0
2 2021-01-20 14:39:24 NO 1
2 2021-01-20 14:47:28 NO 2
2 2021-01-20 14:49:22 NO 3
2 2021-01-20 14:51:25 NO 4
2 2021-01-20 14:53:29 NO 5
2 2021-01-20 14:55:22 NO 6
2 2021-01-20 14:57:22 YES 0

最终,我想知道每个用户的条纹有多长:

user_id streak length
1 0
1 3
1 2
1 4
2 0
2 6

我可以使用LAG() 来查找“否”转换为“是”的位置,反之亦然,但我很难计算每个转换之间的行数。

【问题讨论】:

解释为每个 user_id 显示条纹长度 = 0 背后的逻辑 @eshirvana 这不是必需的,但我想至少展示一下可能的情况。如果用户有所有YES 响应,那么它们可以被完全排除在外,或者被记录为0 的连续长度。 【参考方案1】:

计算每行的“是”数,以便相邻的 NO 具有相同的分组值。然后过滤聚合:

select t.user_id, count(*), min(timestamp), max(timestamp)
from (select t.*,
             sum(case when response = 'YES' then 1 else 0 end) over (partition by user_id order by timestamp) as grp
      from t
     ) t
where response = 'NO'
group by user_id, grp;

注意:这不会返回0 长度的条纹。我不确定“连胜”这个词是否合适。但要获得它们,请移除 where 过滤器并使用条件聚合:

select t.user_id, sum(case when response = 'NO' then 1 else 0 end),
       min(timestamp), max(timestamp)
from (select t.*,
             sum(case when response = 'YES' then 1 else 0 end) over (partition by user_id order by timestamp) as grp
      from t
     ) t
group by user_id, grp;

【讨论】:

以上是关于计算 SQL 中值转换之间的行数的主要内容,如果未能解决你的问题,请参考以下文章

7.04 求一个表的行数

HIVE/Impala 查询:计算满足特定条件的行之间的行数

SQL 计算表中的行数

如何计算 Git 中两次提交之间更改的行数?

如何计算作者在 git 中两个版本之间更改的行数?

计算Sql中的行数