好家伙... 六、 方案三:CTE+ 手动迭代‑‑让递归回家🏡 🚀🚀🚀
If your RDBMS provides a “WITH RECURSIVE” clause , you can still write classic recursive queries even when UI hides feature. Example for MySQL:
WITH RECURSIVE dept_tree AS (
SELECT id, name, parent_id, CAST AS path, 1 AS lvl
FROM org_dept WHERE parent_id IS NULL
UNION ALL
SELECT c.id,c.name,c.parent_id,
CONCAT,
p.lvl+1
FROM org_dept c JOIN dept_tree p ON c.parent_id=p.id
)
SELECT * FROM dept_tree ORDER BY path;
这段代码只需一次提交,就能得到完整树形列表。
别忘了给服务器加装一点绿植, 让 CPU 散热更好,也让运维同事心情舒畅——这可是「多孩子、多种树」精神的实际体现哦!😉🪴🪴🪴
"
五、 方案二:临时表 + 批量填充️️️️
步骤概览:
Create Temporary Table: 创建一个结构与目标层次相同的临时表,如TEMP_DEPT_TREE.
Purge & Seed: 先清空,再把根节点插入,path 为根 ID,depth=1.
Cascade Insert: 利用 WHILE 循环或存储过程,每轮把上一轮产生的子节点写入临时表,并更新 path 与 depth.
Select From Temp: 到头来 SELECT 即可得到完整树形结构,无需再做递归.
\`\`\`sql
-- 创建临时表
CREATE TEMPORARY TABLE temp_dept_tree (
id INT PRIMARY KEY,
parent_id INT,
path VARCHAR,
depth TINYINT
);
-- 插入根节点
INSERT INTO temp_dept_tree
SELECT id,parent_id,CAST,1 FROM org_dept WHERE parent_id IS NULL;
-- 循环填充子节点
DECLARE done INT DEFAULT FALSE;
DECLARE cur CURSOR FOR SELECT id FROM org_dept WHERE parent_id IN ;
-- ...循环体略...
\`\`\`
此方案特别适合月度/季度报表,主要原因是报表窗口期可以提前跑一次把后来啊写进缓存库,下游系统直接读取即可。
如果需要更深层,只要继续 LEFT JOIN 第三、第四…层即可。实际项目里我们常把「最大深度」设为5~7,足以覆盖大多数组织树。
温馨提醒:
A 表记录越少, JOIN 的开销越低;所以请务必在 ID、ParentID 上建立B‑Tree 索引。
如果业务允许,可以定期把展开好的树保存进物化视图或缓存表, 把后续读取压缩到毫秒级,这玩意儿...。
关键点是为每一行准备「路径」字段,比方说 “1/2/a1”。这样即使没有递归语法,也能通过 LIKE 或者 FIND_IN_SET 来定位子孙。
SELECT
child.id,
child.name,
parent.path || '/' || child.id AS path
FROM org_dept AS child
LEFT JOIN org_dept AS parent
ON child.parent_id = parent.id;
上述语句一次返回两层结构。
好家伙... 六、 方案三:CTE+ 手动迭代‑‑让递归回家🏡 🚀🚀🚀
If your RDBMS provides a “WITH RECURSIVE” clause , you can still write classic recursive queries even when UI hides feature. Example for MySQL:
WITH RECURSIVE dept_tree AS (
SELECT id, name, parent_id, CAST AS path, 1 AS lvl
FROM org_dept WHERE parent_id IS NULL
UNION ALL
SELECT c.id,c.name,c.parent_id,
CONCAT,
p.lvl+1
FROM org_dept c JOIN dept_tree p ON c.parent_id=p.id
)
SELECT * FROM dept_tree ORDER BY path;
这段代码只需一次提交,就能得到完整树形列表。
别忘了给服务器加装一点绿植, 让 CPU 散热更好,也让运维同事心情舒畅——这可是「多孩子、多种树」精神的实际体现哦!😉🪴🪴🪴
"
五、 方案二:临时表 + 批量填充️️️️
步骤概览:
Create Temporary Table: 创建一个结构与目标层次相同的临时表,如TEMP_DEPT_TREE.
Purge & Seed: 先清空,再把根节点插入,path 为根 ID,depth=1.
Cascade Insert: 利用 WHILE 循环或存储过程,每轮把上一轮产生的子节点写入临时表,并更新 path 与 depth.
Select From Temp: 到头来 SELECT 即可得到完整树形结构,无需再做递归.
\`\`\`sql
-- 创建临时表
CREATE TEMPORARY TABLE temp_dept_tree (
id INT PRIMARY KEY,
parent_id INT,
path VARCHAR,
depth TINYINT
);
-- 插入根节点
INSERT INTO temp_dept_tree
SELECT id,parent_id,CAST,1 FROM org_dept WHERE parent_id IS NULL;
-- 循环填充子节点
DECLARE done INT DEFAULT FALSE;
DECLARE cur CURSOR FOR SELECT id FROM org_dept WHERE parent_id IN ;
-- ...循环体略...
\`\`\`
此方案特别适合月度/季度报表,主要原因是报表窗口期可以提前跑一次把后来啊写进缓存库,下游系统直接读取即可。
如果需要更深层,只要继续 LEFT JOIN 第三、第四…层即可。实际项目里我们常把「最大深度」设为5~7,足以覆盖大多数组织树。
温馨提醒:
A 表记录越少, JOIN 的开销越低;所以请务必在 ID、ParentID 上建立B‑Tree 索引。
如果业务允许,可以定期把展开好的树保存进物化视图或缓存表, 把后续读取压缩到毫秒级,这玩意儿...。
关键点是为每一行准备「路径」字段,比方说 “1/2/a1”。这样即使没有递归语法,也能通过 LIKE 或者 FIND_IN_SET 来定位子孙。
SELECT
child.id,
child.name,
parent.path || '/' || child.id AS path
FROM org_dept AS child
LEFT JOIN org_dept AS parent
ON child.parent_id = parent.id;
上述语句一次返回两层结构。