如何使用 CTE 对相邻列表的父母和所有兄弟姐妹进行排序?

问题描述

这是我的桌子:

CREATE TABLE IF NOT EXISTS NODE 
(
    UUID VARCHAR NOT NULL,PARENT_UUID VARCHAR NULL,NAME VARCHAR NOT NULL,PRIMARY KEY (UUID)
);

这是我的测试数据:

INSERT INTO node (uuid,parent_uuid,name)
VALUES 
('dfca05bc-551d-4e3d-87aa-7dd7d29539f6',null,'Computers'),('ff83eb99-ea2c-4d11-8ebe-4600445a3bda','Food'),('405f0267-fa22-4cac-a397-c430be221828','Drinks'),('e79ecefa-c3e2-400f-aab4-2d28fcd3a832','dfca05bc-551d-4e3d-87aa-7dd7d29539f6','Monitors'),('61a94b77-56c2-48ff-b869-39305648a25c','System blocks'),('5d88a9b7-7ffe-45e5-b35f-9350072ed619','Mother boards'),('5994c39d-c4ea-454c-ae57-118392b93f66','Different'),('d1c994fe-f3ec-40ed-aace-5221c026c0ea','5994c39d-c4ea-454c-ae57-118392b93f66','Keyboards'),('7757aa9b-abee-4d30-89d3-79f77613b5e8','Mice'),('33d93c3a-1c2d-44b9-8fac-3f83074104a5','Joysticks'),('f13bb023-47b2-473a-83b0-4223ff6e28b9','e79ecefa-c3e2-400f-aab4-2d28fcd3a832','Size 14'),('312a4e56-71ef-4372-a556-17ace15197e6','Size 15'),('c525374c-6a06-46e4-98c8-bc669e811e22','Size 16');

enter image description here

我想得到 a) 所有父母和他们的兄弟姐妹 b) 节点的所有兄弟姐妹。例如,如果我选择了 Joysticks 节点,那么我想获得

  • 计算机
    • 不同
    • 监视器
    • 母板
    • 系统块
  • 饮料
  • 食物

如您所见,未选择属于监视器的大小 14、15、16 节点。

到目前为止,我有以下查询

WITH RECURSIVE theparents (uuid,name,level) AS (
        SELECT uuid,0 AS level,FROM node 
        WHERE uuid = '33d93c3a-1c2d-44b9-8fac-3f83074104a5'

        UNION ALL

        SELECT a.uuid,a.parent_uuid,a.name,b.level + 1 as level
        FROM node a
        INNER JOIN theparents b ON b.parent_uuid = a.uuid
    ),thesiblings AS (
    SELECT a.uuid,b.level as level
    FROM node a
    INNER JOIN theparents b ON b.parent_uuid = a.parent_uuid OR (b.parent_uuid IS NULL AND a.parent_uuid IS NULL)
)
SELECT * FROM thesiblings;

查询选择所有节点,但不进行排序。是否可以使用 sql 对它们进行排序,或者只能手动完成?

解决方法

您只需将 tree 加入 node。唯一的问题是保持它根据树遍历顺序排序。试试这个,在 MySql 8.0 中测试

编辑

现在按基于名称的路径排序,20 是表中的最大名称长度

WITH RECURSIVE tree (uuid,parent_uuid,name,level,path) AS 
(
    SELECT uuid,0 level,cast(Rpad(name,20,' ') as char(200)) path
    FROM nodes 
    WHERE uuid = '33d93c3a-1c2d-44b9-8fac-3f83074104a5'

    UNION ALL

    SELECT a.uuid,a.parent_uuid,a.name,level-1,concat(Rpad(a.name,' '),'>',path)
    FROM nodes a
    INNER JOIN tree b ON b.parent_uuid = a.uuid
)
select uuid,level /*,path */
from (
   select n.uuid,n.name,max(-level) over() + level + 1  level,concat(substring(first_value(path) over(order by level),1,(20+1) * (max(-level) over() + level +1 )),n.name) path
   from tree t
   join nodes n on n.parent_uuid = t.uuid 
       -- no children for starting node
       and t.level <> 0
   
   union all
   --  roots
   select uuid,Rpad(name,' ')
   from nodes
   where parent_uuid is null 
) t
order by path

db<>fiddle