详细聊一聊mysql的树形结构存储以及查询
目录
序存储parent存储pathMPTT(Modified Preorder Tree Traversal)小结doc序
本文主要研究一下mysql的树形结构存储及查询
存储parent
建表及数据准备这种方式就是每个节点存储自己的parent_id信息
CREATE TABLE `menu` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `parent_id` int(11) NOT NULL DEFAULT "0", PRIMARY KEY (`id`) ) ENGINE=InnoDB; INSERT INTO `menu` (`id`, `name`, `parent_id`) VALUES (1, "level1a", 0), (2, "level1b", 0), (3, "level2a-1a",1), (4, "level2b-1a",1), (5, "level2a-1b", 2), (6, "level2b-1b", 2), (7, "level3-2a1a", 3), (8, "level3-2b1a", 4), (9, "level3-2a1b", 5), (10, "level3-2b1b", 6);查询
-- 查询跟节点下的所有节点 SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3 FROM menu AS t1 LEFT JOIN menu AS t2 ON t2.parent_id = t1.id LEFT JOIN menu AS t3 ON t3.parent_id = t2.id WHERE t1.name = "level1a"; +---------+------------+-------------+ | lev1 | lev2 | lev3 | +---------+------------+-------------+ | level1a | level2a-1a | level3-2a1a | | level1a | level2b-1a | level3-2b1a | +---------+------------+-------------+ -- 查询叶子节点 SELECT t1.name FROM menu AS t1 LEFT JOIN menu as t2 ON t1.id = t2.parent_id WHERE t2.id IS NULL; +-------------+ | name | +-------------+ | level3-2a1a | | level3-2b1a | | level3-2a1b | | level3-2b1b | +-------------+
存储及修改上比较方便,就是要在sql里头查询树比较费劲,一般是加载到内存由应用自己构造
存储path
建表及数据准备这种方式在存储parent的基础上,额外存储path,即从根节点到该节点的路径
CREATE TABLE `menu_path` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `parent_id` int(11) NOT NULL DEFAULT "0", `path` varchar(255) NOT NULL DEFAULT "", PRIMARY KEY (`id`) ) ENGINE=InnoDB; INSERT INTO `menu_path` (`id`, `name`, `parent_id`, `path`) VALUES (1, "level1a", 0, "1/"), (2, "level1b", 0, "2/"), (3, "level2a-1a",1, "1/3"), (4, "level2b-1a",1, "1/4"), (5, "level2a-1b", 2, "2/5"), (6, "level2b-1b", 2, "2/6"), (7, "level3-2a1a", 3, "1/3/7"), (8, "level3-2b1a", 4, "1/4/8"), (9, "level3-2a1b", 5, "2/5/9"), (10, "level3-2b1b", 6, "2/6/10");查询
-- 查询某个节点的所有子节点 select * from menu_path where path like "1/%" +----+-------------+-----------+-------+ | id | name | parent_id | path | +----+-------------+-----------+-------+ | 1 | level1a | 0 | 1/ | | 3 | level2a-1a | 1 | 1/3 | | 4 | level2b-1a | 1 | 1/4 | | 7 | level3-2a1a | 3 | 1/3/7 | | 8 | level3-2b1a | 4 | 1/4/8 | +----+-------------+-----------+-------+
查找某个节点及其子节点比较方面,就是修改比较费劲,特别是节点移动,所有子节点的path都得跟着修改
MPTT(Modified Preorder Tree Traversal)
建表及数据准备不存储parent_id,改为存储lft,rgt,它们的值由树的先序遍历顺序决定
CREATE TABLE `menu_preorder` ( `id` int(11) NOT NULL, `name` varchar(50) NOT NULL, `lft` int(11) NOT NULL DEFAULT "0", `rgt` int(11) NOT NULL DEFAULT "0", PRIMARY KEY (`id`) ) ENGINE=InnoDB; 1(level1a)14 2(level2a)7 8(level2b)13 3(level3a-2a)4 5(level3b-2a)6 9(level3c-2b)10 11(level3d-2b)12 INSERT INTO `menu_preorder` (`id`, `name`, `lft`, `rgt`) VALUES (1, "level1a", 1, 14), (2, "level2a",2, 7), (3, "level2b",8, 13), (4, "level3a-2a", 3, 4), (5, "level3b-2a", 5, 6), (6, "level3c-2b", 9, 10), (7, "level3d-2b", 11, 12); select * from menu_preorder +----+------------+-----+-----+ | id | name | lft | rgt | +----+------------+-----+-----+ | 1 | level1a | 1 | 14 | | 2 | level2a | 2 | 7 | | 3 | level2b | 8 | 13 | | 4 | level3a-2a | 3 | 4 | | 5 | level3b-2a | 5 | 6 | | 6 | level3c-2b | 9 | 10 | | 7 | level3d-2b | 11 | 12 | +----+------------+-----+-----+查询
-- 查询某个节点及其子节点,比如level2b select * from menu_preorder where lft between 8 and 13 +----+------------+-----+-----+ | id | name | lft | rgt | +----+------------+-----+-----+ | 3 | level2b | 8 | 13 | | 6 | level3c-2b | 9 | 10 | | 7 | level3d-2b | 11 | 12 | +----+------------+-----+-----+ -- 查询所有叶子节点 SELECT name FROM menu_preorder WHERE rgt = lft + 1; +------------+ | name | +------------+ | level3a-2a | | level3b-2a | | level3c-2b | | level3d-2b | +------------+ -- 查询某个节点及其父节点 SELECT parent.* FROM menu_preorder AS node, menu_preorder AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt AND node.name = "level2b" ORDER BY parent.lft; +----+---------+-----+-----+ | id | name | lft | rgt | +----+---------+-----+-----+ | 1 | level1a | 1 | 14 | | 3 | level2b | 8 | 13 | +----+---------+-----+-----+ -- 树形结构展示 SELECT CONCAT( REPEAT(" ", COUNT(parent.name) - 1), node.name) AS name FROM menu_preorder AS node, menu_preorder AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft; +--------------+ | name | +--------------+ | level1a | | level2a | | level3a-2a | | level3b-2a | | level2b | | level3c-2b | | level3d-2b | +--------------+
好处是通过lft进行范围(该节点的lft,rgt作为范围)查找就可以,缺点就是增删节点导致很多节点的lft及rgt都要修改
小结
存储parent的方式最为场景,一般树形结构数据量不大的话,直接在应用层内存构造树形结构和搜索存储path的好处是可以借助path来查找节点及其子节点,缺点就是移动node需要级联所有子节点的path,比较费劲MPTT的方式好处是通过lft进行范围(该节点的lft,rgt作为范围)查找就可以,缺点就是增删节点导致很多节点的lft及rgt都要修改doc
Managing Hierarchical Data in MySQLhierarchical-data-databasehierarchical-data-database-2hierarchical-data-database-3到此这篇关于mysql树形结构存储以及查询的文章就介绍到这了,更多相关mysql树形结构存储及查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
X 关闭
X 关闭
- 15G资费不大降!三大运营商谁提供的5G网速最快?中国信通院给出答案
- 2联想拯救者Y70发布最新预告:售价2970元起 迄今最便宜的骁龙8+旗舰
- 3亚马逊开始大规模推广掌纹支付技术 顾客可使用“挥手付”结账
- 4现代和起亚上半年出口20万辆新能源汽车同比增长30.6%
- 5如何让居民5分钟使用到各种设施?沙特“线性城市”来了
- 6AMD实现连续8个季度的增长 季度营收首次突破60亿美元利润更是翻倍
- 7转转集团发布2022年二季度手机行情报告:二手市场“飘香”
- 8充电宝100Wh等于多少毫安?铁路旅客禁止、限制携带和托运物品目录
- 9好消息!京东与腾讯续签三年战略合作协议 加强技术创新与供应链服务
- 10名创优品拟通过香港IPO全球发售4100万股 全球发售所得款项有什么用处?