Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Sortowanie poddrzewa w hierarchicznej strukturze danych tabeli zamknięć

To pytanie pojawia się często nie tylko w przypadku tabeli zamykania, ale także innych metod przechowywania danych hierarchicznych. W żadnym z projektów nie jest to łatwe.

Rozwiązanie, które wymyśliłem dla Closure Table obejmuje jedno dodatkowe sprzężenie. Każdy węzeł w drzewie dołącza do łańcucha swoich przodków, jak zapytanie typu „bułka tarta”. Następnie użyj GROUP_CONCAT(), aby zwinąć bułkę tartą w ciąg oddzielony przecinkami, sortując numery identyfikatorów według głębokości w drzewie. Teraz masz ciąg, według którego możesz sortować.

SELECT c2.*, cc2.ancestor AS `_parent`,
  GROUP_CONCAT(breadcrumb.ancestor ORDER BY breadcrumb.depth DESC) AS breadcrumbs
FROM category AS c1
JOIN category_closure AS cc1 ON (cc1.ancestor = c1.id)
JOIN category AS c2 ON (cc1.descendant = c2.id)
LEFT OUTER JOIN category_closure AS cc2 ON (cc2.descendant = c2.id AND cc2.depth = 1)
JOIN category_closure AS breadcrumb ON (cc1.descendant = breadcrumb.descendant)
WHERE c1.id = 1/*__ROOT__*/ AND c1.active = 1
GROUP BY cc1.descendant
ORDER BY breadcrumbs;

+----+------------+--------+---------+-------------+
| id | name       | active | _parent | breadcrumbs |
+----+------------+--------+---------+-------------+
|  1 | Cat 1      |      1 |    NULL | 1           |
|  3 | Cat  1.1   |      1 |       1 | 1,3         |
|  4 | Cat  1.1.1 |      1 |       3 | 1,3,4       |
|  7 | Cat 1.1.2  |      1 |       3 | 1,3,7       |
|  6 | Cat 1.2    |      1 |       1 | 1,6         |
+----+------------+--------+---------+-------------+

Zastrzeżenia:

  • Wartości identyfikatora powinny mieć jednakową długość, ponieważ sortowanie „1,3”, „1,6” i „1327” może nie dać zamierzonej kolejności. Ale sortowanie „001,003” i „001,006” i „001,327”. Więc albo musisz zacząć swoje wartości id od 1000000+, albo użyć ZEROFILL dla przodka i potomka w tabeli category_closure.
  • W tym rozwiązaniu kolejność wyświetlania zależy od kolejności numerycznej identyfikatorów kategorii. Ta kolejność liczbowa wartości identyfikatorów może nie odpowiadać kolejności, w jakiej chcesz wyświetlić drzewo. Lub możesz chcieć mieć swobodę zmiany kolejności wyświetlania niezależnie od wartości liczbowych identyfikatorów. Możesz też chcieć, aby te same dane kategorii pojawiały się w więcej niż jednym drzewie, każde z inną kolejnością wyświetlania.
    Jeśli potrzebujesz większej swobody, musisz przechowywać wartości kolejności sortowania oddzielnie od identyfikatorów, a rozwiązanie zostanie jeszcze bardziej złożony. Ale w większości projektów dopuszczalne jest użycie skrótu, podając identyfikator kategorii jako kolejność wyświetlania drzewa.

Odpowiedz na swój komentarz:

Tak, możesz przechowywać „porządek sortowania rodzeństwa” jako inną kolumnę w tabeli zamknięcia, a następnie użyć tej wartości zamiast ancestor do zbudowania ciągu bułki tartej. Ale jeśli to zrobisz, skończysz z dużą nadmiarowością danych. Oznacza to, że dany przodek jest przechowywany w wielu rzędach, po jednym dla każdej ścieżki od niego opadającej. Musisz więc zapisać tę samą wartość dla sortowania rodzeństwa we wszystkich tych wierszach, co stwarza ryzyko anomalii.

Alternatywą byłoby utworzenie kolejnej tabeli z tylko jedną wiersz na odrębnego przodka w drzewie i dołącz do tego stołu, aby uzyskać kolejność rodzeństwa.

CREATE TABLE category_closure_order (
  ancestor INT PRIMARY KEY,
  sibling_order SMALLINT UNSIGNED NOT NULL DEFAULT 1
);

SELECT c2.*, cc2.ancestor AS `_parent`,
  GROUP_CONCAT(o.sibling_order ORDER BY breadcrumb.depth DESC) AS breadcrumbs
FROM category AS c1
JOIN category_closure AS cc1 ON (cc1.ancestor = c1.id)
JOIN category AS c2 ON (cc1.descendant = c2.id)
LEFT OUTER JOIN category_closure AS cc2 ON (cc2.descendant = c2.id AND cc2.depth = 1)
JOIN category_closure AS breadcrumb ON (cc1.descendant = breadcrumb.descendant)
JOIN category_closure_order AS o ON breadcrumb.ancestor = o.ancestor
WHERE c1.id = 1/*__ROOT__*/ AND c1.active = 1
GROUP BY cc1.descendant
ORDER BY breadcrumbs;

+----+------------+--------+---------+-------------+
| id | name       | active | _parent | breadcrumbs |
+----+------------+--------+---------+-------------+
|  1 | Cat 1      |      1 |    NULL | 1           |
|  3 | Cat  1.1   |      1 |       1 | 1,1         |
|  4 | Cat  1.1.1 |      1 |       3 | 1,1,1       |
|  7 | Cat 1.1.2  |      1 |       3 | 1,1,2       |
|  6 | Cat 1.2    |      1 |       1 | 1,2         |
+----+------------+--------+---------+-------------+



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zaktualizuj kolumnę na podstawie pasujących wartości w innej tabeli w mysql

  2. mysql wybierz identyfikator i nazwę z innej tabeli i dołącz do zapytania

  3. Jak ustawić hasło roota na null?

  4. PDO bind_param to niezdefiniowana metoda

  5. MySQL IFNULL N/A zwraca element nie można znaleźć w kolekcji Błąd