如何找到具有间隔的相同值的终点?

时间:2018-12-19 15:20:45

标签: postgresql

我下面有一张这样的桌子。

ID        Time         State 
1          1         "active"
1          2         "active"
1          3         "active"
1          4        "inactive"
2          2        "inactive"
2          3         "active"
3          1         "active"
3          3         "active"
3          4        "inactive"   

我想按状态对开始/结束时间进行排序。
它可能需要lag()窗口函数,但我不知道如何找到相同状态的终点。

我的期望表应如下所示。

ID        Start          End           State 
1          1              4           "active"
1          4             NULL        "inactive"
2          2              3          "inactive"
2          3             NULL         "active"
3          1              4           "active"
3          4             NULL        "inactive"  

1 个答案:

答案 0 :(得分:1)

demo:db<>fiddle

SELECT DISTINCT ON (sum)  -- 5
    id,
    -- 4
    first_value(time) OVER (PARTITION BY sum ORDER BY time) as start,
    first_value(lead) OVER (PARTITION BY sum ORDER BY time DESC) as end,
    state
FROM (
    SELECT
        *, 
        -- 3
        SUM(CASE WHEN is_prev_state THEN 0 ELSE 1 END) OVER (ORDER BY id, time)
    FROM (
        SELECT 
            *, 
            -- 1
            lead(time) OVER (PARTITION BY id ORDER BY time),
            -- 2                
            state = lag(state) OVER (PARTITION BY id ORDER BY time) as is_prev_state
        FROM states
    )s
)s
  1. lead()将下一个值带到当前行。到time == 4id == 1)转到带有time == 3的行。这样做的目的是使组的最后一个位置排在右行。
  2. lag()做相反的事情。它将前一个值作为当前行。这样,我可以检查状态是否已更改:当前状态是否与上一个相同?
  3. 在这一行中,我为每个状态创建组:如果状态发生更改,则求和一个值。如果不保持相同的值(添加0)。
  4. 现在我有每个状态可能的最后一个值(通过(1)给出),并且可以获得第一个值。这是通过窗口函数first_value()完成的,该函数为您提供了有序组的第一个值。要获得最后一个值,您只需要按降序排列组即可。 (Why not using last_value()
  5. DISTINCT ON仅过滤(使用SUM()函数生成的)组的第一行