请问mysql如何设计多级分销上下级查询的数据结构?
网友回复
你说的分销上下级查询其实就是类似于一个栏目类目树结构。
我们以一个栏目树形结构来为例分析一下如果对无限栏目进行添加查询修改删除。
电灯, 相机 电话、电视机都属于电器这个类别。为了模拟这一类的树,我们可以创建一个命名的表category有三列:id,title,和parent_id如下:CREATE TABLE category ( id int(10) unsigned NOT NULL AUTO_INCREMENT, title varchar(255) NOT NULL, parent_id int(10) unsigned DEFAULT NULL, PRIMARY KEY (id), FOREIGN KEY (parent_id) REFERENCES category (id) ON DELETE CASCADE ON UPDATE CASCADE );表中的每一行都是由id列标识的树中的一个节点。该parent_id列是category表本身的外键。它就像一个指向id列的指针 。
插入数据
树的根节点没有父节点,因此parent_id设置为NULL。其他节点必须设置一个父节点。 要插入根节点,请按如下方式设置parent_idto NULL:INSERT INTO category(title,parent_id) VALUES('电器',NULL);要插入非根节点,只需将其设置 parent_id为其父节点的 id。例如,所述parent_id的电灯、电脑、手机、电视的节点被设置为1:
INSERT INTO category(title,parent_id) VALUES('电灯',1); INSERT INTO category(title,parent_id) VALUES('电脑',2); INSERT INTO category(title,parent_id) VALUES('手机',2); INSERT INTO category(title,parent_id) VALUES('电视',1); INSERT INTO category(title,parent_id) VALUES('智能手机',4); INSERT INTO category(title,parent_id) VALUES('andriod手机',4); INSERT INTO category(title,parent_id) VALUES('苹果手机',4); INSERT INTO category(title,parent_id) VALUES('鸿蒙手机',4);
寻找根节点
根节点是没有父节点的节点。换句话说,它parent_id是NULL:SELECT id, title FROM category WHERE parent_id IS NULL;
查找节点的直接子节点
以下查询获取根节点的直接子节点:SELECT id, title FROM category WHERE parent_id = 1;
查找叶节点
叶节点是没有子节点的节点。SELECT c1.id, c1.title FROM category c1 LEFT JOIN category c2 ON c2.parent_id = c1.id WHERE c2.id IS NULL;
查询整棵树
以下递归公用表表达式 (CTE)检索整个类别树。请注意,CTE功能从 MySQL 8.0 开始可用WITH RECURSIVE category_path (id, title, path) AS ( SELECT id, title, title as path FROM category WHERE parent_id IS NULL UNION ALL SELECT c.id, c.title, CONCAT(cp.path, ' > ', c.title) FROM category_path AS cp JOIN category AS c ON cp.id = c.parent_id ) SELECT * FROM category_path ORDER BY path;
查询子树
以下查询获取id为 4的子树。WITH RECURSIVE category_path (id, title, path) AS ( SELECT id, title, title as path FROM category WHERE parent_id = 4 UNION ALL SELECT c.id, c.title, CONCAT(cp.path, ' > ', c.title) FROM category_path AS cp JOIN category AS c ON cp.id = c.parent_id ) SELECT * FROM category_path ORDER BY path;
查询单个路径
要从下到上查询单个路径,例如 from iOSto Electronics,请使用以下语句:WITH RECURSIVE category_path (id, title, parent_id) AS ( SELECT id, title, parent_id FROM category WHERE id = 10 -- child node UNION ALL SELECT c.id, c.title, c.parent_id FROM category_path AS cp JOIN category AS c ON cp.parent_id = c.id ) SELECT * FROM category_path;
计算每个节点的级别
假设根节点的级别为 0,下面的每个节点都有一个等于其父节点的级别加 1 的级别。WITH RECURSIVE category_path (id, title, lvl) AS ( SELECT id, title, 0 lvl FROM category WHERE parent_id IS NULL UNION ALL SELECT c.id, c.title,cp.lvl + 1 FROM category_path AS cp JOIN category AS c ON cp.id = c.parent_id ) SELECT * FROM category_path ORDER BY lvl;
删除节点及其后代
要删除节点及其后代,只需删除节点本身,所有后代将被DELETE CASCADE外键约束自动删除。例如,要删除手机节点及其子节点 ,请使用以下语句:
DELETE FROM category WHERE id =4;
删除节点并提升其后代
要删除非叶节点并提升其后代:首先,parent_id将节点的直接子节点的更新为id新父节点的 。
然后,删除节点。
例如,要删除手机节点并提升其子节点,例如Android, iOS,鸿蒙节点: 首先,更新 的parent_id所有直接子代手机:UPDATE category SET parent_id =2 WHERE parent_id = 4;二、删除Smartphones节点:
DELETE FROM category WHERE id =4;两个语句都应该包含在一个事务中:
BEGIN; UPDATE category SET parent_id =2 WHERE parent_id = 4; DELETE FROM category WHERE id = 4; COMMIT;
移动子树
要移动子树,刚更新的parent_id子树的顶部节点。例如,要将 移动手机 为 的子代andriod到电灯下面,请使用以下语句:UPDATE category SET parent_id = 2 WHERE id = 6;