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

如何通过带GROUP BY的单条MySQL查询获取正确的最小与最大值

MySQL: 按日期分组同时获取每日最低和最高温度的正确方法

我来帮你拆解这个问题——你想按日期分组,一次性拿到每天的最低和最高温度,但原查询结果不对,核心问题出在GROUP BY的使用逻辑和非聚合列的处理上。

先看你的问题场景

你有一份包含每日温度记录的表,每行的temp_min和temp_max是同一个值(应该是该时间点的温度),现在需要按日期汇总,得到每天的最低和最高温,同时可能想拿到日期对应的星期几,甚至温度对应的其他字段(比如气压、天气状况)。

你的原查询为什么错了?

先看你写的语句:

SELECT MIN(`temp_min`) AS `temp_min`, 
       MAX(`temp_max`) AS `temp_max`, 
       `dt_txt`, 
       DAYNAME(`dt_txt`) AS `dayname`, 
       `pressure`, 
       `condition` 
FROM infoboard.forecasts 
WHERE `dt_txt` >= CURDATE() 
GROUP BY `dt_txt` 
ORDER BY `dt_txt` ASC;

这里有两个关键问题:

  1. 非聚合列的随机值问题:标准SQL要求GROUP BY子句必须包含所有非聚合函数的列,但MySQL默认允许不这么做(取决于ONLY_FULL_GROUP_BY配置)。这就导致pressure和condition这两个列返回的是分组内随机某一行的值,完全不可控。
  2. 可能的日期过滤/分组偏差:如果dt_txt是DATETIME类型(带时分秒),CURDATE()返回的是当前日期(比如2024-05-20),dt_txt >= CURDATE()会过滤掉当天早于当前时间的记录;如果要按自然日分组,应该用DATE(dt_txt)来提取日期部分,避免时间干扰。

你看到的错误温度值,大概率是因为上述问题导致的计算偏差,或者你的dt_txt字段类型和过滤逻辑不匹配。

正确的解决方案分两种情况

情况1:只需要每日的最低温、最高温、日期和星期几

这是最简单的场景,只需要用聚合函数配合GROUP BY分组列即可,完全符合标准SQL:

SELECT 
    MIN(`temp_min`) AS `daily_min_temp`,  -- 当天所有记录中的最低温
    MAX(`temp_max`) AS `daily_max_temp`,  -- 当天所有记录中的最高温
    `dt_txt`,
    DAYNAME(`dt_txt`) AS `dayname`
FROM infoboard.forecasts
-- 如果dt_txt是DATETIME类型,用DATE()提取日期来过滤和分组
WHERE DATE(`dt_txt`) >= CURDATE()
GROUP BY `dt_txt`
ORDER BY `dt_txt` ASC;

这个查询会准确计算每个日期下的温度极值,结果完全可控。

情况2:还需要获取极值对应的其他字段(比如气压、天气状况)

如果你想知道当天最低温对应的气压是什么,或者最高温对应的天气状况,就需要找到对应极值的那一行数据。这里推荐两种方法:

方法1:子查询关联(兼容所有MySQL版本)

先通过子查询找到每个日期的极值,再关联原表拿到对应行的其他字段:

SELECT 
    min_f.temp_min AS daily_min_temp,
    max_f.temp_max AS daily_max_temp,
    min_f.dt_txt,
    DAYNAME(min_f.dt_txt) AS dayname,
    min_f.pressure AS min_temp_pressure,  -- 最低温对应的气压
    min_f.condition AS min_temp_condition,  -- 最低温对应的天气
    max_f.pressure AS max_temp_pressure,  -- 最高温对应的气压
    max_f.condition AS max_temp_condition  -- 最高温对应的天气
FROM
    -- 找到每个日期最低温的记录
    (SELECT * FROM infoboard.forecasts f
     WHERE (DATE(f.dt_txt), f.temp_min) IN 
           (SELECT DATE(dt_txt), MIN(temp_min) FROM infoboard.forecasts GROUP BY DATE(dt_txt))) min_f
JOIN
    -- 找到每个日期最高温的记录
    (SELECT * FROM infoboard.forecasts f
     WHERE (DATE(f.dt_txt), f.temp_max) IN 
           (SELECT DATE(dt_txt), MAX(temp_max) FROM infoboard.forecasts GROUP BY DATE(dt_txt))) max_f
ON DATE(min_f.dt_txt) = DATE(max_f.dt_txt)
WHERE DATE(min_f.dt_txt) >= CURDATE()
ORDER BY min_f.dt_txt ASC;
方法2:窗口函数(MySQL 8.0+推荐,更简洁)

窗口函数可以直接在分组内给记录排名,轻松拿到极值对应的行:

WITH ranked_forecasts AS (
    SELECT 
        *,
        -- 按日期分组,按最低温升序排名,第一行就是最低温记录
        ROW_NUMBER() OVER (PARTITION BY DATE(dt_txt) ORDER BY temp_min ASC) AS min_rank,
        -- 按日期分组,按最高温降序排名,第一行就是最高温记录
        ROW_NUMBER() OVER (PARTITION BY DATE(dt_txt) ORDER BY temp_max DESC) AS max_rank
    FROM infoboard.forecasts
    WHERE DATE(dt_txt) >= CURDATE()
)
SELECT 
    min_f.temp_min AS daily_min_temp,
    max_f.temp_max AS daily_max_temp,
    min_f.dt_txt,
    DAYNAME(min_f.dt_txt) AS dayname,
    min_f.pressure AS min_temp_pressure,
    min_f.condition AS min_temp_condition,
    max_f.pressure AS max_temp_pressure,
    max_f.condition AS max_temp_condition
FROM ranked_forecasts min_f
JOIN ranked_forecasts max_f
ON DATE(min_f.dt_txt) = DATE(max_f.dt_txt)
WHERE min_f.min_rank = 1 AND max_f.max_rank = 1
ORDER BY min_f.dt_txt ASC;

验证结果

用你给的示例数据,情况1的查询会返回:

+----------------+----------------+----------+--------+
| daily_min_temp | daily_max_temp | dt_txt    | dayname |
+----------------+----------------+----------+--------+
| 5.64           | 14.14          | 2018-05-14| Monday  |
| 8.77           | 13.86          | 2018-05-15| Tuesday |
+----------------+----------------+----------+--------+

内容的提问来源于stack exchange,提问作者6bytes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:35:58