我在 PostgreSQL 工作。
我有一个表,用于存储有关客户及其在不同组中的状态的信息。我想要一个选择查询来显示这些信息,例如句点而不是事件结构。因此它将显示 client_id、moment_start、moment_end、status_group 和 status(布尔值)。虽然我可以使用 Lead(),但我得到的结果是客户端的下一个具有相同状态的周期是另一条记录,而我想要获取状态从行到行发生变化的周期(通过 client_id 和 status_group)。实际上,我使用时间戳(6)而不是日期。
我应该在查询中写什么来实现这一点?
原表:
id | client_id | 时刻 | 状态组 | 状态 |
---|---|---|---|---|
1 | 1 | 2021-05-01 | A | 正确 |
2 | 1 | 2021-05-05 | A | 正确 |
3 | 1 | 2021-05-07 | A | 错误 |
4 | 1 | 2021-06-10 | A | 正确 |
5 | 2 | 2021-07-10 | A | 正确 |
6 | 2 | 2021-05-10 | B | 错误 |
所需表格:
client_id | 时刻_开始 | 时刻_结束 | 状态组 | 状态 |
---|---|---|---|---|
1 | 2021-05-01 | 2021-05-07 | A | 正确 |
1 | 2021-05-07 | 2021-06-10 | A | 错误 |
1 | 2021-06-10 | 空 | A | 正确 |
2 | 2021-07-10 | 空 | A | 正确 |
2 | 2021-05-10 | 空 | B | 错误 |
我尝试过:
SELECT
client_id,
moment AS moment_start
LEAD(moment) OVER (PARTITION BY client_id, group ORDER BY moment) AS moment_end,
status_group,
status
FROM table
ORDER BY client_id, moment_start
我拿到的桌子:
client_id | 时刻_开始 | 时刻_结束 | 状态组 | 状态 |
---|---|---|---|---|
1 | 2021-05-01 | 2021-05-05 | A | 正确 |
1 | 2021-05-05 | 2021-05-07 | A | 正确 |
1 | 2021-05-07 | 2021-06-10 | A | 错误 |
1 | 2021-06-10 | 空 | A | 正确 |
2 | 2021-07-10 | 空 | A | 正确 |
2 | 2021-05-10 | 空 | B | 错误 |
以下查询演示了一种仅提取状态更改的方法:
WITH
example_data (id, client_id, moment, status_group, status) AS (
VALUES
(1, 1, '2021-05-01'::TIMESTAMP, 'A', TRUE),
(2, 1, '2021-05-05'::TIMESTAMP, 'A', TRUE),
(3, 1, '2021-05-07'::TIMESTAMP, 'A', FALSE),
(4, 1, '2021-06-10'::TIMESTAMP, 'A', TRUE),
(5, 2, '2021-07-10'::TIMESTAMP, 'A', TRUE),
(6, 2, '2021-05-10'::TIMESTAMP, 'B', FALSE)
),
changes AS (
SELECT
d.id,
d.client_id,
d.moment,
d.status_group,
d.status,
(d.status_group, d.status) IS DISTINCT FROM (LAG(d.status_group) OVER client_moment,
LAG(d.status) OVER client_moment) AS client_status_changed
FROM
example_data d
WINDOW
client_moment AS (PARTITION BY d.client_id, d.status_group ORDER BY d.moment)
)
SELECT
c.client_id,
c.moment,
c.status_group,
c.status
FROM
changes c
WHERE
c.client_status_changed
ORDER BY
c.client_id, c.moment;
产生以下结果:
client_id | 瞬间 | 状态组 | 状态 |
---|---|---|---|
1 | 2021-05-01 00:00:00 | A | 真实 |
1 | 2021-05-07 00:00:00 | A | 假 |
1 | 2021-06-10 00:00:00 | A | 真实 |
2 | 2021-05-10 00:00:00 | B | 假 |
2 | 2021-07-10 00:00:00 | A | 真实 |
查询使用命名窗口框架来减少冗余代码。通过使用主查询中的
moment_start
函数,可以轻松修改查询以返回包括 moment_end
和 LAG
。