PostgreSQL Window 函数
PostgreSQL Window Functions
考虑以下 table 结构:
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;
其中return以下数据:
| 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;
其中return以下数据:
| 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 |
是否有使用 Window Functions
到 return 的任何技巧,如下所示:
| 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 |
有什么想法吗?
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;
使用 window 函数没有技巧,因为 window 函数不会向数据添加行。使用 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
会产生删除重复项的开销。
考虑以下 table 结构:
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;
其中return以下数据:
| 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;
其中return以下数据:
| 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 |
是否有使用 Window Functions
到 return 的任何技巧,如下所示:
| 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 |
有什么想法吗?
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;
使用 window 函数没有技巧,因为 window 函数不会向数据添加行。使用 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
会产生删除重复项的开销。