php/Mysql 最佳树形结构

发布于 2024-11-05 09:41:20 字数 180 浏览 4 评论 0原文

我必须构建一棵树,其中包含大约 300 个节点。该树没有深度限制。所以它可以有 3 或 15 个级别。每个节点可以有无限数量的子节点。

优先级是尽可能快地获得完整的树/子树,但有时我也需要添加节点或移动节点,但不是那么频繁。

我想知道在数据库中存储树的最佳方法以及在 php 中检索数据的最佳方法(如果可能的话)。

I have to build a tree that will contain about 300 nodes inside it. The tree has no depth limitations. So it can have 3 or 15 levels. Each node can have an unlimited number of children.

The priority is to get a complete tree / subtree the faster as possible, but I also need to add nodes or move nodes sometimes but not that often.

I want to know the best way to store the tree in the database and the best way to retrieve the data, if possible, in php.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

秋意浓 2024-11-12 09:41:20

您可以使用嵌套集模型,因为它可以产生非常有效的查询。查看管理 MySQL 中的分层数据并阅读名为 嵌套集模型

如果您使用像 Doctrine 这样的 ORM,它 包括嵌套集功能

对于某些人来说,理解“左”和“右”的嵌套集合概念可能很困难。我发现使用这些数字来类比打开/关闭标记的行号在 XML 文档中,人们发现它更容易掌握。

例如,采用上面 MySQL 链接中的数据示例:

+-------------+----------------------+-----+-----+
| category_id | name                 | lft | rgt |
+-------------+----------------------+-----+-----+
|           1 | ELECTRONICS          |   1 |  20 |
|           2 | TELEVISIONS          |   2 |   9 |
|           3 | TUBE                 |   3 |   4 |
|           4 | LCD                  |   5 |   6 |
|           5 | PLASMA               |   7 |   8 |
|           6 | PORTABLE ELECTRONICS |  10 |  19 |
|           7 | MP3 PLAYERS          |  11 |  14 |
|           8 | FLASH                |  12 |  13 |
|           9 | CD PLAYERS           |  15 |  16 |
|          10 | 2 WAY RADIOS         |  17 |  18 |
+-------------+----------------------+-----+-----+

如果您采用 lftrgt 字段并将它们用作 XML 文档的行号,您将得到

1. <electronics>
2.    <televisions>
3.        <tube>
4.        </tube>
5.        <lcd>
6.        </lcd>
7.        <plasma>  
8.        </plasma> 
9.     </televisions>
10.    <portable electronics>
11.        <mp3 players>
12.            <flash>
13.            </flash>
14.        </mp3 players>
15.        <cd players>
16.        </cd players>
17.        <2 way radios>
18.        </2 way radios>
19.    </portable electronics>
20. </electronics>

:这种方式可以使某些人更容易地可视化生成的嵌套集层次结构。它还使人们更清楚为什么这种方法可以提高效率,因为它可以选择整个节点而无需多个查询或连接。

You can use a Nested Set Model as it yields very efficient queries. Check out Managing Hierarchical Data in MySQL and read the section called Nested Set Model.

If you're using an ORM like Doctrine, it includes nested set capabilities.

It can be difficult for some to grasp the nested set concepts of left and right. I have found that using those numbers as an analogy for the line numbers of open/close tags in an XML document, folks find it easier to grasp.

For instance, take the data example from the MySQL link above:

+-------------+----------------------+-----+-----+
| category_id | name                 | lft | rgt |
+-------------+----------------------+-----+-----+
|           1 | ELECTRONICS          |   1 |  20 |
|           2 | TELEVISIONS          |   2 |   9 |
|           3 | TUBE                 |   3 |   4 |
|           4 | LCD                  |   5 |   6 |
|           5 | PLASMA               |   7 |   8 |
|           6 | PORTABLE ELECTRONICS |  10 |  19 |
|           7 | MP3 PLAYERS          |  11 |  14 |
|           8 | FLASH                |  12 |  13 |
|           9 | CD PLAYERS           |  15 |  16 |
|          10 | 2 WAY RADIOS         |  17 |  18 |
+-------------+----------------------+-----+-----+

If you take the lft, rgt fields and use them as line numbers for an XML document, you get:

1. <electronics>
2.    <televisions>
3.        <tube>
4.        </tube>
5.        <lcd>
6.        </lcd>
7.        <plasma>  
8.        </plasma> 
9.     </televisions>
10.    <portable electronics>
11.        <mp3 players>
12.            <flash>
13.            </flash>
14.        </mp3 players>
15.        <cd players>
16.        </cd players>
17.        <2 way radios>
18.        </2 way radios>
19.    </portable electronics>
20. </electronics>

Seeing it this way can make it much easier for some to visualize the resulting nested set hierarchy. It also makes it clearer why this approach improves efficiency as it makes it possible to select entire nodes without the need for multiple queries or joins.

德意的啸 2024-11-12 09:41:20

这是一篇很棒的文章:管理 MySQL 中的分层数据。我用了很长时间。

如果你有一定的数学能力,你就能真正理解为什么它如此伟大!

This is great article about it: Managing Hierarchical Data in MySQL. I used for a long time.

If you have some mathematical capabilities, you can really understand why it is so great!

