MySQL如何在父ID非空时分组行并保留无父ID数据?
解决MySQL中按父ID分组并保留无父ID记录的问题
看起来你已经找对了方向,但还差几步就能拿到想要的结果。你的原SQL只返回有父ID的记录,是因为GROUP BY parentID会把所有parentID为NULL的行合并成一组,而且你也没处理日期合并和主记录字段的选取。
这里给你一个能满足需求的SQL语句:
SELECT -- 定义分组依据:无父ID则用自身ID,有父ID则用父ID COALESCE(n.parent_id, n.id) AS group_key, -- 获取每组对应的主记录ID:无父ID取自身,有父ID取父记录ID MAX(CASE WHEN n.parent_id IS NULL THEN n.id ELSE p.id END) AS ID, -- 获取每组对应的主记录名称:逻辑同上 MAX(CASE WHEN n.parent_id IS NULL THEN n.name ELSE p.name END) AS NAME, -- 合并该组所有日期,按顺序排列并用 / 分隔,去重避免重复日期 GROUP_CONCAT(DISTINCT n.date ORDER BY n.date SEPARATOR ' / ') AS date, -- 保留父ID(无父ID则为NULL) MAX(n.parent_id) AS PARENT_ID FROM names n -- 关联父记录,用于获取父ID对应的主记录信息 LEFT JOIN names p ON n.parent_id = p.id -- 按我们定义的分组键分组,确保无父ID的行单独成组 GROUP BY group_key -- 按ID排序,和你期望的结果顺序一致 ORDER BY ID;
关键部分解释:
COALESCE(n.parent_id, n.id):这是核心的分组逻辑,当parent_id为空时,用当前行的id作为分组标识,这样每个无父ID的行都会单独成为一组;当parent_id不为空时,统一用父ID分组,把所有属于同一个父节点的行归为一组。GROUP_CONCAT(...):专门用来合并字符串类型的字段,这里我们指定了按日期排序、用/分隔,还加了DISTINCT去重(如果你的场景不需要去重,可以去掉这个关键字)。LEFT JOIN:关联父表是为了获取父ID对应的主记录的ID和NAME,这样分组后显示的是父节点的基础信息,而不是子节点的。
执行这个语句后,就能得到你期望的结果:
ID | NAME | date | PARENT ID
1 | John Doe | 2018-01-12 |
2 | Doe John | 2018-01-12 / 2018-03-22 |
另外补充一点:如果你的日期合并后长度超过默认限制,可以通过调整group_concat_max_len参数来扩大容量,比如执行SET GLOBAL group_concat_max_len = 10240;(根据实际需求调整数值)。
内容的提问来源于stack exchange,提问作者Gurdt
相关产品推荐
相关产品推荐

