树结构反转(MySQL)
我有一个类别树,它有两种结构:每个类别都有一个路径和一个parentID。路径是从IDs类别的底部到顶部创建的。parentID引用另一个类别。我的桌子是这样的:树结构反转(MySQL),mysql,sql,Mysql,Sql,我有一个类别树,它有两种结构:每个类别都有一个路径和一个parentID。路径是从IDs类别的底部到顶部创建的。parentID引用另一个类别。我的桌子是这样的: id | name | path | parentID ---+-------------+---------+--------- 1 | Root | NULL | NULL 2 | Main | NULL | 1 3 | Electronics | |2|
id | name | path | parentID
---+-------------+---------+---------
1 | Root | NULL | NULL
2 | Main | NULL | 1
3 | Electronics | |2| | 2
4 | Computers | |3|2| | 3
5 | PCs | |4|3|2| | 4
6 | Macs | |4|3|2| | 4
7 | Cameras | |3|2| | 3
8 | Canon | |7|3|2| | 7
id | resolved_path
---+-----------------------------
3 | Electronics
4 | Electronics_Computers
5 | Electronics_Computers_PCs
6 | Electronics_Computers_Macs
7 | Electronics_Cameras
8 | Electronics_Cameras_Canon
现在我不需要类别“Root”和“Main”。我试图实现如下输出:
id | name | path | parentID
---+-------------+---------+---------
1 | Root | NULL | NULL
2 | Main | NULL | 1
3 | Electronics | |2| | 2
4 | Computers | |3|2| | 3
5 | PCs | |4|3|2| | 4
6 | Macs | |4|3|2| | 4
7 | Cameras | |3|2| | 3
8 | Canon | |7|3|2| | 7
id | resolved_path
---+-----------------------------
3 | Electronics
4 | Electronics_Computers
5 | Electronics_Computers_PCs
6 | Electronics_Computers_Macs
7 | Electronics_Cameras
8 | Electronics_Cameras_Canon
所以我有一个不同的深度,我需要的类别是相反的顺序。我在网上没有找到太多关于这个的信息。我得到的只是这个片段,它显示了类别的深度:
SELECT
*,
(ROUND(
(LENGTH(cat.path) - LENGTH(REPLACE(cat.path, '|', ''))) / LENGTH('|')
) - 2) depth
FROM
categories cat
WHERE
cat.path IS NOT NULL
我不知道什么更容易:递归地遍历parentID或对路径进行一些处理。您可以使用这个未优化的函数作为基线:
DELIMITER //
DROP FUNCTION IF EXISTS extract_path //
CREATE FUNCTION extract_path(idlist VARCHAR(255))
RETURNS LONGTEXT
BEGIN
DECLARE result LONGTEXT;
DECLARE tmplist VARCHAR(255);
DECLARE buffer VARCHAR(255);
DECLARE lastpos INT;
-- reverse and trim last separator (that first of reversed string)
SELECT TRIM(BOTH FROM SUBSTRING(REVERSE(idlist), 2)) INTO tmplist;
mainloop: LOOP
-- split on separator
SELECT LOCATE('|', tmplist) INTO lastpos;
-- detect end
IF lastpos IS NULL OR lastpos < 2
THEN LEAVE mainloop;
END IF;
-- resolve next id
SELECT cat.name INTO buffer
FROM categories cat
WHERE cat.id = TRIM(REVERSE(SUBSTRING(tmplist, 1, lastpos - 1)));
-- append new element
SELECT CONCAT(COALESCE(CONCAT(result, '_'), ''), buffer) INTO result;
-- prepare for next iteration
SELECT TRIM(BOTH FROM SUBSTRING(tmplist, lastpos + 1)) INTO tmplist;
-- detect end (corner case)
IF tmplist IS NULL
THEN LEAVE mainloop;
END IF;
END LOOP;
RETURN result;
END //
SELECT extract_path('|1|2|3|');
-- with categories 1 -> foo ; 2 -> bar ; 3 -> baz
-- output is 'baz_bar_foo'
DELIMITER ;
您可以使用此未优化的函数作为基线:
DELIMITER //
DROP FUNCTION IF EXISTS extract_path //
CREATE FUNCTION extract_path(idlist VARCHAR(255))
RETURNS LONGTEXT
BEGIN
DECLARE result LONGTEXT;
DECLARE tmplist VARCHAR(255);
DECLARE buffer VARCHAR(255);
DECLARE lastpos INT;
-- reverse and trim last separator (that first of reversed string)
SELECT TRIM(BOTH FROM SUBSTRING(REVERSE(idlist), 2)) INTO tmplist;
mainloop: LOOP
-- split on separator
SELECT LOCATE('|', tmplist) INTO lastpos;
-- detect end
IF lastpos IS NULL OR lastpos < 2
THEN LEAVE mainloop;
END IF;
-- resolve next id
SELECT cat.name INTO buffer
FROM categories cat
WHERE cat.id = TRIM(REVERSE(SUBSTRING(tmplist, 1, lastpos - 1)));
-- append new element
SELECT CONCAT(COALESCE(CONCAT(result, '_'), ''), buffer) INTO result;
-- prepare for next iteration
SELECT TRIM(BOTH FROM SUBSTRING(tmplist, lastpos + 1)) INTO tmplist;
-- detect end (corner case)
IF tmplist IS NULL
THEN LEAVE mainloop;
END IF;
END LOOP;
RETURN result;
END //
SELECT extract_path('|1|2|3|');
-- with categories 1 -> foo ; 2 -> bar ; 3 -> baz
-- output is 'baz_bar_foo'
DELIMITER ;
你可以把这个答案改成相反的顺序:@Preuk我的问题是我的深度不同。所以我需要某种循环来实现这个解决方案。有没有办法做到这一点?为什么不创建一个中间表categories\u parents,用于搜索父类别?。“这是一个更快更简单的方法。”胡安拉格说,这个主意其实还不错。只是为了确保我理解你的意思:我会通过php或类似的方式循环遍历类别,并创建一个表,在其中存储每个类别的父类别?这并不是我真正想要的,因为我尝试用MySQL来完成这一切,但我会尝试一下。看看这个:你可以将这个答案按相反的顺序进行调整:@Preuk我的问题是我的深度不同。所以我需要某种循环来实现这个解决方案。有没有办法做到这一点?为什么不创建一个中间表categories\u parents,用于搜索父类别?。“这是一个更快更简单的方法。”胡安拉格说,这个主意其实还不错。只是为了确保我理解你的意思:我会通过php或类似的方式循环遍历类别,并创建一个表,在其中存储每个类别的父类别?这并不是我真正想要的,因为我尝试用MySQL来完成这一切,但我会尝试一下。看看这个:@jkrzefski没问题,问问你是否需要澄清。无论如何,我建议你考虑把你的模型当做Juan Lago评论。您可以从my函数中提取元素来构建中间表。@jkrzefski没问题,只要询问是否需要澄清即可。无论如何,我建议你考虑把你的模型当做Juan Lago评论。您可以从my函数中提取元素来构建中间表。