按datediff对行进行分组,然后使用diff函数

时间:2019-10-14 15:06:37

标签: sql postgresql

我在PostgreSQL中有一个带有时间戳列created_at和整数列user_id的表。

id | created_at | user_id
1 | 2019-10-14 09:26:53.813 | 1
2 | 2019-10-14 09:26:54.813 | 1
3 | 2019-10-14 09:46:53.813 | 1
4 | 2019-10-14 09:46:54.813 | 2
5 | 2019-10-14 09:46:55.813 | 1
6 | 2019-10-14 09:46:56.813 | 1
7 | 2019-10-14 09:46:57.813 | 2

每行代表用户的某些操作。我需要计算平均用户会话长度。会话定义为时间差小于10分钟的一组动作。如果两个用户操作之间相差10分钟或更长时间,则新会话开始。

我在想:

  1. user_id对行进行分组。
  2. 通过单个用户当前项和下一项之间的差异(以某种方式)对行进行分组。 (以获取会话)
  3. 计算一组(会话)中第一行和最后一行之间的差异。 (以获取会话长度)
  4. 计算平均会话时长。 (以获取平均会话时长)

但是我不能用SQL编写它。

能否给我一些建议/示例,如何在SQL中完成?

2 个答案:

答案 0 :(得分:1)

使用yourString.split('__SEPARATOR__')[2].lstrip("'") 以及差异超出阈值的累积计数:

lag()

答案 1 :(得分:0)

step-by-step demo:db<>fiddle

SELECT 
    user_id,
    AVG(diff)
FROM (
    SELECT DISTINCT
        user_id,
        group_id,
        first_value(created_at) OVER (PARTITION BY user_id, group_id ORDER BY created_at DESC)
            - first_value(created_at) OVER (PARTITION BY user_id, group_id ORDER BY created_at) as diff
    FROM (
        SELECT
            id, created_at, user_id,
            SUM(group_id) OVER (PARTITION BY user_id ORDER BY created_at) AS group_id
        FROM (
            SELECT
                *,
                (created_at 
                    - lag(created_at, 1, created_at) OVER (PARTITION BY user_id ORDER BY created_at)
                    > interval '10 minutes')::int AS group_id
            FROM
                mytable   
        )s
    )s
)s
GROUP BY user_id
  1. (created_at - lag(created_at, 1, created_at) OVER (PARTITION BY user_id ORDER BY created_at) > interval '10 minutes')::int AS group_idlag() window function从上一个记录中获取created_at的值(第二个参数:步长,第三个参数:如果没有上一个记录,则为默认值==当前值)在有序user_id分区(组)中。然后,计算当前created_at值与前一个值之间的差。如果该值> 10分钟,则结果为truefalse否则。可以将该布尔值转换为int值,从而产生01
  2. SUM() / 0值上累积1,每个group_id的每个新会话都会产生user_id s
  3. 每个user_id和会话group_id的第一个created_at时间戳可以通过first_value()窗口函数来获取,最后一个first_value()DESC来获取。不同之处在于您每次会话的时长。之所以使用DISTINCT子句,是因为差异值被放入每个记录中。但是我们只需要一次。
  4. 最后,您可以为用户分组并AVG()进行区别。