PostgreSQL视窗功能

时间:2018-07-06 11:58:54

标签: sql postgresql window-functions

请考虑以下表格结构:

CREATE TABLE tb_log
(
  id INTEGER PRIMARY KEY,
  moment DATE,
  old INTEGER,
  actual INTEGER
);

包含数据

INSERT INTO
  tb_log ( id, moment, old, actual )
VALUES
  ( 1, '2018-06-19', 10, 20 ),
  ( 2, '2018-06-21', 20, 30 ),
  ( 3, '2018-06-25', 30, 40 );

我正试图从tb_log中获取生效值的时间段(开始日期和结束日期)。

第1次试验-使用lag()功能:

SELECT
  lag( moment ) OVER (ORDER BY moment) date_start,
  moment AS date_end,
  old AS period_value
FROM
   tb_log;

哪个返回以下数据:

| date_start |   date_end | period_value |
|------------|------------|--------------|
|     (null) | 2018-06-19 |           10 |
| 2018-06-19 | 2018-06-21 |           20 |
| 2018-06-21 | 2018-06-25 |           30 |

第2次试验-使用lead()功能:

SELECT
  moment AS date_start,
  lead( moment ) OVER (ORDER BY moment) date_end,
  actual AS period_value
FROM
   tb_log;

哪个返回以下数据:

| date_start |   date_end | period_value |
|------------|------------|--------------|
| 2018-06-19 | 2018-06-21 |           20 |
| 2018-06-21 | 2018-06-25 |           30 |
| 2018-06-25 |     (null) |           40 |

SQLFiddle.com

是否有使用Window Functions返回类似内容的技巧:

| date_start |   date_end | period_value |
|------------|------------|--------------|
|     (null) | 2018-06-19 |           10 |
| 2018-06-19 | 2018-06-21 |           20 |
| 2018-06-21 | 2018-06-25 |           30 |
| 2018-06-25 |     (null) |           40 |

有什么想法吗?

2 个答案:

答案 0 :(得分:6)

使用窗口函数没有技巧,因为窗口函数不会向数据添加行。 (我认为)使用lead()更自然:

(SELECT moment, lead(moment) over (order by moment) as date_end,
       actual AS period_value
 FROM tb_log
)
UNION ALL
(SELECT null, moment, old
 FROM tb_log
 ORDER BY moment
 LIMIT 1
);

通常,使用union all代替union是个好主意。 Union会导致删除重复项的开销。

答案 1 :(得分:4)

    SELECT
      lag( moment ) OVER (ORDER BY moment) date_start,
      moment AS date_end,
      old AS period_value
    FROM
       tb_log
    union
    SELECT
      moment AS date_start,
      lead( moment ) OVER (ORDER BY moment) date_end,
      actual AS period_value
    FROM
       tb_log
order by 3;