You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现admission表中按15分钟时间段分组统计公司入院记录?

按15分钟时间段分组统计入院记录问题

实验用表结构及数据

CREATE TABLE IF NOT EXISTS admission
(
    id integer NOT NULL DEFAULT serial,
    ad_date timestamp without time zone,
    company integer,
    CONSTRAINT admission_pkey PRIMARY KEY (id)
);
INSERT INTO admission (ad_date, company) VALUES
     ('2014-03-03 20:46:33',1),
     ('2014-03-03 20:49:13',1),
     ('2014-03-03 21:01:03',1),
     ('2014-03-03 21:01:06',1),
     ('2014-03-03 21:02:16',1),
     ('2014-03-03 21:02:22',1),
     ('2014-03-03 21:15:48',1),
     ('2014-03-03 21:16:19',1);

注:原INSERT语句中的company_id为笔误,对应表字段应为company

需求

将某公司的入院记录按每15分钟为一个时间段分组统计,每个时间段需展示:

  • 该组的起始日期(组内最早的记录时间)
  • 该时间段内最后一条记录的日期(组内最晚的记录时间)
  • 记录总数
  • 公司ID

预期输出

start_date                   next_15_min_date             total_count   company 
2014-03-03 20:46:33.000     2014-03-03 21:01:06.000           4            1
2014-03-03 21:02:16.000     2014-03-03 21:16:19.000           4            1

尝试的SQL(未得到预期结果)

select t1.ad_date as start_date ,t2.ad_date as next_15_min_date , count(t2.ad_date),t2.company 
from admission t1,admission t2
where t2.ad_date between  t1.ad_date and t1.ad_date+interval '15 minute'
group by t1.ad_date,t2.ad_date,t2.company
order by t1.ad_date,t2.ad_date,t2.company

解决方案

原SQL的问题在于自连接逻辑错误,导致生成大量重复分组,无法得到正确的聚合结果。以下是两种适配需求的PostgreSQL解决方案:

方案1:匹配预期输出的连续时间段分组

该方案基于记录的连续时间划分窗口,以上一个窗口结束时间作为下一个窗口的起点,完全贴合你的预期输出:

WITH ranked_records AS (
    SELECT 
        ad_date,
        company,
        -- 计算每条记录与前一条的时间差,超过15分钟则开启新分组
        SUM(CASE WHEN ad_date - LAG(ad_date, 1, ad_date) OVER (PARTITION BY company ORDER BY ad_date) > INTERVAL '15 minutes' THEN 1 ELSE 0 END) OVER (PARTITION BY company ORDER BY ad_date) AS group_id
    FROM admission
    WHERE company = 1 -- 指定目标公司
)
SELECT 
    MIN(ad_date) AS start_date,
    MAX(ad_date) AS next_15_min_date,
    COUNT(*) AS total_count,
    company
FROM ranked_records
GROUP BY company, group_id
ORDER BY start_date;

方案2:固定时间桶分组(可选)

如果需要按整点/15分的固定时间间隔分组(比如20:45-21:00、21:00-21:15这类固定窗口),可以使用时间截断函数:

SELECT 
    DATE_TRUNC('minute', ad_date) - INTERVAL '1 minute' * ((EXTRACT(minute FROM ad_date)::int % 15)) AS start_date,
    MAX(ad_date) AS next_15_min_date,
    COUNT(*) AS total_count,
    company
FROM admission
WHERE company = 1
GROUP BY company, DATE_TRUNC('minute', ad_date) - INTERVAL '1 minute' * ((EXTRACT(minute FROM ad_date)::int % 15))
ORDER BY start_date;

内容的提问来源于stack exchange,提问作者Avinash Ware

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:22:47