PostgreSQL分析函数窗口化以查找列中的下一个值

时间:2017-12-13 00:15:22

标签: sql database postgresql window-functions

我有一个使用PostgreSQL创建的数据集如下:

SELECT T.*

FROM

(
WITH REF_TABLE AS 
(
SELECT 22 AS "UNIT", 1 AS "CYCLE", 5.3 AS "FIRST_SHIFT", 9.56 AS "LAST_SHIFT", 1 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 1 AS "CYCLE", 5.3 AS "FIRST_SHIFT", 9.56 AS "LAST_SHIFT", 2 AS "ROUTE"  FROM DUAL
UNION
SELECT 22 AS "UNIT", 1 AS "CYCLE", 5.3 AS "FIRST_SHIFT", 9.56 AS "LAST_SHIFT", 3 AS "ROUTE"  FROM DUAL
UNION
SELECT 22 AS "UNIT", 1 AS "CYCLE", 5.3 AS "FIRST_SHIFT", 9.56 AS "LAST_SHIFT", 4 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 2 AS "CYCLE", 3.8 AS "FIRST_SHIFT", 6.25 AS "LAST_SHIFT", 1 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 2 AS "CYCLE", 3.8 AS "FIRST_SHIFT", 6.25 AS "LAST_SHIFT", 3 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 3 AS "CYCLE", 7.0 AS "FIRST_SHIFT", 10.05 AS "LAST_SHIFT", 1 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 3 AS "CYCLE", 7.0 AS "FIRST_SHIFT", 10.05 AS "LAST_SHIFT", 2 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 3 AS "CYCLE", 7.0 AS "FIRST_SHIFT", 10.05 AS "LAST_SHIFT", 3 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 3 AS "CYCLE", 7.0 AS "FIRST_SHIFT", 10.05 AS "LAST_SHIFT", 4 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 3 AS "CYCLE", 7.0 AS "FIRST_SHIFT", 10.05 AS "LAST_SHIFT", 5 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 4 AS "CYCLE",  4.3 AS "FIRST_SHIFT", 8.10 AS "LAST_SHIFT", 4 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 4 AS "CYCLE", 4.3 AS "FIRST_SHIFT", 8.10 AS "LAST_SHIFT", 5 AS "ROUTE" FROM DUAL
UNION
SELECT 22 AS "UNIT", 4 AS "CYCLE", 4.3 AS "FIRST_SHIFT", 8.10 AS "LAST_SHIFT", 8 AS "ROUTE" FROM DUAL
)
SELECT * FROM REF_TABLE
)
T

Dataset

 UNIT | CYCLE | FIRST_SHIFT | LAST_SHIFT | ROUTE
------+-------+-------------+------------+-------
   22 |     1 |         5.3 |       9.56 |     1
   22 |     1 |         5.3 |       9.56 |     2
   22 |     1 |         5.3 |       9.56 |     3
   22 |     1 |         5.3 |       9.56 |     4
   22 |     2 |         3.8 |       6.25 |     1
   22 |     2 |         3.8 |       6.25 |     3
   22 |     3 |         7.0 |      10.05 |     1
   22 |     3 |         7.0 |      10.05 |     2
   22 |     3 |         7.0 |      10.05 |     3
   22 |     3 |         7.0 |      10.05 |     4
   22 |     3 |         7.0 |      10.05 |     5
   22 |     4 |         4.3 |       8.10 |     4
   22 |     4 |         4.3 |       8.10 |     5
   22 |     4 |         4.3 |       8.10 |     8

我无法为这个数据集锻炼正确的PostgreSQL分析函数(LEAD,LAG或FIRST_VALUE,LAST_VALUE)窗口;但 想生成如下输出:

enter image description here

1 个答案:

答案 0 :(得分:0)

我更确定我在这里发明了一个方形轮,但万一没有人给你正常的解决方案:

t=# with a as (
  select *
 , case when r = max(r) over (partition by u,c,f) then row_number() over () else 0 end casex
 , case when r = min(r) over (partition by u,c,f) then row_number() over () else 0 end casen
 , lead(f) over (partition by u order by u,c)
 , lag(l) over (partition by u order by u,c)
 from t
)
, b as (
  select *
  , max("casex") over(partition by u,c) x
  , max("casen") over(partition by u,c) n
  from a
)
select u,c,f,l,r
, nth_value("lead","x"::int) over()
, nth_value("lag","n"::int) over() 
from b;
 u  | c |  f  |   l   | r | nth_value | nth_value
----+---+-----+-------+---+-----------+-----------
 22 | 1 | 5.3 |  9.56 | 1 |       3.8 |
 22 | 1 | 5.3 |  9.56 | 2 |       3.8 |
 22 | 1 | 5.3 |  9.56 | 3 |       3.8 |
 22 | 1 | 5.3 |  9.56 | 4 |       3.8 |
 22 | 2 | 3.8 |  6.25 | 1 |       7.0 |      9.56
 22 | 2 | 3.8 |  6.25 | 3 |       7.0 |      9.56
 22 | 3 | 7.0 | 10.05 | 1 |       4.3 |      6.25
 22 | 3 | 7.0 | 10.05 | 2 |       4.3 |      6.25
 22 | 3 | 7.0 | 10.05 | 3 |       4.3 |      6.25
 22 | 3 | 7.0 | 10.05 | 4 |       4.3 |      6.25
 22 | 3 | 7.0 | 10.05 | 5 |       4.3 |      6.25
 22 | 4 | 4.3 |  8.10 | 4 |           |     10.05
 22 | 4 | 4.3 |  8.10 | 5 |           |     10.05
 22 | 4 | 4.3 |  8.10 | 8 |           |     10.05
(14 rows)

我再一次在这里编写了一步一步的逻辑选择,但我确信有一些数学技巧可以快捷方式