SQL单查询实现:按日期分组获取首尾记录及价格最值
解决方案:单条SQL实现日期分组的多维度价格统计
当然可以用单条SQL完美实现你的需求!我帮你拆解思路,再给出适配不同数据库的示例代码~
首先明确你的核心需求:按日期分组,每组需要拿到四个关键值:
- 当日小时最早的记录对应的价格
- 当日小时最晚的记录对应的价格
- 当日所有记录中的最高价格
- 当日所有记录中的最低价格
核心思路
利用窗口函数标记出每个日期下小时最早/最晚的记录,再结合外层的聚合函数提取对应价格,同时直接计算当日的极值。这种方法高效且逻辑清晰,完全可以用单条SQL完成。
示例代码(以Oracle为例)
假设你的数据表名为price_records,包含record_date(datetime类型,格式如2024-05-20 08:30:00)和price(数值型)两个核心字段:
SELECT TRUNC(record_date) AS record_day, -- 提取当日小时最早的价格 MAX(CASE WHEN rn_asc = 1 THEN price END) AS earliest_hour_price, -- 提取当日小时最晚的价格 MAX(CASE WHEN rn_desc = 1 THEN price END) AS latest_hour_price, -- 当日最高价格 MAX(price) AS daily_max_price, -- 当日最低价格 MIN(price) AS daily_min_price FROM ( SELECT record_date, price, -- 按日期分区,小时升序编号,最早的那条标记为1 ROW_NUMBER() OVER (PARTITION BY TRUNC(record_date) ORDER BY EXTRACT(HOUR FROM record_date) ASC) AS rn_asc, -- 按日期分区,小时降序编号,最晚的那条标记为1 ROW_NUMBER() OVER (PARTITION BY TRUNC(record_date) ORDER BY EXTRACT(HOUR FROM record_date) DESC) AS rn_desc FROM price_records ) t GROUP BY TRUNC(record_date) ORDER BY record_day;
适配其他数据库的版本
如果用的是MySQL,只需要调整日期处理函数即可:
SELECT DATE(record_date) AS record_day, MAX(CASE WHEN rn_asc = 1 THEN price END) AS earliest_hour_price, MAX(CASE WHEN rn_desc = 1 THEN price END) AS latest_hour_price, MAX(price) AS daily_max_price, MIN(price) AS daily_min_price FROM ( SELECT record_date, price, ROW_NUMBER() OVER (PARTITION BY DATE(record_date) ORDER BY HOUR(record_date) ASC) AS rn_asc, ROW_NUMBER() OVER (PARTITION BY DATE(record_date) ORDER BY HOUR(record_date) DESC) AS rn_desc FROM price_records ) t GROUP BY DATE(record_date) ORDER BY record_day;
为什么你之前的尝试没成功?
DISTINCT(date):DISTINCT是对整行数据去重,不是分组统计,所以无法帮你聚合每个日期下的多维度数据;- 单独用
TRUNC:TRUNC只是把日期截断到天,但如果不配合聚合函数或窗口函数,你只能拿到每个日期的唯一值,无法关联到对应的价格信息。
内容的提问来源于stack exchange,提问作者Dreg Korig




