简体   繁体   English

PostgreSQL 上一组和下一组值

[英]PostgreSQL previous and next group value

The problem is the following:问题如下:

Suppose, I have a table of such view (it is a sub-sample of the table I'm working with):假设,我有一个这样的视图表(它是我正在使用的表的子样本):

| col1 | col2 |
|------|------|
|   1  |  a2  |
|   1  |  b2  |
|   2  |  c2  |
|   2  |  d2  |
|   2  |  e2  |
|   1  |  f2  |
|   1  |  g2  |
|   3  |  h2  |
|   1  |  j2  |

I need to add two new columns我需要添加两个新列

  • prev containing the previous value in col1 not equal to the current prev包含col1中的先前值不等于当前值
  • next containing the next value in col1 not equal to the current next包含col1不等于当前值的下一个值

If there is no previous value, prev should contain the current col1 's value as well as next should contain the current value if no next values exist.如果没有以前的值,则prev应包含当前col1的值,如果不存在下一个值,则next应包含当前值。

Result should have the following form:结果应具有以下形式:

| col1 | col2 | prev | next |
|------|------|------|------|
|   1  |  a2  |   1  |   2  |
|   1  |  b2  |   1  |   2  |
|   2  |  c2  |   1  |   1  |
|   2  |  d2  |   1  |   1  |
|   2  |  e2  |   1  |   1  |
|   1  |  f2  |   2  |   3  |
|   1  |  g2  |   2  |   3  |
|   3  |  h2  |   1  |   1  |
|   1  |  j2  |   3  |   1  |

I will be grateful any help.我将不胜感激任何帮助。

If I assume that you have an id column that specifies the ordering, then this is possible.如果我假设您有一个指定排序的id列,那么这是可能的。 I'm just not sure this is easily expressed using window functions.我只是不确定这是否可以使用窗口函数轻松表达。

You can use correlated subqueries:您可以使用相关子查询:

select t.*,
       (select t2.col1
        from t t2
        where t2.id < t.id and t2.col1 <> t.col1
        order by t2.id desc
        fetch first 1 row only
       ) as prev_col1,
       (select t2.col1
        from t t2
        where t2.id > t.id and t2.col1 <> t.col1
        order by t2.id asc
        fetch first 1 row only
       ) as prev_col2
from t;

You can add the coalece() for missing previous and next values.您可以为缺少上一个和下一个值添加coalece() That is not the interesting part of the problem.这不是问题的有趣部分。

You can try this using combination of window functions lead , lag , first_value , last_value and sum .您可以使用窗口函数leadlagfirst_valuelast_valuesum组合来尝试此操作。

select
    t.col1, t.col2, n,
    coalesce(first_value(y) over (partition by x order by col2), col1) prev_val,
    coalesce(last_value(y2) over (partition by x order by col2 
        rows between current row and unbounded following), col1) next_val
from (
    select
        t.*,
        case when col1 <> lag(col1) over (order by col2) then lag(col1) over (order by col2) end y,
        case when col1 <> lead(col1) over (order by col2) then lead(col1) over (order by col2) end y2,
        sum(n) over (order by col2) x
    from (
        select
            t.*,
            case when col1 <> lag(col1) over (order by col2) then 1 else 0 end n
        from t
    ) t
) t;

It finds the lead/lag per group of rows.它找到每组行的领先/滞后。

WITH cte AS (
SELECT row_number() over() rowid, *
  FROM unnest(array[1,1,2,2,2,1,1,3,1], array['a2','b2','c2','d2','e2','f2','g2','h2','j2']) t(col1,col2)
)
SELECT t.col1,
       t.col2,
       COALESCE(prev.col1,t.col1) prev,
       COALESCE("next".col1,t.col1) "next"
  FROM cte t
    LEFT JOIN LATERAL (SELECT prev.col1
                         FROM cte prev
                         WHERE prev.rowid < t.rowid
                           AND prev.col1 != t.col1
                         ORDER BY prev.rowid DESC
                         LIMIT 1
                      ) prev ON True
   LEFT JOIN LATERAL (SELECT "next".col1
                         FROM cte "next"
                         WHERE "next".rowid > t.rowid
                           AND "next".col1 != t.col1
                         ORDER BY "next".rowid ASC
                         LIMIT 1
                      ) "next" ON True

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM