2011-10-03 12 views
17

Tutti,connettersi equivalente Prima di MySQL

ho tre campi di una tabella che definiscono una relazione genitore-figlio presenti in un database MySQL versione 5.0. Il nome della tabella è tb_Tree ed ha i seguenti dati:

Table Name: tb_Tree 

Id | ParentId | Name 
-------------------- 
1 | 0  | Fruits 
2 | 0  | Vegetables 
3 | 1  | Apple 
4 | 1  | Orange 
5 | 2  | Cabbage 
6 | 2  | Eggplant 

Come faccio a scrivere una query per ottenere tutti i bambini se viene specificato un ParentId. Si noti che le voci della tabella fornite sono solo dati di esempio e possono avere molte più righe. Oracle ha una clausola "CONNECT BY PRIOR", ma non ho trovato nulla di simile per MySQL. Qualcuno può consigliare?

Grazie

+0

penso "CON" può aiutare con query ricorsive. – FUD

+0

puoi per favore elaborare? Grazie – Jake

+1

MySQL non ha CTE ('WITH') –

risposta

10

MySQL non supporta le query ricorsive quindi bisogna farlo nel modo più duro:

  1. selezionare le righe in cui ParentID = X dove X è root.
  2. Raccogliere i valori Id da (1).
  3. Ripetere (1) per ogni Id da (2).
  4. Continuare a ricorrere a mano fino a trovare tutti i nodi foglia.

Se si conosce una profondità massima allora si può unire la vostra tabella con se stessa (utilizzando SINISTRA outer join) verso la profondità massima possibile e poi pulire i NULL.

È inoltre possibile modificare la rappresentazione ad albero in nested sets.

1

Questo è un vecchio thread, ma da quando sono arrivato la questione in un altro forum ho pensato aggiungilo qui. In questo caso, ho creato una procedura memorizzata che è codificata per gestire il caso specifico. Questo, naturalmente, ha alcuni inconvenienti poiché non tutti gli utenti possono creare stored procedure a piacimento, ma ciò nonostante.

consideri la seguente tabella con i nodi e figli:

CREATE TABLE nodes (
     parent INT, 
     child INT 
); 

INSERT INTO nodes VALUES 
     (5, 2), (5, 3), 
     (18, 11), (18, 7), 
     (17, 9), (17, 8), 
     (26, 13), (26, 1), (26,12), 
     (15, 10), (15, 5),  
     (38, 15), (38, 17), (38, 6), 
     (NULL, 38), (NULL, 26), (NULL, 18); 

Con questa tabella, il seguente stored procedura calcola un set di risultati costituito da tutti i discendenti del nodo previste:

delimiter $$ 
CREATE PROCEDURE find_parts(seed INT) 
BEGIN 
    -- Temporary storage 
    DROP TABLE IF EXISTS _result; 
    CREATE TEMPORARY TABLE _result (node INT PRIMARY KEY); 

    -- Seeding 
    INSERT INTO _result VALUES (seed); 

    -- Iteration 
    DROP TABLE IF EXISTS _tmp; 
    CREATE TEMPORARY TABLE _tmp LIKE _result; 
    REPEAT 
    TRUNCATE TABLE _tmp; 
    INSERT INTO _tmp SELECT child AS node 
     FROM _result JOIN nodes ON node = parent; 

    INSERT IGNORE INTO _result SELECT node FROM _tmp; 
    UNTIL ROW_COUNT() = 0 
    END REPEAT; 
    DROP TABLE _tmp; 
    SELECT * FROM _result; 
END $$ 
delimiter ; 
1

Il sottostante select elenca tutti gli impianti e il loro parentid fino a 4 livelli (e ovviamente è possibile estendere il livello):

select id, name, parentid 
,(select parentid from tb_tree where id=t.parentid) parentid2 
,(select parentid from tb_tree where id=(select parentid from tb_tree where id=t.parentid)) parentid3 
,(select parentid from tb_tree where id=(select parentid from tb_tree where id=(select parentid from tb_tree where id=t.parentid))) parentid4 
from tb_tree t 

e quindi è possibile utilizzare questa query per ottenere il risultato finale. per esempio, è possibile ottenere tutti i figli di "frutti" dal sql qui sotto:

select id ,name from (
    select id, name, parentid 
    ,(select parentid from tb_tree where id=t.parentid) parentid2 
    ,(select parentid from tb_tree where id=(select parentid from tb_tree where id=t.parentid)) parentid3 
    ,(select parentid from tb_tree where id=(select parentid from tb_tree where id=(select parentid from tb_tree where id=t.parentid))) parentid4 
    from tb_tree t) tt 
where ifnull(parentid4,0)=1 or ifnull(parentid3,0)=1 or ifnull(parentid2,0)=1 or ifnull(parentid,0)=1 
0

L'ordine seguente procedura memorizzata una tabella che ha righe con riferimento all'indietro alla precedente. Nota sul primo passaggio copio le righe nella tabella temporanea: quelle righe corrispondono a qualche condizione. Nel mio caso quelle sono file che appartengono allo stesso lineare (strada che viene utilizzata nella navigazione GPS).Il dominio aziendale non è importante. Solo nel mio caso sto smistando segmenti che appartengono alla stessa strada

PROCEDURA DI GOCCIA SE ESISTE orderLocations; DELIMITER //

CREA orderLocations procedura (_full_linear_code VARCHAR (11)) BEGIN

DECLARE _code VARCHAR(11); 
DECLARE _id INT(4); 
DECLARE _count INT(4); 
DECLARE _pos INT(4); 

DROP TEMPORARY TABLE IF EXISTS temp_sort; 

CREATE TEMPORARY TABLE temp_sort (
    id    INT(4) PRIMARY KEY, 
    pos    INT(4), 
    code   VARCHAR(11), 
    prev_code  VARCHAR(11) 
); 

-- copy all records to sort into temp table - this way sorting would go all in memory 
INSERT INTO temp_sort SELECT 
         id, -- this is primary key of original table 
         NULL, -- this is position that still to be calculated 
         full_tmc_code, -- this is a column that references sorted by 
         negative_offset -- this is a reference to the previous record (will be blank for the first) 
         FROM tmc_file_location 
         WHERE linear_full_tmc_code = _full_linear_code; 

-- this is how many records we have to sort/update position 
SELECT count(*) 
FROM temp_sort 
INTO _count; 

-- first position index 
SET _pos = 1; 

-- pick first record that has no prior record 
SELECT 
    code, 
    id 
FROM temp_sort l 
WHERE prev_code IS NULL 
INTO _code, _id; 

-- update position of the first record 
UPDATE temp_sort 
SET pos = _pos 
WHERE id = _id; 

-- all other go by chain link 
WHILE (_pos < _count) DO 
    SET _pos = _pos +1; 

    SELECT 
    code, 
    id 
    FROM temp_sort 
    WHERE prev_code = _code 
    INTO _code, _id; 


    UPDATE temp_sort 
    SET pos = _pos 
    WHERE id = _id; 

END WHILE; 

-- join two tables and return position along with all other fields 
SELECT 
    t.pos, 
    l.* 
FROM tmc_file_location l, temp_sort t 
WHERE t.id = l.id 
ORDER BY t.pos; 

END; 
Problemi correlati