【问题标题】:How to pull grandchildren from database如何从数据库中提取孙子
【发布时间】:2010-12-23 23:58:45
【问题描述】:

我想从 MySQL 中提取菜单项。

Main menu           id=1, parentid=0
-Contact us         id=2, parentid=1
-Music              id=3, parentid=1
 --Rock             id=8, parentid=3
 --Classic          id=9, parentid=3
-Car                id=4, parentid=1
  --Toyota          id=5, parentid=4,
  --Ford            id=6, parentid=4,
  --Honda           id=7, parentid=4

Other menu          id=10, parentid=0
-Othermain          id=11, parentid=10
  --submenu         id=12, parentid=11

etc.

我可以从 id=1 提取数据到 4 并通过“...where parentid=1”等显示。 但是,这只会拉出顶层。

但我也想提取所有数据,包括每个菜单(主菜单)的子菜单。

谁能告诉我如何在 MySQL 中为此编写查询?

提前致谢。

【问题讨论】:

    标签: mysql menu navigation adjacency-list


    【解决方案1】:

    您需要实现递归以重复调用数据库以检索所有子项。你必须用你自己的替换我的数据库抽象层实现,但概念是一样的。

    内存缓存解决方案

    function generateTree($parentid = 0, &$tree) {
        $sql = sprintf('SELECT * FROM navigation WHERE parentid = %d', $parentid);
        $res = $this->db->results($sql);
        if ($res) {
            foreach ($res as $r) {
                // push found result onto existing tree
                $tree[$r->id] = $r;
                // create placeholder for children
                $tree[$r->id]['children'] = array();
                // find any children of currently found child
                $tree = generateTree($r->id, $tree[$r->id]['children']);
            }
        }
    }
    
    function getTree($parentid) {
        // memcache implementation
        $memcache = new Memcache();
        $memcache->connect('localhost', 11211) or die ("Could not connect"); 
        $tree = $memcache->get('navigation' . $parentid);
        if ($tree == null) {
            // need to query for tree
            $tree = array();
            generateTree($parentid, $tree);
    
            // store in memcache for an hour
            $memcache->set('navigation' . $parentid, $result, 0, 3600);
        }
        return $tree;
    }
    
    // get tree with parentid = 0
    getTree(0);
    

    非内存缓存解决方案

    function generateTree($parentid = 0, &$tree) {
        $sql = sprintf('SELECT * FROM navigation WHERE parentid = %d', $parentid);
        $res = $this->db->results($sql);
        if ($res) {
            foreach ($res as $r) {
                // push found result onto existing tree
                $tree[$r->id] = $r;
                // create placeholder for children
                $tree[$r->id]['children'] = array();
                // find any children of currently found child
                $tree = generateTree($r->id, $tree[$r->id]['children']);
            }
        }
    }
    
    // get tree with parentid = 0
    $tree = array();
    $parentid = 0;
    generateTree($parentid, $tree);
    
    // output the results of your tree
    var_dump($tree); die;
    

    以上内容未经测试,如果有人发现错误,请告诉我或随时更新。

    【讨论】:

    • 在这里您生成n 数量的SELECT 查询。这不是最佳解决方案。
    • @hsz - 我个人喜欢实现一个缓存解决方案,以避免执行这种数据库密集型功能。由于导航往往是相当静态的,因此很容易实现永久缓存,只有在对导航进行管理更新时才会删除/失效。
    • @cballou - 好的,我同意你的看法 - 但我们必须实现这个缓存。但是访问 n 个缓存文件而不是一个呢? ;)
    • @hsz - 您将缓存返回的数组,而不是每个单独的级别。
    • @shin - 我为您添加了它,但我建议您在 memcache 上进行搜索,因为它会极大地加快您的导航生成速度。
    【解决方案2】:

    最快的方法是从表格中获取所有元素并在代码端构建菜单树。

    【讨论】:

    • 谁能告诉我为什么这是错误的?它只使用一个查询,是导航菜单的最佳解决方案。
    • +1 我完全同意,构建菜单树只需一个查询
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多