Self ricorsivi


15

Ho una commentstabella, che può essere semplificata fino a questo:

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

dove parent_idè nullable, ma potrebbe essere una chiave per il commento principale.


Ora, come posso selecttutti i discendenti di un commento specifico?
I commenti potrebbero essere di diversi livelli in basso ...

Risposte:


16

Le query gerarchiche , come sono note quelle query ricorsive, non sono supportate per MySQL.

Sono tuttavia supportati in Oracle, Microsoft SQL Server, DB2 e PostgreSQL, tra gli altri.

Se hai bisogno di una soluzione alternativa, puoi trovare un trucco dinamico (e quindi potenzialmente pericoloso) qui: /programming/8104187/mysql-hierarchical-queries

Puoi anche trovare una discussione su come archiviare i dati gerarchici con altri modelli che con un elenco di adiacenza (ovvero la colonna Parent ) qui: /programming/192220/what-is-the-most-efficient- elegante-way-to-parse-a-flat-tavolo-in-a-tree /

In bocca al lupo!


Mi chiedo come quella soluzione nel tuo secondo link possa essere pericolosa. Potresti spiegarlo? Altrimenti, benvenuto nel sito!
dezso

3
@dezso: Quassnoi è il mago stesso della query, " * Non è sicuro per l'aggiornamento * perché MySQL non definisce chiaramente il comportamento delle variabili di sessione. Tuttavia, è l'unico modo per gestire tempestivamente gli elenchi di adiacenza ." Pericolosa potrebbe essere stata una parola troppo forte ( potenzialmente instabile ?), Ma preferisco sbagliare per cautela (in più, sono più ben informato in Oracle che in MySQL, quindi volevo essere più precario). Grazie per il benvenuto, a proposito! Sono stato a lungo in agguato alla rete SE, e ho deciso che era tempo di ripagare un po '.
Valmoer,

2
La sintassi WITH [RECURSIVE] è ora supportata da mysql 8.0. dev.mysql.com/doc/refman/8.0/it/with.html
ClearCrescendo,

6

Il design di questa tabella è un antipasto SQL "Alberi ingenui" come descritto da Bill Karwin (a partire dalla diapositiva 48 nel suo SQL Antipatterns Strike Back ). Il problema con questo progetto è in particolare la difficoltà di ottenere tutti i discendenti (o genitori) di un nodo. Dato che stai usando MySQL non puoi usare espressioni di tabella comuni (l'istruzione WITH e il suo modificatore RECURSIVE) presenti in altri RDBMS.

Quello che ti rimane è:

  • utilizzare un'implementazione alternativa della struttura gerarchica dei dati (le risposte a questa domanda potrebbero essere un buon riferimento su questo)
  • creare query di auto-join con un limite di profondità. Per profondità = 5 potresti usare qualcosa nelle righe di:

    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)
  • usa un RDBMS che supporti WITH RECURSIVE (anche se molto probabilmente non è un'opzione per la maggior parte delle persone)


2
Non sono d'accordo con Bill Karwin qui. Il modello di adiacenza non è un anti-schema. Con un moderno DBMS che supporta query ricorsive (Oracle lo supporta da oltre 20 anni), tale modello è molto efficiente da recuperare e aggiornare.
a_horse_with_no_name l'

5

MySQL non supporta query ricorsive come quella di cui hai bisogno.

Quello che ho fatto qualche tempo fa è stato scrivere Stored Procedure che forniscono il modello per farlo.

Invece di reinventare la ruota, ti darò i link ai miei post precedenti su questo:

In breve, le Stored Procedures che ho fatto eseguono il pre-attraversamento dell'albero usando l'elaborazione della coda

  • GetParentIDByID
  • GetAncestry
  • GetFamilyTree

Parent to All Children (come GetFamilyTree Stored Procedure)

  • STEP01) Inizia con a parent_idin una coda
  • STEP02) Dequeue il successivo parent_idcome corrente
  • PASSAGGIO03) Accodare tutti i idvalori che hanno la correnteparent_id
  • PASSO04) Stampa o raccogli il commento
  • PASSO05) Se la coda non è vuota, vai a STEP02
  • PASSO06) Hai finito !!!

Figlio di tutti i genitori (come GetAncestry Stored Procedure)

  • STEP01) Inizia con un idin una coda
  • STEP02) Dequeue il successivo idcome corrente
  • STEP03) Accodare il parent_idvalore della correnteid
  • PASSO04) Stampa o raccogli il commento
  • PASSO05) Se la coda non è vuota, vai a STEP02
  • PASSO06) Hai finito !!!

Per favore guarda le Stored procedure negli altri miei post per vedere l'implementazione.

Provaci !!!


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

violino

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.