我建议你读一读
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');