【问题标题】:Mysql recursion?mysql递归?
【发布时间】:2018-01-24 11:17:37
【问题描述】:

考虑这样的表格:

   folders_table
   -----------------------
      INT id_folder
      INT id_folder_parent
      VARCHAR folder_name

其中存储了一个简单的目录结构。如何使用单个 SELECT 查询获取目录的所有子目录?

【问题讨论】:

  • 很想知道为什么要在数据库级别而不是在应用程序层执行此操作?
  • 因为一个查询比在应用程序级别构建树所需的许多查询要快得多。
  • 您要从查询中寻找的确切结果是什么?你想要一个给定目录的子目录吗?您想要每个目录及其所有子目录配对的列表吗?你想用查询构造树结构吗?还有什么?
  • @outis 我只想获取单个目录的所有子目录。但是我现在已经用递归在应用程序逻辑中完成了它(我只是在 PHP 的递归函数中查询数据库服务器)。这有点慢,但现在必须工作。
  • 我明白了,现在。换句话说,您需要所有后代目录。 “子目录”是模棱两可的,因为它可能意味着所有子目录或所有后代目录。

标签: sql mysql


【解决方案1】:

可以,但是你需要改变你的数据库结构;进行更改后,您可以在一个查询中检索任意深度的树。查询稍微复杂一些,但仍然非常简单。

【讨论】:

  • 站点链接已损坏。你知道在哪里可以找到另一个副本吗?
  • 对不起,我指的是 MySQL 文章。你知道在哪里可以找到它的副本吗?
  • 不,我不抱歉,但信息几乎完全相同。在我阅读它们时,我发现 Sitepoint 文章在两者中更清晰,所以即使 MySQL 可用,我也建议使用 Sitepoint 一篇。
  • @Cam:MySQL的文章现在在作者的个人网站上,我添加了链接。
  • 所描述的概念的名称是“邻接列表模型”和“嵌套集模型”(带有“改进的前序树遍历算法”)。您可以在网上找到很多关于此主题的的信息。
【解决方案2】:

使用您显示的表结构,这不能用 MySQL 完成,因为它不支持递归查询

【讨论】:

  • 见下方评论;使用这种数据结构是不可能的,但可以通过避免递归和稍微改变数据结构来实现。
  • 这就是我所说的 ;) MySQL 无法进行递归查询(与其他 DBMS 不同)
  • 但是这个可以用mysql来完成; OP 从未说过必须使用递归查询来完成。我指出的方法在一个查询中完成。
  • 我假设 OP 希望保留已定义的表结构。我编辑了我的答案以包含这个假设
【解决方案3】:

使用 MySql/MariaDB,您可以使用 Open Query Graph 引擎 (http://openquery.com/graph/doc),它是一个 mysql 插件,可让您创建一个特殊的表来放置关系,基本上是 parentId 和 childId。

神奇的是,您使用特殊的列锁存器查询此表,具体取决于查询中传递的值,它将告诉 OQGRAPH 引擎执行哪个命令。有关详细信息,请参阅文档。

它不仅处理树(递归 1-n 关系),还处理带有权重的图形数据结构(递归 n-m 关系)(例如,您想存储公司所有权,一个公司可以有多个子公司,也可以有多个股东)。

【讨论】:

    【解决方案4】:

    另一个选项是存储节点的深度并为每个节点的完整路径保留一个标识符,并将这两者用作标准。

    我在关系数据库中存储 XML 节点的方式如下:

    SELECT id,value FROM element e1
    INNER JOIN element e2 ON (e2.id=e1.parent_id AND name='friend')
    WHERE e1.depth>4 AND e1.path like 'root[1]/users[1]/user:dana[1]/public[1]%'
    

    在这个例子中,我有一个节点名称字段和一个方括号中的插入器,用于在树中的每个级别具有相同节点名称的重复节点。

    当您插入每个节点时,您必须通过将父节点向下跟踪到根节点 (parent_id IS NULL) 来计算完整路径,并将每个级别附加到一个数组中,同时存储路径的深度。

    在存储在数据库中的任何类型的层次结构中,具有可视化表示和轻松访问任何路径总是好的,因为在每个请求上跟随树可能会很昂贵,特别是对于没有任何直接的 mysql递归 SQL 语法。

    在我看来,在层次结构(嵌套集邻接列表)中存储节点的左/右方案太危险了,这种方案可能会出错,因为管理起来非常复杂。

    【讨论】:

      【解决方案5】:

      1、新建表。 tree_folder(id, id_folder, tree_id) 2、新建表。 tree(id, tree_json)

      tree 表维护一个完整的树节点。例如,下面这个树的根节点为1

      {
          "folder_id": 1,
          "parent_folder_id": 0,
          "children": [
            {
                "folder_id": 10,
                "parent_folder_id": 1,
                "children": null
            },
            {
                "folder_id": 11,
                "parent_folder_id": 2,
                "children": null
            }
          ]
      }
      

      表格包含这一行。

      [id, tree_json]
      [1, "xxxxx"]
      

      然后维护节点和树之间的关系。如您所见,树包含节点11011。然后我们有表格tree_folder

      [id, folder_id, tree_id]
      [1,  1        ,  1]
      [2,  10       , 1]
      [3,  11       , 1]
      

      当您需要获取文件夹10 的树时。只需从树中获取,然后在您的程序中处理它。

      这样,你只需在内存中进行递归,而不是在mysql中。

      就是写数据的时候要维护结构,但是查询方便快捷。如果查询很频繁,这可以正常工作。但是如果写频繁的话,就用缓存代替这个方法吧。

      【讨论】:

        猜你喜欢
        • 2011-03-13
        • 2013-01-17
        • 2010-09-21
        • 1970-01-01
        • 2012-08-02
        • 2023-03-12
        • 2014-01-29
        • 2011-04-11
        相关资源
        最近更新 更多