sql - 如何按彼此接近的时间戳对 SQL 表进行分组?

标签 sql postgresql select group-by sql-view

我有一个用户事件表:

CREATE TABLE public.user_session_activity_table (
    id integer NOT NULL,
    "userId" integer NOT NULL,
    "creationDate" timestamp without time zone DEFAULT now() NOT NULL
);

INSERT INTO public.user_session_activity_table 
(
    id, 
    "userId",
    "creationDate"
) 
VALUES 
    (1, 1, '2021-11-06 10:54:23.891327'),
    (2, 1, '2021-11-06 10:59:56.616956'),
    (3, 1, '2021-11-06 10:59:57.680751'),
    (4, 1, '2021-11-06 10:59:58.857336'),
    (5, 1, '2021-11-06 11:36:47.112812'),
    (6, 1, '2021-11-06 11:36:49.049485'),
    (7, 1, '2021-11-06 11:36:50.931315')
    

所需输出:

id  userId  sessionLenght
1   1       123s                 -- row 1 
2   1       123s                 -- row 2-4 grouped together
3   1       123s                 -- row 4-7 grouped together

说明:

我正在创建用户 session View ,形成一个包含已保存用户事件行的表。我想根据创建日期之间耗时增量进行分组。如果经过了太多时间(假设阈值是 1 分钟),则当前组结束并开始新一组。这将导致此示例数据对齐到 3 个组:

  • id:1
  • id:2,id:3,id:4
  • id:5,id:6,id:7

如您所见,最显着的时间差异是 id:1 <-> id:2 和 id:4 <-> id:5 之间,这就是为什么它应该分为 3 个单独的组。

我正在使用最新版本的 PostgreSQL。 “sessionLength”并不是那么重要,我自己可以找到解决方案,主要问题是创建这些组。

一个重要的事实是:四舍五入日期不起作用, session 可能会持续几分钟或几小时。应该结束和开始组的事情是事件之间的时间差(例如,当用户注销或离开键盘一小时时)。

更新1:

窗口 RANGE 函数也不是孤立的。一开始它很有说服力,但它只将预先指定的时间范围内的行分组在一起。

enter image description here

SELECT 
*
FROM (
    SELECT
        "usa"."userId",
        "usa"."creationDate" AS "currentDate",
        FIRST_VALUE("usa"."creationDate") OVER www AS "sessionStartDate",
        LAST_VALUE("usa"."creationDate") OVER www AS "sessionEndDate"
    --  first_value("usa"."id") OVER www AS first_id, 
    --  last_value("usa"."id") OVER www AS last_id, 
--      LAST_VALUE("usa"."creationDate") OVER www - FIRST_VALUE("usa"."creationDate") OVER www AS "sessionLength"
    FROM public."user_session_activity_view" AS "usa"
    WINDOW www AS 
    (
        PARTITION BY "userId"
        ORDER BY "creationDate"
        RANGE BETWEEN '3 min' PRECEDING AND '3 min' FOLLOWING
    ) 
) AS "sq"

WHERE "sq"."userId" = 33
    
ORDER BY
    "sq"."userId",
    "sq"."sessionStartDate"

谢谢,非常感谢任何帮助! (如果问题不清楚,请告诉我,我会尽力澄清一下!:))

最佳答案

我知道这并不能为您提供完整的解决方案,但它可能会帮助您实现这一目标,使用 row_number 来标识要在 60 秒的持续时间内分组在一起的行:

with u as (
  select *,
    id - row_number() over (partition by userid, round(extract('epoch' from creationdate) / 60) * 60 order by creationdate) gp
  from t 
)
select 
  row_number() over(partition by max(userId) order by max(creationdate)) GroupNo,
  max(userid) UserId,
  min(creationdate) StartOfRange, max(CreationDate) EndOfRange,
  round(max(date_part('second',creationdate::time))- min(date_part('second',creationdate::time))) duration
from u
group by gp

关于sql - 如何按彼此接近的时间戳对 SQL 表进行分组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69864133/

相关文章:

sql - 在 Postgres 中插入自定义类型的数组

mysql - 如何实现反向0x​​104567910?

mysql - 为什么 find_in_set 有效但 IN 子句

sql - 当日期不完全连续时,按连续日期对记录进行分组

php - 在一个查询 PDO 中选择两个表

postgresql - ~ ‘^[0-9]+$’ 在 PostgreSQL 中意味着什么

windows - psql shell 使用代码页 850,windows 使用 1252。如何解决更改控制台代码页?

sql - 具有多个变量的 T-SQL SELECT

sql - 连续行对的平均值

SQL 服务器 : trigger firing every time