【问题标题】:Retrieve all parent/child records from database on Laravel (hierarchical data)从 Laravel 的数据库中检索所有父/子记录(分层数据)
【发布时间】:2015-06-13 14:04:04
【问题描述】:

我有以下简化的数据库表结构,用于旧式票证系统。

messages
  id         INT
  parent_id  INT
  content    TEXT
  answer     TEXT
  ...

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

问题是,现在我需要制作一个所有与这条消息相关的parentschildren的列表结构,以及这条消息在树中的位置. 如何从数据库中检索这些?

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


例子: ╔════╦═══════════╦════════════════════════╦═══════ ══════════╗ ║ id ║ parent_id ║ 内容 ║ 回答 ║ ╠════╬═══════════╬════════════════════════╬═══════ ══════════╣ ║ 1 ║ NULL ║ 你好,我有问题║ 我无能为力 ║ ║ 2 ║ 1 ║ 问题依旧 ║ 好的,是什么? ║ ║ 3 ║ 2 ║ 没关系,我知道了 ║ 哦,好吧。 ║ ║ 4 ║ 3 ║ 问题又回来了 ║ 哪个问题? ║ ║ 5 ║ 4 ║ 同样的问题又来了║ ... ║ ╚════╩═══════════╩════════════════════════╩═══════ ══════════╝

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

消息历史记录:
- 嗨,我有一个问题
- 问题依然存在
- 没关系,我得到了这个
- 问题又回来了
- 又是同样的问题

我只能想到一个循环和几个 SQL 查询执行,对于每个父子和子,这看起来像是代码异味。


更新

正如 Daan 所说,这个问题似乎与 How to create a MySQL hierarchical recursive query 重复。

但我决定不删除它,因为 Ravan 只是用 Laravel 方法回答了它,帮助我解决了问题,所以我将把它留在这里以供将来参考。

【问题讨论】:

  • 很遗憾mysql没有支持分层查询的东西,你可能需要写一个递归函数来完成这项工作。
  • 确实是重复的。搜索此内容时,我无法想到“分层”一词。我该怎么办,删除这个问题?
  • 我认为这个问题是相关的,因为有特定于 Laravel 的解决方案。
  • 好的,我将编辑问题的标题以专注于 Laravel 解决方案,因为这是我的真实场景,并提及其他可能的重复项,以防它帮助其他人。感谢您的回答 Ravan,这正是我所需要的。

标签: php mysql laravel hierarchy hierarchical-data


【解决方案1】:

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

一种方法是使用Nested Set Model,这样会更容易。 Laravel 有一个很棒的包来处理它,叫做etrepat/baum,它也解释了它是如何工作的,我引用:

背后的理论,一个 TL;DR 版本

可视化嵌套集如何工作的一种简单方法是考虑一个父实体围绕所有 它的孩子,以及它周围的父母等等。所以这棵树:

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
|   |___________________________|   |___________________________|   |
|___________________________________________________________________|

数字代表左右边界。那么该表可能 看起来像这样:

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

要获取 父节点 节点的所有子节点,您需要

SELECT * WHERE lft IS BETWEEN parent.lft AND parent.rgt

要获得孩子的数量,是

(right - left - 1)/2

要让一个节点及其所有祖先回到根,你

SELECT * WHERE node.lft IS BETWEEN lft AND rgt

如您所见,递归查询和执行速度非常慢 普通的树木突然变得相当快。漂亮,不是吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 2020-08-08
    • 2014-04-14
    • 2016-10-21
    相关资源
    最近更新 更多