SQL同表父子关系查询:查找无子父节点及各父节点最新子节点
自关联父子表两类查询实现方案
先约定测试表结构(可根据你的实际表名、字段名对应替换):
- 表名:
node_relation - 核心字段:
id:行主键,自增,数值越大代表数据插入时间越新parent_id:关联父节点的id字段,无父节点时可设为NULL
1. 查找无任何子节点的父节点
优先推荐NOT EXISTS写法,大数据量下性能优于左连接判空:
SELECT n.* FROM node_relation n WHERE NOT EXISTS ( SELECT 1 FROM node_relation child WHERE child.parent_id = n.id );
也可以用左连接实现:
SELECT n.* FROM node_relation n LEFT JOIN node_relation child ON n.id = child.parent_id WHERE child.id IS NULL;
2. 查询存在子节点的父节点对应的最新子节点
支持窗口函数的数据库(MySQL8.0+/PostgreSQL/SQL Server等)
用ROW_NUMBER()窗口函数实现,逻辑清晰易扩展:
WITH child_ranked AS ( SELECT child.*, -- 按父节点分组,子节点id倒序排序,序号为1的就是最新子节点 ROW_NUMBER() OVER (PARTITION BY child.parent_id ORDER BY child.id DESC) AS rn FROM node_relation child WHERE child.parent_id IS NOT NULL ) SELECT parent.id AS parent_id, child_ranked.* FROM node_relation parent INNER JOIN child_ranked ON parent.id = child_ranked.parent_id WHERE child_ranked.rn = 1;
不支持窗口函数的旧版数据库
用分组取最大值再关联实现:
SELECT parent.id AS parent_id, c.* FROM node_relation parent INNER JOIN ( -- 先取每个父节点对应的最新子节点id SELECT parent_id, MAX(id) AS latest_child_id FROM node_relation WHERE parent_id IS NOT NULL GROUP BY parent_id ) latest ON parent.id = latest.parent_id -- 关联回原表取最新子节点完整信息 INNER JOIN node_relation c ON latest.latest_child_id = c.id;
注:如果你的表用
create_time之类的时间字段判断新旧,把上述代码里的ORDER BY child.id DESC替换成ORDER BY child.create_time DESC,MAX(id)替换成MAX(create_time)即可。
内容的提问来源于stack exchange,提问作者Saleem
相关产品推荐
相关产品推荐

