使用窗口函数分组而不是两个窗口函数

时间:2015-08-19 13:40:41

标签: sql postgresql

我有一个包含2列的表:timeid。我们认为行首先按id排序,然后按时间排序。

╔════════╦══════════╗
║ time   ║ id       ║
╠════════╬══════════╣
║ 9:10   ║  1       ║
║ 9:20   ║  1       ║
║ 10:10  ║  1       ║
║ 11:30  ║  1       ║
║ 11:50  ║  1       ║
║ 10:20  ║  2       ║
║ 10:30  ║  2       ║
║ 11:20  ║  3       ║
║ 11:50  ║  3       ║
╚════════╩══════════╝

我只想从中选择id与“上一行”id相同的行,并且与前一行的时差不到一小时。

这可以通过首先创建一个表来完成,其中第3列的时间差与前一行和第4列的id差异,并且只选择id_diff为0且time_diff在上面的行1小时。

但是这种方法似乎不够优雅,因为我想分别查看每个id并在每个id内查看其时间并检查连续差异是否超过一小时。这将更好地反映出分别查看每个id的逻辑,因为它们是不同的实体。

那么怎样才能对id进行分组,而不是两次使用窗口函数呢?我知道GROUP BY的存在。

有效的代码,有两个窗口函数:

SELECT auxiliary_table_with_lag_diffs.*
FROM (
    select info.*,
        time-lag(time) over (Order by id, time ) as diff_time,
        id-lag(id) over (order by id, time) as diff_id
    from info
    )auxiliary_table_with_lag_diffs
WHERE diff_time>'01:00:00'
    AND diff_id=0
ORDER BY id, time;

2 个答案:

答案 0 :(得分:1)

如果您想查看上一行,那么为什么要先按id排序?

SELECT i.*
FROM (select i.*, lag(time) over (order by time) as prev_time,
             lag(id) over (order by time) as prev_id
     from info i
     ) i 
WHERE time < prev_time + interval '1 hour' and id = prev_id
ORDER BY id, time;

如果您不想在输出中使用prev_timeprev_id,只需明确选择您想要的列。

注意:您可能需要>而不是<,具体取决于您的实际需求(问题含糊不清)。

答案 1 :(得分:1)

此处只需要一个分析函数调用:在同一ID中获取上一次。

SELECT *
FROM 
(
  select info.*,
    time - lag(time) over (partition by id order by time) as diff_time
  from info
) auxiliary_table_with_lag_diffs
WHERE diff_time > interval '1 hour';
ORDER BY id, time;