递归排序 table

Order by on recursive table

我有一个 categories table,有一些递归。有些类别是子类别,因此在 parent_category_id 字段中有一个值。顶级类别在 parent_category_id 字段中为空。

要求列出的类别应显示为:

Parent category 1
  Sub category 1
  Sub category 2

Parent category 2
  Subcategory 3
  Subcategory 4

这是否可以通过单个查询顺序语句实现,或者我是否需要进行单独的查询?

请求的一些示例数据:

在 MYSQL 中,不支持递归 cte:

select id, path(id) from mytable order by 2,其中 path(id)

定义
DELIMITER $$
CREATE FUNCTION path(v_id INT(10)) RETURNS varchar(255)
begin
declare v_path varchar(255);
declare v_parent_id INT(10); 
declare MAX_ITERS int;
declare iters int;
set v_path = '';
set MAX_ITERS = 20;
set iters = 0;

if not exists (select * from node where id = v_id) then
    return 'no such node'; 
end if;

if not exists (select * from node where parent_id < 0) then
    return 'no root node in table';
end if;

select parent_id into v_parent_id from node where id = v_id;
while (v_parent_id >= 0) do
    set iters = iters + 1;
    if iters >= MAX_ITERS then
        return 'path too long'; 
    end if;
    select parent_id, concat(id, '.', v_path) into v_parent_id, v_path from node where id = v_id;
    set v_id = v_parent_id;
end while;
return trim(both '.' from v_path);

end$$


DELIMITER ;
;

请注意,在我的示例中,我使用的节点 ID 为 -1,而不是根的空父节点。

为了性能,维护第二个table(使用触发器),它存储每个节点的'path',其中路径(节点)由上面的UDF定义。

这是SQL服务器语法:

DECLARE @category TABLE(category_id INT,parent_category_id INT,caption varchar(100));
INSERT INTO @category VALUES
 (1,NULL,'Top1')
,(2,1,'Sub11')
,(3,1,'Sub12')
,(4,2,'Sub111')
,(5,2,'Sub112')
,(6,NULL,'Top2')
,(7,6,'Sub21')
,(8,6,'Sub22')
,(9,8,'Sub221');

WITH rCTE AS
(
    SELECT c.category_id
          ,c.parent_category_id
          ,c.caption
          ,CAST(ROW_NUMBER() OVER(ORDER BY c.category_id) AS VARCHAR(MAX)) +  '.' AS [Level] 
          ,REPLACE(STR(ROW_NUMBER() OVER(ORDER BY c.category_id),4),' ','0') +  '.' AS [Sortable] 
    FROM @category AS c WHERE parent_category_id IS NULL

    UNION ALL

    SELECT c.category_id
          ,c.parent_category_id
          ,c.caption
          ,rCTE.[Level] + CAST(ROW_NUMBER() OVER(ORDER BY c.category_id) AS VARCHAR(MAX)) +  '.'
          ,rCTE.Sortable + REPLACE(STR(ROW_NUMBER() OVER(ORDER BY c.category_id),4),' ','0') +  '.'
    FROM rCTE 
    INNER JOIN @category AS c ON c.parent_category_id=rCTE.category_id 
)

SELECT * 
FROM rCTE
ORDER BY Sortable

结果

+-------------+--------------------+---------+--------+-----------------+
| category_id | parent_category_id | caption | Level  | Sortable        |
+-------------+--------------------+---------+--------+-----------------+
| 1           | NULL               | Top1    | 1.     | 0001.           |
+-------------+--------------------+---------+--------+-----------------+
| 2           | 1                  | Sub11   | 1.1.   | 0001.0001.      |
+-------------+--------------------+---------+--------+-----------------+
| 4           | 2                  | Sub111  | 1.1.1. | 0001.0001.0001. |
+-------------+--------------------+---------+--------+-----------------+
| 5           | 2                  | Sub112  | 1.1.2. | 0001.0001.0002. |
+-------------+--------------------+---------+--------+-----------------+
| 3           | 1                  | Sub12   | 1.2.   | 0001.0002.      |
+-------------+--------------------+---------+--------+-----------------+
| 6           | NULL               | Top2    | 2.     | 0002.           |
+-------------+--------------------+---------+--------+-----------------+
| 7           | 6                  | Sub21   | 2.1.   | 0002.0001.      |
+-------------+--------------------+---------+--------+-----------------+
| 8           | 6                  | Sub22   | 2.2.   | 0002.0002.      |
+-------------+--------------------+---------+--------+-----------------+
| 9           | 8                  | Sub221  | 2.2.1. | 0002.0002.0001. |
+-------------+--------------------+---------+--------+-----------------+