Własne rekurencyjne dołączanie

15

Mam commentstabelę, którą można uprościć do tego stopnia :

comments
=======
id
user_id
text
parent_id

gdzie parent_idjest zerowalne, ale może być kluczem do jego komentarza nadrzędnego.


Jak mogę teraz selectwszystkich potomków określonego komentarza?
Komentarze mogą być kilka poziomów niżej ...

Josh
źródło

Odpowiedzi:

16

Hierarchiczne zapytania , jak wiadomo te zapytania rekurencyjne, nie są obsługiwane dla MySQL.

Są one jednak obsługiwane między innymi w Oracle, Microsoft SQL Server, DB2 i PostgreSQL.

Jeśli potrzebujesz obejścia, możesz znaleźć dynamiczną (a więc potencjalnie niebezpieczną) sztuczkę tutaj: /programming/8104187/mysql-hierarchical-queries

Dyskusję na temat przechowywania danych hierarchicznych w innych modelach niż w liście Adjacency (tj. W kolumnie Parent ) można znaleźć tutaj: /programming/192220/what-is-the-the-most-fficient- elegancki sposób na parsowanie płaskiego stołu do drzewa /

Powodzenia!

Valmoer
źródło
Zastanawiam się, jak to rozwiązanie w twoim drugim łączu może być niebezpieczne. Czy możesz to wyjaśnić? W przeciwnym razie witamy na stronie!
dezso,
3
@dezso: Cytując samego twórcę zapytania, Quassnoi „ * To nie jest bezpieczne do uaktualnienia *, ponieważ MySQL nie definiuje wyraźnie zachowania zmiennych sesji. Jest to jednak jedyny sposób radzenia sobie z listami sąsiedztwa we właściwym czasie w zapytaniu ”. Niebezpieczne może być zbyt mocne słowo ( potencjalnie niestabilne ?), Ale wolę się mylić ze względu na ostrożność (a ponadto, mam większą wiedzę na temat Oracle niż MySQL, więc chciałem być bardzo ostrożny). Nawiasem mówiąc, dziękuję za powitanie! Od dawna czaję w sieci SE i zdecydowałem, że nadszedł czas, aby trochę spłacić.
Valmoer,
2
Składnia WITH [RECURSIVE] jest teraz obsługiwana z mysql 8.0. dev.mysql.com/doc/refman/8.0/en/with.html
ClearCrescendo
6

Ten projekt tabeli jest antipatternem SQL „Naiwne drzewa”, jak opisał Bill Karwin (patrząc od slajdu 48 w swojej prezentacji SQL Antipatterns Strike Back ). Problemem w tym projekcie jest w szczególności trudność w uzyskaniu wszystkich potomków (lub rodziców) węzła. Ponieważ używasz MySQL, nie możesz używać wspólnych wyrażeń tabelowych (instrukcja WITH i jej modyfikator RECURSIVE) obecnych w innych RDBMS.

Pozostało ci:

  • użyj alternatywnej implementacji hierarchicznej struktury danych (odpowiedzi na to pytanie mogą być dobrym źródłem informacji na ten temat)
  • buduj zapytania z własnym łączeniem z limitem głębokości. Dla głębokości = 5 możesz użyć czegoś w liniach:

    SELECT *
    FROM comments AS c1
      JOIN comments AS c2 ON (c2.parent_id = c1.id)
      JOIN comments AS c3 ON (c3.parent_id = c2.id)
      JOIN comments AS c4 ON (c4.parent_id = c3.id)
      JOIN comments AS c5 ON (c5.parent_id = c4.id)
  • użyj RDBMS, który obsługuje Z NAGRYWANIEM (chociaż najprawdopodobniej nie jest to opcja dla większości osób)

Redguy
źródło
2
Nie zgadzam się z Billem Karwinem tutaj. Model przylegania nie jest anty-wzorem. Dzięki nowoczesnemu DBMS, który obsługuje zapytania rekurencyjne (Oracle obsługuje to od ponad 20 lat), taki model jest bardzo wydajny w wyszukiwaniu i aktualizacji.
a_horse_w_no_name
5

MySQL nie obsługuje zapytań rekurencyjnych, takich jak te, których potrzebujesz.

To, co zrobiłem jakiś czas temu, to napisanie Procedur składowanych, które zapewniają model do tego.

Zamiast ponownie wymyślić koło, dam ci linki do moich poprzednich postów na ten temat:

Krótko mówiąc, wykonane przeze mnie Procedury przechowywane wykonują przechodzenie drzewa przed kolejnością przy użyciu przetwarzania kolejek

  • GetParentIDByID
  • GetAncestry
  • GetFamilyTree

Nadrzędny dla wszystkich dzieci (jak procedura przechowywana GetFamilyTree)

  • KROK 01) Zacznij od parent_idw kolejce
  • KROK 02) Usuń kolejną parent_idjako bieżącą
  • KROK03) Kolejkuj wszystkie idwartości, które mają prądparent_id
  • KROK04) Wydrukuj lub zbierz komentarz
  • KROK05) Jeśli kolejka nie jest pusta, goto STEP02
  • KROK06) Skończyłeś !!!

Dziecko do wszystkich rodziców (jak procedura przechowywana GetAncestry)

  • KROK 01) Zacznij od idw kolejce
  • KROK 02) Usuń kolejną idjako bieżącą
  • KROK03) Kolejkuj parent_idwartość prąduid
  • KROK04) Wydrukuj lub zbierz komentarz
  • KROK05) Jeśli kolejka nie jest pusta, goto STEP02
  • KROK06) Skończyłeś !!!

Przejrzyj Procedury przechowywane w moich innych postach, aby zobaczyć wdrożenie.

Spróbuj !!!

RolandoMySQLDBA
źródło
2
SELECT  group_concat(@id :=
        (
        SELECT  id
        FROM    comments
        WHERE   parent_id = @id
        )) AS comment
FROM    (
        SELECT  @id := 1
        ) vars
STRAIGHT_JOIN
        comments
WHERE   @id IS NOT NULL

skrzypce

Praveen Prasannan
źródło