可遇━不可求 2024-11-12 09:41:20
            <?php

            $host = "localhost";
            //Database user name.   
            $login = "root";
            //Database Password.
            $dbpass = "";
            $dbname = "abc";
            $PDO = new PDO("mysql:host=localhost;dbname=$dbname", "$login", "$dbpass");
            $rows = array();
            $sql = 'SELECT id, parent_id, name FROM employee';
            $query = $PDO->prepare($sql);
            $query->execute();
            $rows = array();

                if (!$query)
                {
                    $error = 'Error fetching page structure, for nav menu generation.';
                    exit();
                }

            while($row = $query->fetch(PDO::FETCH_ASSOC)){
                if( strcasecmp($row['parent_id'],'null') === 0 || empty($row['parent_id']) ) {
                     $row['parent_id'] = null;
                }

                $rows[] = $row;
            }


            // covert raw result set to tree
            $menu = convertAdjacencyListToTree(null,$rows,'id','parent_id','links');
            // echo '<pre>',print_r($menu),'</pre>';

            // display menu
            echo themeMenu($menu,1);

            /*
            * ------------------------------------------------------------------------------------
            * Utility functions
            * ------------------------------------------------------------------------------------
            */

            /*
            * Convert adjacency list to hierarchical tree
            *
            * @param value of root level parent most likely null or 0
            * @param array result
            * @param str name of primary key column
            * @param str name of parent_id column - most likely parent_id
            * @param str name of index that children will reside ie. children, etc
            * @return array tree
            */
            function convertAdjacencyListToTree($intParentId,&$arrRows,$strIdField,$strParentsIdField,$strNameResolution) {

                $arrChildren = array();

                for($i=0;$i<count($arrRows);$i++) {
                    if($intParentId === $arrRows[$i][$strParentsIdField]) {
                        $arrChildren = array_merge($arrChildren,array_splice($arrRows,$i--,1));
                    }
                }

                $intChildren = count($arrChildren);
                if($intChildren != 0) {
                    for($i=0;$i<$intChildren;$i++) {
                        $arrChildren[$i][$strNameResolution] = convertAdjacencyListToTree($arrChildren[$i][$strIdField],$arrRows,$strIdField,$strParentsIdField,$strNameResolution);
                    }
                }

                return $arrChildren;

            }

            /*
            * Theme menu
            *
            * @param array menu
            * @param runner (depth)
            * @return str themed menu
            */
            function themeMenu($menu,$runner) {

                $out = '';

                if(empty($menu)) {
                    return $out;
                }

                $out.='<ul>';
                foreach($menu as $link) {
                    $out.= sprintf(
                        '<li class="depth-%u">%s%s</li>'
                        ,$runner
                        ,$link['name']
                        ,themeMenu($link['links'],($runner+1))
                    );
                }

                $out.='</ul>';
                return $out;

            }

            ?>
            <?php

            $host = "localhost";
            //Database user name.   
            $login = "root";
            //Database Password.
            $dbpass = "";
            $dbname = "abc";
            $PDO = new PDO("mysql:host=localhost;dbname=$dbname", "$login", "$dbpass");
            $rows = array();
            $sql = 'SELECT id, parent_id, name FROM employee';
            $query = $PDO->prepare($sql);
            $query->execute();
            $rows = array();

                if (!$query)
                {
                    $error = 'Error fetching page structure, for nav menu generation.';
                    exit();
                }

            while($row = $query->fetch(PDO::FETCH_ASSOC)){
                if( strcasecmp($row['parent_id'],'null') === 0 || empty($row['parent_id']) ) {
                     $row['parent_id'] = null;
                }

                $rows[] = $row;
            }


            // covert raw result set to tree
            $menu = convertAdjacencyListToTree(null,$rows,'id','parent_id','links');
            // echo '<pre>',print_r($menu),'</pre>';

            // display menu
            echo themeMenu($menu,1);

            /*
            * ------------------------------------------------------------------------------------
            * Utility functions
            * ------------------------------------------------------------------------------------
            */

            /*
            * Convert adjacency list to hierarchical tree
            *
            * @param value of root level parent most likely null or 0
            * @param array result
            * @param str name of primary key column
            * @param str name of parent_id column - most likely parent_id
            * @param str name of index that children will reside ie. children, etc
            * @return array tree
            */
            function convertAdjacencyListToTree($intParentId,&$arrRows,$strIdField,$strParentsIdField,$strNameResolution) {

                $arrChildren = array();

                for($i=0;$i<count($arrRows);$i++) {
                    if($intParentId === $arrRows[$i][$strParentsIdField]) {
                        $arrChildren = array_merge($arrChildren,array_splice($arrRows,$i--,1));
                    }
                }

                $intChildren = count($arrChildren);
                if($intChildren != 0) {
                    for($i=0;$i<$intChildren;$i++) {
                        $arrChildren[$i][$strNameResolution] = convertAdjacencyListToTree($arrChildren[$i][$strIdField],$arrRows,$strIdField,$strParentsIdField,$strNameResolution);
                    }
                }

                return $arrChildren;

            }

            /*
            * Theme menu
            *
            * @param array menu
            * @param runner (depth)
            * @return str themed menu
            */
            function themeMenu($menu,$runner) {

                $out = '';

                if(empty($menu)) {
                    return $out;
                }

                $out.='<ul>';
                foreach($menu as $link) {
                    $out.= sprintf(
                        '<li class="depth-%u">%s%s</li>'
                        ,$runner
                        ,$link['name']
                        ,themeMenu($link['links'],($runner+1))
                    );
                }

                $out.='</ul>';
                return $out;

            }

            ?>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文