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

如何用JOOQ/SQL按外键barId筛选Foo表中最小time的全字段数据?

解决每个barId分组中取time最小行的问题

这问题我太熟悉了!你碰到的错误是因为SQL的分组规则:当你用GROUP BY的时候,SELECT列表里的列要么得是GROUP BY里的分组字段,要么得用聚合函数(比如MIN()、MAX())处理。但你要的是每个barId分组里整个行的数据,直接GROUP BY barId肯定满足不了,因为id和time既不在分组字段里,也没被聚合,数据库不知道该返回哪一行的这两个值。

下面给你几个实用的解决办法,适配不同的数据库场景:

方法一:通用窗口函数法(推荐,大部分数据库支持)

用ROW_NUMBER()窗口函数给每个barId分组里的行按time排序,然后取排序第一的行:

SELECT id, time, barId
FROM (
    SELECT 
        id, 
        time, 
        barId,
        -- 按barId分组,每组内按time升序排,给行编号
        ROW_NUMBER() OVER (PARTITION BY barId ORDER BY time ASC) AS row_num
    FROM Foo
) ranked_foo
WHERE row_num = 1;

针对你的示例数据,这个查询会给barId=1的两行编号1和2(对应10am和11am),barId=2的两行编号1和2(对应9am和10am),筛选row_num=1就正好拿到行1和4,完全符合预期。

如果你的数据里存在同一个barId有多个相同的最小time,想要返回所有这些行的话,可以把ROW_NUMBER()换成RANK()或者DENSE_RANK(),这样相同最小时间的行都会得到编号1。

方法二:子查询关联法

先通过子查询找出每个barId对应的最小time,再和原表关联匹配出完整行:

SELECT f.id, f.time, f.barId
FROM Foo f
INNER JOIN (
    -- 先拿到每个barId的最小时间
    SELECT barId, MIN(time) AS min_time
    FROM Foo
    GROUP BY barId
) min_times ON f.barId = min_times.barId AND f.time = min_times.min_time;

这个方法逻辑直观,同样能得到你要的结果。和窗口函数不同的是,它会返回所有time等于该barId最小时间的行,适合需要保留重复最小时间行的场景。

方法三:PostgreSQL专属简洁写法

如果你用的是PostgreSQL,可以用DISTINCT ON语法,一行搞定:

SELECT DISTINCT ON (barId) id, time, barId
FROM Foo
ORDER BY barId, time ASC;

DISTINCT ON (barId)会确保每个barId只返回一行,配合ORDER BY barId, time ASC,就会取每个分组里time最小的那一行,非常简洁。

再说说你遇到的错误原因

当你尝试直接GROUP BY barId并SELECT id, time, barId时,数据库无法确定要返回该分组下哪一个id和time——毕竟一个barId对应多行数据。所以必须要么把id也加入GROUP BY(但这样就变成按barId+id分组,不符合你的需求),要么对id用聚合函数(比如MIN(id)),但这样拿到的id不一定是time最小的那行的id,这就是为什么会抛出那个错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:25:33