【问题标题】:Grouping data in SQL by difference in column values按列值的差异对 SQL 中的数据进行分组
【发布时间】:2018-02-12 06:34:32
【问题描述】:

我在 postgres 表的日志表中有以下数据:

  1. logid => int(自动递增)
  2. start_time => bigint(存储纪元值)
  3. inserted_value => int

以下是存储在表中的数据(其中实际开始时间不是列,只是以UTC格式以24小时格式显示start_time值)

logid   user_id    start_time       inserted_value       start time actual
 1      1          1518416562       15                   12-Feb-2018 06:22:42
 2      1          1518416622       8                    12-Feb-2018 06:23:42 
 3      1          1518417342       9                    12-Feb-2018 06:35:42 
 4      1          1518417402       12                   12-Feb-2018 06:36:42 
 5      1          1518417462       18                   12-Feb-2018 06:37:42
 6      1          1518418757       6                    12-Feb-2018 06:59:17 
 7      1          1518418808       11                   12-Feb-2018 07:00:08

我想根据 start_time 的差异对值进行分组和求和

对于上述数据,应分三组计算总和:

  user_id         sum
   1              15 + 8
   1              9 + 12 + 18
   1              6 + 11

因此,每组中的值有 1 分钟的差异。这个 1 可以被认为是任何 x 分钟的差异。

我也在尝试LAG 功能,但无法完全理解。我希望我能够解释我的问题。

【问题讨论】:

    标签: sql postgresql datetime group-by analytic-functions


    【解决方案1】:

    您可以使用普通的group by 来实现您想要的。只需使属于同一分钟的所有start_time 值相等。例如

    select user_id, start_time/60, sum(inserted_value)
    from log_table
    group by user_id, start_time/60
    

    我假设您的 start_time 列包含表示毫秒的整数,因此 /60 将正确地将它们截断为分钟。如果值是浮点数,则应使用floor(start_time/60)

    如果您还想选择分组时的可读日期,可以将to_timestamp((start_time/60)*60) 添加到选择列表中。

    【讨论】:

    • start_time 以毫秒为单位存储纪元值,表示自 1970 年 1 月 1 日以来经过的毫秒数
    • 恐怕没那么简单。 15184165622018-02-12T06:22:4215184166222018-02-12T06:23:42。我认为 06:22:4206:23:42 必须组合在一起,但 06:22:4206:23:43 不应该。
    • 如果必须将 06:22:42 和 06:23:42 组合在一起,则跨度超过一分钟。通过传递性,06:23:42 和 06:24:42 也必须组合在一起,这会将所有时间归为一个组:-)
    • @dnswlt 编辑了我的问题,添加了 2 个日志条目以使问题更清晰
    • 好的,现在我明白了!只要与前一个条目的差异不大于一分钟,您就希望对值求和。那么@SalmanA 的使用窗口函数的解决方案可能是要走的路。
    【解决方案2】:

    您可以使用LAG 检查当前行是否比前一行多 60 秒,并在每次发生这种情况时设置group_changed(虚拟列)。

    在下一步中,对该列使用运行总和。这将创建一个group_number,您可以使用它来对第三步中的结果进行分组。

    WITH cte1 AS (
        SELECT
            testdata.*,
            CASE WHEN start_time - LAG(start_time, 1, start_time) OVER (PARTITION BY user_id ORDER BY start_time) > 60 THEN 1 ELSE 0 END AS group_changed
        FROM testdata
    ), cte2 AS (
        SELECT
            cte1.*,
            SUM(group_changed) OVER (PARTITION BY user_id ORDER BY start_time) AS group_number
        FROM cte1
    )
    SELECT user_id, SUM(inserted_value)
    FROM cte2
    GROUP BY user_id, group_number
    

    SQL Fiddle

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-05
      • 2023-02-04
      • 1970-01-01
      • 2019-07-22
      • 2016-10-10
      • 2020-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多