我有一张非常简单的表格:

create table tmp(
    id int,
    source_id int,
    event_user varchar,
    event_date timestamp
);
 

这是数据:

insert into tmp(id, source_id, event_user, event_date)
values (1, 1,  'A', now()),
       (2, 1,  'A', now()+interval '1 day'),
       (3, 1,  'B', now()+interval '2 day'),
       (4, 1,  'B', now()+interval '3 day'),
       (5, 1,  'A', now()+interval '4 day'),
       (6, 1,  'A', now()+interval '5 day'),
       (7, 1,  'A', now()+interval '6 day'),
       (8, 2,  'A', now()+interval '7 day'),
       (9, 2,  'B', now()+interval '8 day'),
       (10, 2,  'A', now()+interval '9 day'),
       (11, 2,  'B', now()+interval '10 day'),
       (12, 2,  'B', now()+interval '11 day') ;

(为了简单起见,我只是在event_Date列中的"now"时间戳中添加了1天,以显示时间序列.在实际情况下,无法对事件_日期的分布做出任何假设.实际情况下的列"id"和"source_id"也属于uuid类型.)

当我查询此表时:

select * from tmp
order by event_date;

我得到: initial data

id source_id event_user event_date
1 1 A 03-05-2024
2 1 A 04-05-2024
3 1 B 05-05-2024
4 1 B 06-05-2024
5 1 A 07-05-2024
6 1 A 08-05-2024
7 1 A 09-05-2024
8 2 A 10-05-2024
9 2 B 11-05-2024
10 2 A 12-05-2024
11 2 B 13-05-2024
12 2 B 14-05-2024

现在,问题在于,我需要额外的列(series_id),它标识属于同一source_id和server_user的顺序(按Events_Date的顺序)记录组.

因此,当我查询时,我希望得到以下结果:

expected result

id source_id SERIES_ID event_user event_date
1 1 1 A 03-05-2024
2 1 1 A 04-05-2024
3 1 2 B 05-05-2024
4 1 2 B 06-05-2024
5 1 3 A 07-05-2024
6 1 3 A 08-05-2024
7 1 3 A 09-05-2024
8 2 1 A 10-05-2024
9 2 2 B 11-05-2024
10 2 3 A 12-05-2024
11 2 4 B 13-05-2024
12 2 4 B 14-05-2024

我try 过窗口函数(rank()、dense_rank()),但没有成功,当然是因为预期组中的记录除了在时间上是"结果"之外没有共同特征.可能这是一种"差距和岛屿"问题,但不幸的是我不知道如何解决它.

推荐答案

你的怀疑是正确的,这是一个缺口和岛屿问题.以下是获得所描述结果的一种方法:

WITH
  tmp (id, source_id, event_user, event_date) AS (
    VALUES
      (1, 1, 'A', NOW()),
      (2, 1, 'A', NOW() + INTERVAL '1 day'),
      (3, 1, 'B', NOW() + INTERVAL '2 day'),
      (4, 1, 'B', NOW() + INTERVAL '3 day'),
      (5, 1, 'A', NOW() + INTERVAL '4 day'),
      (6, 1, 'A', NOW() + INTERVAL '5 day'),
      (7, 1, 'A', NOW() + INTERVAL '6 day'),
      (8, 2, 'A', NOW() + INTERVAL '7 day'),
      (9, 2, 'B', NOW() + INTERVAL '8 day'),
      (10, 2, 'A', NOW() + INTERVAL '9 day'),
      (11, 2, 'B', NOW() + INTERVAL '10 day'),
      (12, 2, 'B', NOW() + INTERVAL '11 day')
  ),
  breaks AS (
    SELECT
      id,
      event_user IS DISTINCT FROM LAG(event_user) OVER (
        PARTITION BY
          source_id
        ORDER BY
          event_date,
          event_user
      ) break,
      source_id,
      event_user,
      event_date
    FROM
      tmp
  )
SELECT
  id,
  source_id,
  COUNT(break) FILTER (
    WHERE
      break
  ) OVER (
    PARTITION BY
      source_id
    ORDER BY
      event_date
  ) AS series_id,
  event_user,
  event_date
FROM
  breaks
ORDER BY
  event_date;

这种方法确定哪些行开始新系列,然后通过计数每source_id内开始的系列数来分配系列.

Sql相关问答推荐

Oracle SQL中多个函数上的SON构建不会以良好的格式结束

SQL查询:合并2个表

在postgres中动态计算出现次数并插入到json中

通过 Select 值的顺序进行排序ClickHouse

Oracle SQL-将结果列在单行中

雅典娜嵌套Json提取液

在数据库中搜索列

我怎样才能得到列值对应的最大值在另一个?

如何计算给定日期前三个月的值以及月初数据?

将JSON文件导入Postgres 16数据库时出错(22P04上次预期列之后的额外数据)

如何在MS Access中基于另外两个表自动填充一个表中的字段?

如何修复初学者 SQL INNER JOIN 查询错误

当我返回 sql 列时,有没有办法只反转数字? ( hebrew )

Oracle 21c 中的递归查询回顾过go 3 周

SQL的左连接在多对多关系情况下使用

oracle中多行的跨日期范围的交集

如何 Select 一列具有最小值而另一列具有给定值的记录?

面对来自以下两个代码的不同输出

如何在一个存储过程中创建全局临时表,并在另一个存储过程中使用它

使用标准SQL 触发更新当前日期