2009-03-23 17 views
7

Ho una tabella del database MySQL con questa struttura:Recupero lista collegata nel database MySQL

table 
    id INT NOT NULL PRIMARY KEY 
    data .. 
    next_id INT NULL 

ho bisogno di recuperare i dati in ordine di lista collegata. Ad esempio, in questi dati:

id | next_id 
----+--------- 
    1 |  2 
    2 |  4 
    3 |  9 
    4 |  3 
    9 | NULL 

ho bisogno di recuperare le righe per id = 1, 2, 4, 3, 9, in questo ordine. Come posso fare questo con una query del database? (Posso farlo sul lato client.Sono curioso se questo può essere fatto dal lato del database.Così, dicendo che è impossibile va bene (dato prova sufficiente)).

Sarebbe bello avere anche un punto di terminazione (ad es. Fermarsi dopo 10 recuperi o quando alcune condizioni della fila diventano vere) ma questo non è un requisito (può essere fatto dal lato client). Io (spero di farlo) non è necessario verificare i riferimenti circolari.

+0

Sei in grado di creare tabelle indice aggiuntive? Sono davvero curioso di spiegare il piano per la query suggerita da Bill. Potrebbe non essere così male visto che è sempre in cerca sulla chiave primaria. Suppongo che fornirai l'ID del primo nodo nella tua query. (altrimenti, sarà brutale). 10 viaggi di andata lo farebbero (lo so, non quello che hai chiesto). Le tabelle temporanee create nella query potrebbero farlo, in particolare se il risultato lo ha impostato in modo ridotto. – TheJacobTaylor

risposta

5

Alcune marche di database (ad esempio Oracle, Microsoft SQL Server) supportano la sintassi SQL aggiuntiva per eseguire "query ricorsive", ma MySQL non supporta alcuna soluzione di questo tipo.

Il problema che si sta descrivendo è lo stesso di una struttura ad albero in un database SQL. Hai solo un albero lungo e magro.

Esistono diverse soluzioni per la memorizzazione e il recupero di questo tipo di struttura dati da un RDBMS. Vedere alcune delle seguenti domande:


Dal momento che si parla che si desidera limitare la "profondità" restituito dalla query, è possibile ottenere questo mentre interrogando l'elenco in questo modo:

SELECT * FROM mytable t1 
LEFT JOIN mytable t2 ON (t1.next_id = t2.id) 
LEFT JOIN mytable t3 ON (t2.next_id = t3.id) 
LEFT JOIN mytable t4 ON (t3.next_id = t4.id) 
LEFT JOIN mytable t5 ON (t4.next_id = t5.id) 
LEFT JOIN mytable t6 ON (t5.next_id = t6.id) 
LEFT JOIN mytable t7 ON (t6.next_id = t7.id) 
LEFT JOIN mytable t8 ON (t7.next_id = t8.id) 
LEFT JOIN mytable t9 ON (t8.next_id = t9.id) 
LEFT JOIN mytable t10 ON (t9.next_id = t10.id); 

Sarà perf Mi piace la melassa e il risultato tornerà tutto su una riga (per elenco collegato), ma otterrai il risultato.

+0

Il primo collegamento sembra molto interessante. Purtroppo, non posso cambiare la struttura del database. Può essere modificato in qualche modo per soddisfare le mie esigenze? In caso contrario, aspetterò di vedere se qualcun altro risponde di "sì". – strager

+0

Crazy SELECT lì. =] Dirò solo che questo è impossibile da ottenere ragionevolmente. Grazie per le informazioni! – strager

+0

Sì, non raccomanderei un SELECT come quello. Ma hai detto che non puoi cambiare la struttura del database - a volte non c'è altra scelta. –

2

Questa è meno una soluzione e più di una soluzione, ma, per una lista lineare (piuttosto che l'albero menzionato da Bill Karwin), potrebbe essere più efficiente utilizzare una colonna di ordinamento nel proprio elenco. Ad esempio:

TABLE `schema`.`my_table` (
    `id` INT NOT NULL PRIMARY KEY, 
    `order` INT, 
    data .., 
    INDEX `ix_order` (`sort_order` ASC) 
); 

Poi:

SELECT * FROM `schema`.`my_table` ORDER BY `order`; 

Questo ha lo svantaggio di inserti più lenti (bisogna riposizionare tutti gli elementi filtrate oltre il punto di inserimento) ma dovrebbe essere veloce per il recupero perché la colonna ordine è indicizzato.

+0

Purtroppo non sono riuscito a modificare la struttura del database perché altri programmi dipendevano dalla struttura. Grazie per la tua indicazione, comunque! – strager

+0

Ironicamente, questa è la soluzione con cui l'utente ha iniziato a [questa domanda] (http://stackoverflow.com/questions/10594408/insert-record-into-table-with-position-without-updating-all-the -records-position), che gli intervistati hanno detto dovrebbero essere cambiati nello stile dell'elenco collegato che l'OP sta usando in questa domanda! Sembra che archiviare un ordine di registrazione arbitrario in un database sia solo un problema difficile ... – octern

3

Se ciò che si sta tentando di evitare è avere più query (una per ogni nodo) e si è in grado di aggiungere colonne, si potrebbe avere una nuova colonna che si collega al nodo radice. In questo modo è possibile inserire tutti i dati contemporaneamente dall'ID root, ma sarà comunque necessario ordinare l'elenco (o albero) sul lato client.

Quindi, in questo è caso si ha:

id | next_id | root_id 
----+---------+--------- 
    1 |  2 |  1 
    2 |  4 |  1 
    3 |  9 |  1 
    4 |  3 |  1 
    9 | NULL |  1 

Naturalmente lo svantaggio di questo al contrario di liste tradizionali legate o alberi è che la radice non può cambiare senza scrivere su un ordine di grandezza di O (n) dove n è il numero di nodi. Questo perché dovresti aggiornare l'id root per ogni nodo. Fortunatamente, dovresti sempre essere in grado di farlo in una singola query di aggiornamento, a meno che tu non stia dividendo un elenco/albero nel mezzo.

+0

Questa soluzione è abbastanza grande. – appl3r

Problemi correlati