我有一个具有以下结构的表
table
unit date_active date_inactive
a 2018-01-01 NULL
b 2018-01-01 2020-07-05
c 2019-02-01 2020-01-01
我需要一个查询来生成从首次活动日期到今天的按月活动单位总数。输出需要遵循以下内容:
2018-01-01 2
2018-02-01 2
....
当日期不活动为 NULL 时,该单位今天仍然处于活动状态。我正在使用 PostgreSQL
生成一系列日期,将其连接到表中并计算每个日期的单位:
select m::date as month, count(unit)
from generate_series('2018-01-01'::date, '2020-12-31', '1 month') m
left join my_table on m::date between date_active and coalesce(date_inactive, 'infinity')
group by 1
order by 1
就像库存查询一样。
建立一个中间两列表
counters
,以开始日期和+1作为计数器,UNION ALL结束日期和-1作为计数器。
在该中间表上运行计数器的运行总和。
WITH
counters(dt,counter) AS (
SELECT
date_active
, 1
FROM input
UNION ALL
SELECT
date_inactive
, -1
FROM input
)
SELECT
dt
, SUM(counter) OVER(ORDER BY ts) AS active_count
FROM counters;
一个选项对行进行逆透视,然后聚合:
select x.dt, sum(sum(x.cnt)) over(order by x.dt) cnt
from mytable t
cross join lateral (values
(date_active, 1),
(date_inactive, -1)
) x(dt, cnt)
where x.dt is not null
group by x.dt
order by x.dt
这是一个完全类似的场景 - 只是它是时间戳而不是基于日期...针对 PostgreSQL 12.4 运行它。
WITH
input(unit,ts_active,ts_inactive) AS (
SELECT 'w',TIMESTAMP '2020-08-13 00:58:14.528778',TIMESTAMP '2020-08-13 00:58:14.552428'
UNION ALL SELECT 'w',TIMESTAMP '2020-08-13 00:59:32.022632',TIMESTAMP '2020-08-13 00:59:32.042015'
UNION ALL SELECT 'w',TIMESTAMP '2020-08-13 01:20:31.555526',TIMESTAMP '2020-08-13 01:20:31.599932'
UNION ALL SELECT 'w',TIMESTAMP '2020-08-13 01:23:55.585023',TIMESTAMP '2020-08-13 01:23:55.655960'
UNION ALL SELECT 'c',TIMESTAMP '2020-08-13 16:09:40.286047',TIMESTAMP '2020-08-13 16:09:40.332600'
UNION ALL SELECT 'c',TIMESTAMP '2020-08-13 16:09:51.887808',TIMESTAMP '2020-08-13 16:09:51.913150'
UNION ALL SELECT 'c',TIMESTAMP '2020-08-13 16:09:51.919182',TIMESTAMP '2020-08-13 16:09:52.023836'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 16:11:11.904413',TIMESTAMP '2020-08-13 16:11:11.921197'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 16:11:25.617580',TIMESTAMP '2020-08-13 16:11:26.084465'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 16:11:25.624842',TIMESTAMP '2020-08-13 16:11:25.631024'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 16:11:25.640343',TIMESTAMP '2020-08-13 16:11:25.647049'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 16:11:25.655991',TIMESTAMP '2020-08-13 16:11:25.662542'
UNION ALL SELECT 'i',TIMESTAMP '2020-08-13 16:11:25.691300',TIMESTAMP '2020-08-13 16:11:25.934098'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 16:11:25.958651',TIMESTAMP '2020-08-13 16:11:26.032297'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 16:11:26.076818',TIMESTAMP '2020-08-13 16:11:26.083056'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 16:23:23.779083',TIMESTAMP '2020-08-13 16:23:23.812426'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 16:23:34.150468',TIMESTAMP '2020-08-13 16:23:34.176461'
UNION ALL SELECT 't',TIMESTAMP '2020-08-13 17:30:16.483214',TIMESTAMP '2020-08-13 17:30:16.490638'
UNION ALL SELECT 'c',TIMESTAMP '2020-08-13 17:30:16.492756',TIMESTAMP '2020-08-13 17:30:16.505191'
UNION ALL SELECT 's',TIMESTAMP '2020-08-13 17:30:29.819721',TIMESTAMP '2020-08-13 17:30:29.957229'
)
,
counters(ts,counter) AS (
SELECT
ts_active
, 1
FROM input
UNION ALL
SELECT
ts_inactive
, -1
FROM input
)
SELECT
ts
, SUM(counter) OVER(ORDER BY ts) AS active_count
FROM counters;
ts | active_count
----------------------------+--------------
2020-08-13 00:58:14.528778 | 1
2020-08-13 00:58:14.552428 | 0
2020-08-13 00:59:32.022632 | 1
2020-08-13 00:59:32.042015 | 0
2020-08-13 01:20:31.555526 | 1
2020-08-13 01:20:31.599932 | 0
2020-08-13 01:23:55.585023 | 1
2020-08-13 01:23:55.65596 | 0
2020-08-13 16:09:40.286047 | 1
2020-08-13 16:09:40.3326 | 0
2020-08-13 16:09:51.887808 | 1
2020-08-13 16:09:51.91315 | 0
2020-08-13 16:09:51.919182 | 1
2020-08-13 16:09:52.023836 | 0
2020-08-13 16:11:11.904413 | 1
2020-08-13 16:11:11.921197 | 0
2020-08-13 16:11:25.61758 | 1
2020-08-13 16:11:25.624842 | 2
2020-08-13 16:11:25.631024 | 1
2020-08-13 16:11:25.640343 | 2
2020-08-13 16:11:25.647049 | 1
2020-08-13 16:11:25.655991 | 2
2020-08-13 16:11:25.662542 | 1
2020-08-13 16:11:25.6913 | 2
2020-08-13 16:11:25.934098 | 1
2020-08-13 16:11:25.958651 | 2
2020-08-13 16:11:26.032297 | 1
2020-08-13 16:11:26.076818 | 2
2020-08-13 16:11:26.083056 | 1
2020-08-13 16:11:26.084465 | 0
2020-08-13 16:23:23.779083 | 1
2020-08-13 16:23:23.812426 | 0
2020-08-13 16:23:34.150468 | 1
2020-08-13 16:23:34.176461 | 0
2020-08-13 17:30:16.483214 | 1
2020-08-13 17:30:16.490638 | 0
2020-08-13 17:30:16.492756 | 1
2020-08-13 17:30:16.505191 | 0
2020-08-13 17:30:29.819721 | 1
2020-08-13 17:30:29.957229 | 0