2009-03-18 8 views
9

Ultimamente sto usando lo schifo del Nested Set Model. Mi sono divertito a progettare le query per quasi tutte le operazioni e le visualizzazioni utili. Una cosa su cui sono bloccato è come selezionare i bambini immediati (e solo i bambini, non più discendenti!) Di un nodo.Esiste un modo semplice per interrogare i figli di un nodo?

Per essere onesti, so di un modo - ma comporta quantità ingestibili di SQL. Sono sicuro che esiste una soluzione più semplice.

risposta

9

Hai letto l'articolo che hai pubblicato? E 'sotto la voce "Trova i subalterni immediati di un nodo"

SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth 
FROM nested_category AS node, 
    nested_category AS parent, 
    nested_category AS sub_parent, 
    (
     SELECT node.name, (COUNT(parent.name) - 1) AS depth 
     FROM nested_category AS node, 
     nested_category AS parent 
     WHERE node.lft BETWEEN parent.lft AND parent.rgt 
     AND node.name = 'PORTABLE ELECTRONICS' 
     GROUP BY node.name 
     ORDER BY node.lft 
    )AS sub_tree 
WHERE node.lft BETWEEN parent.lft AND parent.rgt 
    AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt 
    AND sub_parent.name = sub_tree.name 
GROUP BY node.name 
HAVING depth <= 1 
ORDER BY node.lft; 

Tuttavia, quello che faccio (questo è barare) è ho unito l'insieme nidificato con liste di adiacenza - a incorporare un "parent_id" nella tabella , quindi posso facilmente chiedere i figli di un nodo.

+0

"... ho unito il set nidificato con liste di adiacenza ..." Ah! È quello che sto facendo. Mi unisco a un adj. visualizzazione elenco, basata su una query di Joe Celko. Sembra solo un sacco di codice. Anche la soluzione dell'articolo correlato è ... prolissa. – Metaphile

+0

Voglio dire, confrontare la selezione di tutti i discendenti di un nodo: SELECT * FROM nodes WHERE nodes.leftBound BETWEEN parentLeftBound AND parentRightBound; – Metaphile

+0

Bene, "child_view" è piuttosto semplice, SELECT * FROM nodes WHERE parent_id = 123456: D –

7

Mi sembra che questo dovrebbe essere facilmente realizzabile senza subquery o ridondanza della colonna genitore! Ad esempio, a sinistra data di genitore e destra sono già noti:

SELECT child.id 
FROM nodes AS child 
LEFT JOIN nodes AS ancestor ON 
    ancestor.left BETWEEN @parentleft+1 AND @parentright-1 AND 
    child.left BETWEEN ancestor.left+1 AND ancestor.right-1 
WHERE 
    child.left BETWEEN @parentleft+1 AND @parentright-1 AND 
    ancestor.id IS NULL 

Cioè, “da tutti i discendenti del nodo in questione, scegliere quelli con nessun antenato tra di loro e il nodo”.

+0

Mi chiedo quale risposta sia migliore nelle prestazioni, in questo o nel post accettato. Tuttavia, entrambe le soluzioni funzionano. Questo sembra un po 'più compatto. – andreas

+0

Per alberi di dimensioni molto grandi, abbiamo trovato che questo ha prestazioni scarse in MySQL e peggio in SQL server perché richiede un ciclo nidificato da eseguire sul database. Abbiamo cambiato il nostro codice per recuperare solo tutti i discendenti e quindi potare solo i bambini nel nostro codice applicazione. – user393274

+0

@andreas Questo è molto simile alla risposta accettata, la differenza è che invece di contare i bambini e di filtrare quelli con 1 figlio, filtra vedendo se l'antenato è NULL. Ciò significa che ha meno lavoro da fare (nessun tipo e contare il passo). Dovrebbe essere più veloce, ma non l'ho provato. – Ariel

5

questo è meglio e più piccolo

utente "bobince" quasi l'aveva. L'ho capito e ho funzionato per me perché ho un po 'più di esperienza MySQL di molti altri. Tuttavia, posso capire perché la risposta di Bobince potrebbe spaventare la gente. La sua richiesta è incompleta. Devi prima selezionare parent_left e parent_right nelle variabili mysql.

Le due query sotto supporre che la tabella si chiama tree, la colonna di sinistra è chiamato lft, colonna di destra è chiamato rgt, e che la chiave primaria è chiamato id. Cambia questi valori in base alle tue esigenze. Inoltre, esaminare la prima istruzione select. Vedrai che sto cercando i discendenti immediati del nodo 5. Cambia il numero 5 per cercare i figli di qualunque nodo tu voglia.

Personalmente ritengo che questa sia una query più elegante, più sexy e più efficiente rispetto agli altri presentati finora.

SELECT `lft`, `rgt` INTO @parent_left, @parent_right FROM efm_files WHERE `id` = 5; 
SELECT `child`.`id` 
FROM `tree` AS `child` 
LEFT JOIN `tree` AS `ancestor` ON 
    `ancestor`.`lft` BETWEEN @parent_left+1 AND @parent_right-1 AND 
    `child`.`lft` BETWEEN `ancestor`.`lft`+1 AND `ancestor`.`rgt`-1 
WHERE 
    `child`.`lft` BETWEEN @parent_left+1 AND @parent_right-1 AND 
    `ancestor`.`id` IS NULL 
+0

Che cos'è 'efm_files'? – Madbreaks

+0

efm_files è il nome di una tabella nel mio database mysql. Sostituirlo con il proprio nome di tabella per il proprio database. – mrbinky3000

0

So che sto facendo un post necro, ma qui è la mia opinione.

perché non includere una colonna "profondità" nel set nidificato? la colonna di profondità indicherà il "livello" di un articolo.

così, per selezionare il bambino immediati di un elemento, basta fare

select c.*
from tree as p
join tree as c on (c.left > p.left and c.right < p.right and c.depth = p.dept + 1) where p.id = @parentID

+0

Perché in senso stretto non è più un insieme nidificato, è una combinazione di modelli gerarchici. E il più delle volte, cambiare il modello per risolvere un problema non è un'opzione. – Madbreaks

0

mi piacerebbe andare con una colonna di profondità, anche. Ma l'uso

SELECT Child.Node, Child.LEFT, Child.RIGHT 
FROM Tree AS Child, Tree AS Parent 
WHERE 
     Child.Depth = Parent.Depth + 1 
     AND Child.LEFT > Parent.LEFT 
     AND Child.RIGHT < Parent.RIGHT 
     AND Parent.LEFT = 1 -- Given Parent Node Left Index 

Wikipedia

+0

Nota che richiede * ulteriore * colonna di profondità insieme a sinistra e destra Id. – Youngjae

0

ho trovato Wikipedia link ha una buona versione ridotta di risposta con risposta selezionata.

SELECT DISTINCT Child.Name 
FROM ModelTable AS Child, ModelTable AS Parent 
WHERE Parent.Lft < Child.Lft AND Parent.Rgt > Child.Rgt -- associate Child Nodes with ancestors 
GROUP BY Child.Name 
HAVING MAX(Parent.Lft) = @parentId -- Subset for those with the given Parent Node as the nearest ancestor 

E, qualcuno di voi cercare di esprimere con LINQ, segui il link: https://stackoverflow.com/a/25594386/361100

Problemi correlati