从 Laravel 上的数据库中检索所有 parent/child 记录(分层数据)
Retrieve all parent/child records from database on Laravel (hierarchical data)
我有以下简化的数据库 table 结构,用于类似遗留票证的系统。
messages
id INT
parent_id INT
content TEXT
answer TEXT
...
在列表中,我显示了所有消息。单击一条消息时,我会显示其答案等。
问题是,现在我需要制作一个列表结构,包含与此消息相关的所有 parents 和 children,以及此消息在树中的位置。 如何从数据库中检索这些信息?
我正在使用 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 查询执行,对于每个父子,这看起来像代码味道。
更新
正如 Daan 所说,这个问题似乎与 How to create a MySQL hierarchical recursive query 重复。
但是我决定不删除它,因为 Ravan 刚刚用 Laravel 方法回答了它,帮助我解决了问题,所以我将把它留在这里以供将来参考。
由于您正在进行分层操作,因此您应该使用一种策略来保存和从数据库中检索这些数据。
一种方法是使用 Nested Set Model,这样会更容易。
Laravel 有一个很好的包来处理它,叫做 etrepat/baum,它也解释了它是如何工作的,我引用:
背后的理论,一个 TL;DR 版本
可视化嵌套集如何工作的一种简单方法是想象一个 parent 实体包围所有
它的 children,以及它周围的 parent,等等。所以这棵树:
root
|_ Child 1
|_ Child 1.1
|_ Child 1.2
|_ Child 2
|_ Child 2.1
|_ Child 2.2
可以这样形象化:
___________________________________________________________________
| 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
| |___________________________| |___________________________| |
|___________________________________________________________________|
数字代表左右边界。 table 然后可能
看起来像这样:
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
要获取 parent 节点的所有 children,你
SELECT * WHERE lft IS BETWEEN parent.lft AND parent.rgt
要得到children的个数,是
(right - left - 1)/2
要让一个节点及其所有祖先回到根,您
SELECT * WHERE node.lft IS BETWEEN lft AND rgt
如您所见,递归的查询速度非常慢
普通的树木突然变得相当快。很漂亮,不是吗?
我有以下简化的数据库 table 结构,用于类似遗留票证的系统。
messages
id INT
parent_id INT
content TEXT
answer TEXT
...
在列表中,我显示了所有消息。单击一条消息时,我会显示其答案等。
问题是,现在我需要制作一个列表结构,包含与此消息相关的所有 parents 和 children,以及此消息在树中的位置。 如何从数据库中检索这些信息?
我正在使用 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 查询执行,对于每个父子,这看起来像代码味道。
更新
正如 Daan 所说,这个问题似乎与 How to create a MySQL hierarchical recursive query 重复。
但是我决定不删除它,因为 Ravan 刚刚用 Laravel 方法回答了它,帮助我解决了问题,所以我将把它留在这里以供将来参考。
由于您正在进行分层操作,因此您应该使用一种策略来保存和从数据库中检索这些数据。
一种方法是使用 Nested Set Model,这样会更容易。 Laravel 有一个很好的包来处理它,叫做 etrepat/baum,它也解释了它是如何工作的,我引用:
背后的理论,一个 TL;DR 版本
可视化嵌套集如何工作的一种简单方法是想象一个 parent 实体包围所有 它的 children,以及它周围的 parent,等等。所以这棵树:
root
|_ Child 1
|_ Child 1.1
|_ Child 1.2
|_ Child 2
|_ Child 2.1
|_ Child 2.2
可以这样形象化:
___________________________________________________________________
| 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
| |___________________________| |___________________________| |
|___________________________________________________________________|
数字代表左右边界。 table 然后可能 看起来像这样:
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
要获取 parent 节点的所有 children,你
SELECT * WHERE lft IS BETWEEN parent.lft AND parent.rgt
要得到children的个数,是
(right - left - 1)/2
要让一个节点及其所有祖先回到根,您
SELECT * WHERE node.lft IS BETWEEN lft AND rgt
如您所见,递归的查询速度非常慢 普通的树木突然变得相当快。很漂亮,不是吗?