MySQL中的递归查询邻接表深度优先?

问题描述 投票:0回答:2

运行此查询的表的结构大致如下:

comments_table(PK id, FK reply_to_id, content) 

FK is a self join on itself

它在 10.4.27-MariaDB 上运行

数据看起来像这样:

+----+-------------+---------+
| id | reply_to_id | content |
+----+-------------+---------+
| 12 |     NULL    |   text  |
| 13 |      12     |   text  |
| 14 |      12     |   text  |
| 15 |      13     |   text  |
+----+-------------+---------+

查询应该按顺序检索输入父亲(或树根)中给出的所有回复注释。

结果顺序应该是深度优先。

预期结果示例:

Input : 12
Result: 13,15,14

    12
  /    \
13      14
  \
   15
+----+
| id |
|----+
| 13 |
| 15 |
| 14 |
+----+

等等

我想要存档的是在查询中完成此操作,而不使用任何外部代码。

我一直在尝试递归并修改如下所示的查询:

select id 
from (
    select * from comments order by id
) comments_sorted, (
    select @pv := '62'
) initialisation 
where find_in_set(replied_to_id, @pv)
and length(@pv := concat(@pv, ',', id));

查询确实有效并且它在输出中给出了对给定父亲(或树根)的所有回复

输出如下所示:

+----+
| id |
+----+
| 13 |
| 14 |
| 15 |
+----+

同时所需的输出如上所示

如何才能实现?

编辑

提供额外反馈

将您的查询@Luuk 与这组数据一起使用:

+----+---------------+
| id | replied_to_id |
+----+---------------+
| 81 |          NULL |
| 82 |          NULL |
| 83 |            82 |
| 84 |            83 |
| 85 |            83 |
| 86 |            83 |
| 87 |            84 |
| 88 |            87 |
| 93 |            88 |
+----+---------------+

我得到这个结果:

+---+----+---------------+
| x | id | replied_to_id |
+---+----+---------------+
| 1 | 83 |            82 |
| 1 | 84 |            83 |
| 1 | 85 |            83 |
| 1 | 86 |            83 |
| 1 | 87 |            84 |
| 1 | 88 |            87 |
| 1 | 93 |            88 |
+---+----+---------------+

我可以看到 x 值没有增加。

我使用的查询是:

WITH RECURSIVE cte AS ( 
   SELECT row_number() over (order by id) as x, id, replied_to_id 
   FROM comments 
   WHERE replied_to_id=82 
   UNION ALL 
   SELECT x, comments.id, comments.replied_to_id 
   FROM cte 
   INNER JOIN comments on comments.replied_to_id = cte.id 
) 
SELECT * FROM cte ORDER BY x,id;

可能是什么?

sql mariadb recursive-query mariadb-10.4
2个回答
3
投票
WITH RECURSIVE cte AS (
  SELECT 
     row_number() over (order by id) as x,
     id,
     reply_to_id 
  FROM test 
  WHERE reply_to_id=12
  
  UNION ALL
  
  SELECT x, test.id, test.reply_to_id
  FROM cte 
  INNER JOIN test on test.reply_to_id = cte.id
  )

SELECT * 
  FROM cte
  ORDER BY x,id;

参见:DBFIDDLE

row_number()
对第一级的回复进行排序,并且此排序将复制到下一级。

输出:

x id 回复id
1 13 12
1 15 13
2 14 12

2
投票

这是另一种方法,使用路径来排序数据:

WITH recursive cte (id, reply_to_id, path)
AS
(
    SELECT id, reply_to_id, CAST(id AS CHAR(200)) AS path
    FROM comments_table
    WHERE reply_to_id = 12
  UNION ALL
    SELECT e.id, e.reply_to_id, CONCAT(cte.path, ",", e.id)
    FROM comments_table AS e
    JOIN cte ON e.reply_to_id = cte.id
)
SELECT *
from cte
order by path

演示在这里

© www.soinside.com 2019 - 2024. All rights reserved.