在 PostgreSQL 中使用 row_number() 进行透视
Pivot with row_number() in PostgreSQL
我在 PostgreSQL 中有一个 table 模式,用于监视某些设备。基于某些条件,设备进入监控阶段,如果它在接下来的连续几天保持该状态,则设备进入操作阶段。它将保持在行动阶段,直到情况好转。
CREATE TABLE public.monitoring_engine
(
cell_id character varying(1024) COLLATE pg_catalog."default",
monitoring_started_at timestamp without time zone,
gap character varying(1024) COLLATE pg_catalog."default",
status character varying(1024) COLLATE pg_catalog."default"
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.monitoring_engine
OWNER to postgres;
插入语句
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-15', NULL, 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-16', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-17', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-18', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-20', '2 days', 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-15', NULL, 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-17', '2 days', 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-18', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-20', '2 days', 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-21', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-23', '2 days', 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-24', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-25', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-26', '1 day', 'Action');
执行上述查询后,table.
中将提供以下数据
cell_id monitoring_started_at gap status
Cell_A 9/15/2020 0:00 NULL Monitor
Cell_A 9/16/2020 0:00 1 day Action
Cell_A 9/17/2020 0:00 1 day Action
Cell_A 9/18/2020 0:00 1 day Action
Cell_A 9/20/2020 0:00 2 days Monitor
Cell_B 9/15/2020 0:00 NULL Monitor
Cell_B 9/17/2020 0:00 2 days Monitor
Cell_B 9/18/2020 0:00 1 day Action
Cell_B 9/20/2020 0:00 2 days Monitor
Cell_B 9/21/2020 0:00 1 day Action
Cell_B 9/23/2020 0:00 2 days Monitor
Cell_B 9/24/2020 0:00 1 day Action
Cell_B 9/25/2020 0:00 1 day Action
Cell_B 9/26/2020 0:00 1 day Action
需要输出
cell_id monitor_date first_action_date last_action_date
Cell_A 9/15/2020 0:00 9/16/2020 0:00 9/18/2020 0:00
Cell_A 9/20/2020 0:00 null null
Cell_B 9/15/2020 0:00 null null
Cell_B 9/17/2020 0:00 9/18/2020 0:00 9/18/2020 0:00
Cell_B 9/20/2020 0:00 9/21/2020 0:00 9/21/2020 0:00
Cell_B 9/23/2020 0:00 9/24/2020 0:00 9/26/2020 0:00
所需的输出将取决于连续的日期。如果日期的连续性有任何中断,则设备进入监控阶段。
需要在 PostgreSQL 中完成。
这是一个 gaps-and-islands 问题。我认为最简单的方法是计算最新“Monitor”状态的日期,然后用它来对行进行分组。
select
cell_id,
monitor_date,
min(monitoring_started_at) filter(where status = 'Action') first_action_date,
max(monitoring_started_at) filter(where status = 'Action') last_action_date
from (
select me.*,
max(monitoring_started_at)
filter(where status = 'Monitor')
over(partition by cell_id order by monitoring_started_at)
as monitor_date
from monitoring_engine me
) t
group by cell_id, monitor_date
order by cell_id, monitor_date
cell_id | monitor_date | first_action_date | last_action_date
:------ | :------------------ | :------------------ | :------------------
Cell_A | 2020-09-15 00:00:00 | 2020-09-16 00:00:00 | 2020-09-18 00:00:00
Cell_A | 2020-09-20 00:00:00 | null | null
Cell_B | 2020-09-15 00:00:00 | null | null
Cell_B | 2020-09-17 00:00:00 | 2020-09-18 00:00:00 | 2020-09-18 00:00:00
Cell_B | 2020-09-20 00:00:00 | 2020-09-21 00:00:00 | 2020-09-21 00:00:00
Cell_B | 2020-09-23 00:00:00 | 2020-09-24 00:00:00 | 2020-09-26 00:00:00
我在 PostgreSQL 中有一个 table 模式,用于监视某些设备。基于某些条件,设备进入监控阶段,如果它在接下来的连续几天保持该状态,则设备进入操作阶段。它将保持在行动阶段,直到情况好转。
CREATE TABLE public.monitoring_engine
(
cell_id character varying(1024) COLLATE pg_catalog."default",
monitoring_started_at timestamp without time zone,
gap character varying(1024) COLLATE pg_catalog."default",
status character varying(1024) COLLATE pg_catalog."default"
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.monitoring_engine
OWNER to postgres;
插入语句
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-15', NULL, 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-16', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-17', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-18', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_A', '2020-09-20', '2 days', 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-15', NULL, 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-17', '2 days', 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-18', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-20', '2 days', 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-21', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-23', '2 days', 'Monitor');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-24', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-25', '1 day', 'Action');
INSERT INTO public.monitoring_engine(cell_id, monitoring_started_at, gap, status) VALUES ('Cell_B', '2020-09-26', '1 day', 'Action');
执行上述查询后,table.
中将提供以下数据cell_id monitoring_started_at gap status
Cell_A 9/15/2020 0:00 NULL Monitor
Cell_A 9/16/2020 0:00 1 day Action
Cell_A 9/17/2020 0:00 1 day Action
Cell_A 9/18/2020 0:00 1 day Action
Cell_A 9/20/2020 0:00 2 days Monitor
Cell_B 9/15/2020 0:00 NULL Monitor
Cell_B 9/17/2020 0:00 2 days Monitor
Cell_B 9/18/2020 0:00 1 day Action
Cell_B 9/20/2020 0:00 2 days Monitor
Cell_B 9/21/2020 0:00 1 day Action
Cell_B 9/23/2020 0:00 2 days Monitor
Cell_B 9/24/2020 0:00 1 day Action
Cell_B 9/25/2020 0:00 1 day Action
Cell_B 9/26/2020 0:00 1 day Action
需要输出
cell_id monitor_date first_action_date last_action_date
Cell_A 9/15/2020 0:00 9/16/2020 0:00 9/18/2020 0:00
Cell_A 9/20/2020 0:00 null null
Cell_B 9/15/2020 0:00 null null
Cell_B 9/17/2020 0:00 9/18/2020 0:00 9/18/2020 0:00
Cell_B 9/20/2020 0:00 9/21/2020 0:00 9/21/2020 0:00
Cell_B 9/23/2020 0:00 9/24/2020 0:00 9/26/2020 0:00
所需的输出将取决于连续的日期。如果日期的连续性有任何中断,则设备进入监控阶段。
需要在 PostgreSQL 中完成。
这是一个 gaps-and-islands 问题。我认为最简单的方法是计算最新“Monitor”状态的日期,然后用它来对行进行分组。
select
cell_id,
monitor_date,
min(monitoring_started_at) filter(where status = 'Action') first_action_date,
max(monitoring_started_at) filter(where status = 'Action') last_action_date
from (
select me.*,
max(monitoring_started_at)
filter(where status = 'Monitor')
over(partition by cell_id order by monitoring_started_at)
as monitor_date
from monitoring_engine me
) t
group by cell_id, monitor_date
order by cell_id, monitor_date
cell_id | monitor_date | first_action_date | last_action_date :------ | :------------------ | :------------------ | :------------------ Cell_A | 2020-09-15 00:00:00 | 2020-09-16 00:00:00 | 2020-09-18 00:00:00 Cell_A | 2020-09-20 00:00:00 | null | null Cell_B | 2020-09-15 00:00:00 | null | null Cell_B | 2020-09-17 00:00:00 | 2020-09-18 00:00:00 | 2020-09-18 00:00:00 Cell_B | 2020-09-20 00:00:00 | 2020-09-21 00:00:00 | 2020-09-21 00:00:00 Cell_B | 2020-09-23 00:00:00 | 2020-09-24 00:00:00 | 2020-09-26 00:00:00