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

Posted

技术标签:

【中文标题】PostgreSQL 分析函数窗口化以查找列中的下一个值【英文标题】:PostgreSQL analytic function windowing to find the next value in column 【发布时间】:2017-12-13 00:15:21 【问题描述】:

我有一个使用 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)窗口;但 想生成如下输出:

【问题讨论】:

显示输出是好的(如果不是图像会更好),但您还应该用文字描述所需的行为。 SELECT ... FROM DUAL 听起来好像你真的在使用 Oracle 【参考方案1】:

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

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)

我再次在这里编写了一个逐步逻辑选择的代码,但我确信有一些数学技巧可以缩短方式

【讨论】:

以上是关于PostgreSQL 分析函数窗口化以查找列中的下一个值的主要内容,如果未能解决你的问题,请参考以下文章

定义窗口并在多个分析列中使用它

Postgresql - 窗口函数聚合

PostgreSQL 如何查找并删除重复数据

PostgreSQL 如何查找并删除重复数据

PostgreSQL 如何查找并删除重复数据

从 Excel 调用 VBA 函数 - 在选定工作表上的选定列中查找