MySQL의 메뉴 테이블에서 일관된 메뉴 트리 데이터 얻기
-
13-09-2019 - |
문제
해결할 수 없는 트리/조상/쿼리 문제가 있습니다.
메뉴 데이터가 포함된 테이블과 메뉴의 모든 상위 항목이 포함된 테이블이 있습니다.
table menu table ancestors
+-----+------------+--------+ +---------+--------------+-------+
| id | title | active | | menu_id | ancestor_id | level |
+-----+------------+--------+ +---------+--------------+-------+
| 1 | Home | 0 | | 1 | 0 | 0 |
| 2 | News | 0 | | 2 | 1 | 1 |
| 3 | Foo | 0 | | 3 | 2 | 2 |
| 4 | Bar | 1 | | 3 | 1 | 1 |
| 5 | Downloads | 1 | | 4 | 3 | 3 |
+-----+------------+--------+ | 4 | 2 | 2 |
| 4 | 1 | 1 |
| 5 | 1 | 1 |
+---------+--------------+-------+
다음을 사용하여 조상과 함께 모든 활성 메뉴 항목을 쉽게 얻을 수 있습니다.
SELECT menu.id, menu.title, GROUP_CONCAT(ancestors.ancestor_id) as ancestors
FROM menu, ancestors
WHERE menu.active = 1
GROUP BY (menu.id);
+----+-----------+----------+
| id | title |ancestors |
+----+-----------+----------+
| 4 | Bar | 3,2,1 |
| 5 | Downloads | 1 |
+----+-----------+----------+
그런데 나무에 필요한 조상을 어떻게 모두 얻을 수 있습니까?결과적으로 일관된 트리를 얻으려면 Foo 및 News 항목이 필요합니다.다음과 같아야 합니다.
+----+-----------+----------+
| id | title |ancestors |
+----+-----------+----------+
| 2 | News | 1 |
| 3 | Foo | 2,1 |
| 4 | Bar | 3,2,1 |
| 5 | Downloads | 1 |
+----+-----------+----------+
쿼리는 어떻게 되나요?
해결책
내가 이것을 할 때, 나는 구조를 구성한다. ancestors
테이블이 조금 다릅니다.대신에 level
, 나는 저장한다 pathlength
.또한 경로 길이가 0인 각 메뉴 항목이 자신을 가리키도록 행을 저장합니다.
+---------+--------------+------------+
| menu_id | ancestor_id | pathlength |
+---------+--------------+------------+
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 3 | 0 |
| 4 | 4 | 0 |
| 5 | 5 | 0 |
| 2 | 1 | 1 |
| 3 | 2 | 2 |
| 3 | 1 | 1 |
| 4 | 3 | 3 |
| 4 | 2 | 2 |
| 4 | 1 | 1 |
| 5 | 1 | 1 |
+---------+--------------+------------+
이러한 "반사" 항목을 사용하면 활성 메뉴 항목 세트를 클로저 테이블에 결합할 수 있습니다.레벨을 경로 길이로 변경하면 조상 세트에서 반사 항목을 제외할 수 있습니다.
이제 활성 메뉴 항목 자체를 포함하여 "활성" 메뉴 항목의 조상인 모든 메뉴 항목을 쿼리할 수 있습니다.
SELECT a2.menu_id, m2.title, GROUP_CONCAT(a2.ancestor_id) AS ancestors
FROM menu m1
JOIN ancestors a1 ON (m1.id = a1.menu_id)
JOIN ancestors a2 ON (a1.ancestor_id = a2.menu_id AND a2.pathlength > 0)
JOIN menu m2 ON (a2.menu_id = m2.id)
WHERE m1.active = 1
GROUP BY a2.menu_id;
결과:
+---------+-----------+-----------+
| menu_id | title | ancestors |
+---------+-----------+-----------+
| 2 | News | 1 |
| 3 | Foo | 2,1 |
| 4 | Bar | 3,2,1 |
| 5 | Downloads | 1 |
+---------+-----------+-----------+
제휴하지 않습니다 StackOverflow