2017-02-09 48 views
2

的問題是以下內容:PostgreSQL的先前和下一組值

假設,我有這樣視圖的表(它是我的工作表中的一個子樣品):

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

我需要添加兩個新列

  • prev包含col1以前的值不等於當前
  • 含有col1不等於當前

如果不存在先前的值的下一個值,prev應包含當前col1的值以及next應包含的當前值如果不存在下一個值。

結果應該有如下形式:

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

我會很感激的任何幫助。

+1

使用lag()和lead()over(order by)窗口函數 –

+0

https://www.postgresql.org/docs/current/static/tutorial-window.html –

+1

SQL表示代表* unordered *集合。沒有「上一個」或「下一個」值,除非列指定了排序。您的數據中沒有任何列看起來像排序數據的明顯列。 –

回答

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; 

它發現每行組的行數/滯後。

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()。這不是問題的有趣部分。

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