【问题标题】:Group by and aggregate when colums change over time in Clickhouse当列在 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 进行分组并计算持续时间。

有什么解决办法吗?

【问题讨论】:

标签: sql aggregate clickhouse


【解决方案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 实例。根据需要进行调整。我已经用另一个引擎测试了等效项。

      【讨论】:

        猜你喜欢
        • 2012-09-06
        • 2021-04-29
        • 2019-03-24
        • 2021-01-27
        • 2021-03-03
        • 2012-02-09
        • 1970-01-01
        • 1970-01-01
        • 2013-04-22
        相关资源
        最近更新 更多