PostgreSQL上一组和下一组值

时间:2017-02-09 13:11:57

标签: sql postgresql

问题如下:

假设我有一张这样的视图表(它是我正在使用的表格的子样本):

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

我需要添加两个新列

  • prev包含col1中之前的值,不等于当前的
  • next包含col1中的下一个值,不等于当前的

如果没有以前的值,则prev应包含当前col1的值,如果不存在下一个值,则next应包含当前值。< / p>

结果应具有以下形式:

| 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  |

我将不胜感激。

3 个答案:

答案 0 :(得分:1)

如果我假设您有一个id列指定了排序,那么这是可能的。我只是不确定使用窗口函数可以很容易地表达它。

您可以使用相关子查询:

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;

您可以为缺少的上一个和下一个值添加coalece()。这不是问题的有趣部分。

答案 1 :(得分:1)

您可以使用窗口函数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;

它找到每组行的超前/滞后。

答案 2 :(得分:0)

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