如何按ID分组筛选每组最早日期的行并正确保留TYPE字段?
解决GROUP BY查询中TYPE字段"非GROUP BY表达式"错误的方案
现有INPUT表包含ID、DATE、TYPE字段,需生成OUTPUT表保留每个ID对应的最早日期记录及对应TYPE字段。使用GROUP BY ID结合MIN(DATE)的SQL语句时,TYPE字段报**"非GROUP BY表达式"**错误,以下是问题详情及解决方法:
输入输出示例
INPUT表
| ID | DATE | TYPE |
|---|---|---|
| 884 | 2017-03-16 06:08:40 | B |
| 857 | 2017-03-24 07:14:29 | A |
| 857 | 2017-06-24 12:15:29 | A |
| 884 | 2017-10-05 00:33:08 | A |
| 255 | 2019-08-02 02:47:22 | B |
期望OUTPUT表
| ID | DATE | TYPE |
|---|---|---|
| 884 | 2017-03-16 06:08:40 | B |
| 857 | 2017-03-24 07:14:29 | A |
| 255 | 2019-08-02 02:47:22 | B |
原错误SQL及报错信息
尝试的SQL语句:
create OUTPUT as select ID, min(DATE) as DATE, TYPE from INPUT group by ID
报错信息:非GROUP BY表达式
错误原因
SQL分组查询规则要求:SELECT子句中的字段要么是GROUP BY中指定的分组字段,要么是被聚合函数(如MIN、MAX)包裹的字段。原SQL中TYPE既不在GROUP BY列表,也未使用聚合函数,数据库无法确定该返回对应ID下哪条记录的TYPE值,因此报错。
解决方案
方案1:子查询关联(通用兼容多数数据库)
先通过子查询获取每个ID的最早日期,再关联原表获取对应TYPE:
CREATE OUTPUT AS SELECT i.ID, i.DATE, i.TYPE FROM INPUT i INNER JOIN ( SELECT ID, MIN(DATE) AS MIN_DATE FROM INPUT GROUP BY ID ) t ON i.ID = t.ID AND i.DATE = t.MIN_DATE;
方案2:窗口函数(适用于支持窗口函数的数据库,如MySQL 8+、Oracle、PostgreSQL等)
使用ROW_NUMBER()窗口函数为每个ID的记录按日期排序,取排序为1的记录:
CREATE OUTPUT AS SELECT ID, DATE, TYPE FROM ( SELECT ID, DATE, TYPE, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DATE ASC) AS rn FROM INPUT ) t WHERE rn = 1;
如果同一ID存在多条相同最早日期的记录,ROW_NUMBER()会随机取一条;若需保留所有相同最早日期的记录,可改用RANK()或DENSE_RANK()替换ROW_NUMBER()。
方案3:聚合函数结合CASE(仅当同一ID最早日期对应的TYPE唯一时适用)
如果能确保每个ID的最早日期对应唯一TYPE,可使用MIN()或MAX()聚合TYPE:
CREATE OUTPUT AS SELECT ID, MIN(DATE) AS DATE, MIN(TYPE) AS TYPE -- 或MAX(TYPE),结果一致 FROM INPUT GROUP BY ID;
此方案仅在同一ID最早日期的TYPE无歧义时使用,否则可能返回错误的TYPE值。
内容的提问来源于stack exchange,提问作者pietrodito
相关产品推荐
相关产品推荐

