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

rjzwgtxy  于 7个月前  发布在  Mysql
关注(0)|答案(2)|浏览(58)

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

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;

会是什么?

sz81bmfz

sz81bmfz1#

下面是另一种方法,使用路径对数据进行排序:

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

Demo here

d5vmydt9

d5vmydt92#

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 |

相关问题