从Laravel上的数据库中检索所有父/子记录(分层数据)

Cha*_*les 7 php mysql hierarchy hierarchical-data laravel

对于类似遗留票证的系统,我有以下简化的数据库表结构.

messages
  id         INT
  parent_id  INT
  content    TEXT
  answer     TEXT
  ...
Run Code Online (Sandbox Code Playgroud)

在列表中,我显示所有消息.单击消息时,我会显示其答案等.

问题是:现在我需要所有的表结构的父母孩子的关系到这条消息,以及这个消息在树中的位置.我怎样才能从数据库中检索它们?

我正在使用Laravel,但原始SQL也可以帮助我找到方向.


例:

?????????????????????????????????????????????????????????????
? id ? parent_id ?        content         ?     answer      ?
?????????????????????????????????????????????????????????????
?  1 ? NULL      ? Hi, I have a problem   ? I can't help    ?
?  2 ? 1         ? The problem persists   ? Ok, what is it? ?
?  3 ? 2         ? Nevermind, I got this  ? Oh, well.       ?
?  4 ? 3         ? Problem is back        ? Which problem?  ?
?  5 ? 4         ? The same problem again ? ...             ?
?????????????????????????????????????????????????????????????

显示消息时id = 4,我应该能够显示如下列表:

消息历史:
- 嗨,我有一个问题
- 问题仍然存在
- 没关系,我得到了这个
- 问题又回来了
- 同样的问题再次出现

我只能想到一个循环和几个SQL查询执行,每个父和子,看起来像一个代码气味.


UPDATE

如Daan所述,这个问题似乎与如何创建MySQL分层递归查询重复.

我决定不删除它,因为Ravan刚刚用Laravel方法回答了它,这有助于我解决问题,所以我将把它留在这里以备将来参考.

Rav*_*afi 5

由于您正在执行分层操作,因此应使用一种策略来保存和从数据库中检索此数据。

一种方法是使用嵌套集模型,可以使其更容易。Laravel有一个很好的软件包,叫做etrepat / baum,它也解释了它是如何工作的,我引用:

TL; DR版本背后的理论

可视化嵌套集工作方式的一种简单方法是,考虑围绕其所有子级的父实体,以及围绕其子级的父实体,等等。因此,这棵树:

root
  |_ Child 1
    |_ Child 1.1
    |_ Child 1.2
  |_ Child 2
    |_ Child 2.1
    |_ Child 2.2
Run Code Online (Sandbox Code Playgroud)

可以像这样可视化:

 ___________________________________________________________________
|  Root                                                             |
|    ____________________________    ____________________________   |
|   |  Child 1                  |   |  Child 2                  |   |
|   |   __________   _________  |   |   __________   _________  |   |
|   |  |  C 1.1  |  |  C 1.2 |  |   |  |  C 2.1  |  |  C 2.2 |  |   |
1   2  3_________4  5________6  7   8  9_________10 11_______12 13  14
|   |___________________________|   |___________________________|   |
|___________________________________________________________________|
Run Code Online (Sandbox Code Playgroud)

数字代表左边界和右边界。该表可能如下所示:

id | parent_id | lft  | rgt  | depth | data
 1 |           |    1 |   14 |     0 | root
 2 |         1 |    2 |    7 |     1 | Child 1
 3 |         2 |    3 |    4 |     2 | Child 1.1
 4 |         2 |    5 |    6 |     2 | Child 1.2
 5 |         1 |    8 |   13 |     1 | Child 2
 6 |         5 |    9 |   10 |     2 | Child 2.1
 7 |         5 |   11 |   12 |     2 | Child 2.2
Run Code Online (Sandbox Code Playgroud)

要获取节点的所有子节点,您可以

SELECT * WHERE lft IS BETWEEN parent.lft AND parent.rgt
Run Code Online (Sandbox Code Playgroud)

为了得到孩子的数量,

(right - left - 1)/2
Run Code Online (Sandbox Code Playgroud)

为了使节点及其所有祖先回到根,您可以

SELECT * WHERE node.lft IS BETWEEN lft AND rgt
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,在普通树上那些递归且速度过慢的查询突然变得非常快。漂亮,不是吗?