【问题标题】:Create a multiselect drop down with parent-child menu items使用父子菜单项创建多选下拉菜单
【发布时间】:2012-03-11 17:21:21
【问题描述】:

我打算在 php 中创建一个多选下拉菜单或多选复选框表单元素。但是具有父子菜单项关系。

例如:所以我有三个单独的表 tbl_branch、tbl_area、tbl_region 和另外 2 个用于映射 tbl_regiontoarea 和 tbl_areatobranch 的表。现在我需要一个看起来像这样的多选或多选复选框:

Branch 1
 Area 1
   Region 1
   Region 2
 Area 2
   Region 3
   Region 4
   Region 7
   Region 9
 Area 5
 Area 7
   Region 8

Branch 2 
 Area 3

Branch 3
Branch 4
Branch 5
 Area 6
   Region 10
 Area 2

如您所料,Branch 是层次结构中的最高层,region 是最低层,即 Branch 是父级.我希望它循环直到找到它的孩子。一旦它停止查找任何子项,它就会移动到数组中的下一个父项。

我对数组和形成复杂的 sql 查询非常不擅长,因此期待有一些关于如何做到这一点的起始方向。如果有人可以帮助我,我将不胜感激。

提前致谢

【问题讨论】:

    标签: php mysql html arrays


    【解决方案1】:

    我建议你读一读

    http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

    我已经建立了一个几乎相同的数据树,并使用上述文档中建议的方法使问题变得更加简单,尤其是在确定低至 n 级的父母和兄弟姐妹时。

    简短的版本是您在每个节点的“左”和“右”分配一个数字,然后使用它可以非常有效地选择树的段。更冗长的版本在那篇文章中,并且比我更彻底地解释它,并包含有用的 MySQL 代码。

    这是您的主表的潜在大纲

    treeTable (
        // ID field
        id INT UNSIGNED PK AI,
        // Fields for branching
        lft INT UNSIGNED,
        rgt INT UNSIGNED,
        // ID fields for the specific types
        leafType ENUM('Branch','Area','Region'),
        leafID INT UNSIGNED,
        leafName VARCHAR
    )
    
    UNIQUE INDEX (leafType,leafID)
    

    如果您需要每种类型的特定数据,那么您可以为它们创建单独的表,但上述方法可以让您创建树、映射 id 并允许将关系与显示名称一起存储。

    当然,您可以在每个leafType 之间标准化的数据越多越好,理想情况下,它们毕竟都是同一类型的数据,因为它们都是地理子部分

    以您的数据样本为例

    Branch 3
    Branch 4
    Branch 5
     Area 6
       Region 10
     Area 2
    

    你可能会得到这样的表格

    id  lft rgt leafType    leafID  
    1   1   2   'Branch'    3   
    2   3   4   'Branch'    4
    3   5   12  'Branch'    5
    4   6   9   'Area'      6
    5   7   8   'Region'    10
    6   10  11  'Area'      2
    

    关于如何插入等的查询可以在链接的文章中找到,即(逐字引用自http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

    LOCK TABLE nested_category WRITE;
    
    SELECT @myLeft := lft FROM nested_category
    
    WHERE name = '2 WAY RADIOS';
    
    UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myLeft;
    UPDATE nested_category SET lft = lft + 2 WHERE lft > @myLeft;
    
    INSERT INTO nested_category(name, lft, rgt) VALUES('FRS', @myLeft + 1, @myLeft + 2);
    
    UNLOCK TABLES;
    

    然后 SELECT 可以说明树(再次逐字逐句)

    SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
    FROM nested_category AS node,
            nested_category AS parent
    WHERE node.lft BETWEEN parent.lft AND parent.rgt
    GROUP BY node.name
    ORDER BY node.lft;
    

    上述2中的字段/表名当然没有变化,但您可以根据需要更新表/字段名

    根据我的最新评论,下面是我用于插入新行的存储过程的定义

    CREATE PROCEDURE `addOptionalExtraToTree`(inParentOptionID INT,inOptionName VARCHAR(40),inLeafType VARCHAR(20))
    BEGIN
        DECLARE myRight INT UNSIGNED DEFAULT 0;
    
        SELECT optionalExtra_tree_right-1
        INTO myRight
        FROM optionalExtras
        WHERE optionalExtraID = inParentOptionID;
    
        IF myRight = 0 THEN
            SELECT COALESCE(MAX(optionalExtra_tree_right),0)
            INTO myRight
            FROM optionalExtras;
        END IF;
    
        UPDATE optionalExtras 
        SET optionalExtra_tree_right = optionalExtra_tree_right + 2 
        WHERE optionalExtra_tree_right > myRight;
    
        UPDATE optionalExtras 
        SET optionalExtra_tree_left = optionalExtra_tree_left + 2 
        WHERE optionalExtra_tree_left > myRight;
    
        INSERT INTO optionalExtras (
            optionalExtra_name,
            optionalExtra_leaf_type,
            optionalExtra_tree_left,
            optionalExtra_tree_right
        ) VALUES (
            inOptionName,
            inLeafType,
            myRight + 1,
            myRight + 2
        );
    
        SELECT LAST_INSERT_ID() AS optionalExtraID;
    
    END;
    

    然后使用如下调用调用它

    CALL addOptionalExtraToTree(0,'New root option','Region');
    CALL addOptionalExtraToTree(4,'New child option','Area');
    

    【讨论】:

    • 根据我的理解,我刚刚阅读了 n,我发现了两个问题:首先,我的数据分布在多个表上,而不是像 category 表中那样只有一个表。其次,我有多个父项,例如Electronics,所以无论他们是否有孩子,它都会循环遍历所有项。
    • 首先你可以有多个父节点。如果您有一个左右 1:4 的节点和一个左右 5:6 的第二个节点,那么即使第二个没有子节点,SELECT 也会返回它们。作为第二点,您将所有数据视为一棵树,这将表明数据属于相似类型,因此为了能够有效地做到这一点,可能需要重组以规范关键区域,将添加一个建议表上面的布局。
    • 所以基本上你要求我创建另一个表,其中包含我的分支/区域/区域的超级映射。而且我仍然不清楚如何在此表中插入值。如果您不介意,您能否通过实际从问题中的数据中挑选来解释一下您的表格在我的数据中的样子?
    • 感谢详细的示例。但是我怎么每次都知道我的左右价值观是什么。由于我正在为应用程序构建此功能,我将如何继续为lftrgt 插入正确的值?你知道我的意思吗?
    • 您可以添加用于插入存储过程的逻辑。我已经在我自己的表中做到了这一点,其中存储过程作为输入(parentID,leafType,leafName)(我没有单独的leafID)。如果我将 parentID 指定为 0,它会将其添加为树末尾的新根节点。
    猜你喜欢
    • 2021-11-19
    • 2018-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-20
    • 1970-01-01
    相关资源
    最近更新 更多