当列在 Clickhouse 中随时间变化时分组和聚合

Posted

技术标签:

【中文标题】当列在 Clickhouse 中随时间变化时分组和聚合【英文标题】:Group by and aggregate when colums change over time in Clickhouse 【发布时间】:2021-08-09 05:36:51 【问题描述】:

假设我在 Clickhouse 中有下表:

f_datetime, f_user, f_tile
2021-07-08 07:00:00, x, a
2021-07-08 08:30:00, x, a
2021-07-08 08:45:00, x, a

2021-07-08 09:00:00, x, b
2021-07-08 11:00:00, x, b

2021-07-08 12:00:00, x, a
2021-07-08 15:00:00, x, a

2021-07-08 16:00:00, x, b
2021-07-08 20:00:00, x, b

我想要一个聚合查询来获得以下结果:

f_user, f_tile, f_duration
x, a, 105
x, b, 120
x, a, 180
x, b, 240

我想在 f_datetime 之前对 f_tile、f_user 进行分组并计算持续时间。

有什么解决办法吗?

【问题讨论】:

***.com/questions/61163259/… 【参考方案1】:

这是一个间隙和孤岛问题的示例。对于这个版本,最简单的解决方案可能是行号的不同:

select f_user, t_tile,
       min(f_datetime), max(f_datetime),
       date_diff('minute', min(f_datetime), max(f_datetime)) as f_duration
from (select t.*,
             row_number() over (partition by f_user order by f_datetime) as seqnum,
             row_number() over (partition by f_user, f_tile order by f_datetime) as seqnum_2
      from t
     ) t
group by f_user, f_tile, (seqnum - seqnum_2)

【讨论】:

【参考方案2】:

表中的下一个日期时间值是该用户的最小值,>= 当前行的日期时间。

SELECT t.f_user, t.f_title,
(SELECT MIN(t1.f_datetime) 
    FROM Yourtable t1 
    WHERE t1.f_datetime >= t.f_datetime AND t1.f_user = t.f_user AND t1.f_tile = t.f_tile) - t.f_datetime
FROM Yourtable t

您可以应用 DIFF 函数,而不是减去这些值。

【讨论】:

【参考方案3】:

由于您希望对每个连续的 f_tile 段进行计算(我猜是 f_user),这里有一种方法,使用窗口函数:

数据:初始表。 cte2:查找每个连续 f_tile 的边缘,每个 f_user 运行 cte3:为每次运行计算一个组 (grp) 指标以进行聚合 cte4:计算每次f_tile 运行的持续时间
WITH cte2 AS (  -- Find edges of each f_tile run for each f_user by datetime
        SELECT t.*
             , CASE WHEN LAG(f_tile) OVER (PARTITION BY f_user ORDER BY f_datetime) = f_tile THEN 0 ELSE 1 END AS edge
          FROM data AS t
     )
   , cte3 AS (  -- Assign a group (grp) indicator for each run for aggregation
        SELECT t.*, SUM(edge) OVER (PARTITION BY f_user ORDER BY f_datetime) AS grp
          FROM cte2 AS t
     )
   , cte4 AS (
        SELECT f_user, f_tile, grp
             , MIN(f_datetime) AS start
             , DATE_DIFF('minute', MAX(f_datetime), MIN(f_datetime)) AS duration
          FROM cte3 AS t
         GROUP BY f_user, f_tile, grp
     )
SELECT f_user, f_tile, duration
  FROM cte4
 ORDER BY start
;

结果:

+--------+--------+----------+
| f_user | f_tile | duration |
+--------+--------+----------+
| x      | a      |      105 |
| x      | b      |      120 |
| x      | a      |      180 |
| x      | b      |      240 |
+--------+--------+----------+

注意:我没有要测试的 clickhouse 实例。根据需要进行调整。我已经用另一个引擎测试了等效项。

【讨论】:

以上是关于当列在 Clickhouse 中随时间变化时分组和聚合的主要内容,如果未能解决你的问题,请参考以下文章

这些列在 db 性能图表中的含义是啥?

当列数不相等而不将每个列定义为 NuLL 时,有没有办法在 Impala SQL 中合并两个表

Anylogic 参数变化实验:我以何种方式使用“表达式”列在其允许的状态下改变布尔参数?

比较随时间戳变化的字符

如何在clickhouse中按时间顺序折叠相同的值行?

ClickHouse存储解析JSON数据