2011-10-03 15 views
17

Todo,Conectar Por Equivalente Antes de MySQL

que tiene tres campos de una tabla que define una relación padre-hijo presente en una versión de base de datos MySQL 5.0. El nombre de la tabla es tb_Tree y tiene los siguientes datos:

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 

¿Cómo se escribe una consulta para obtener todos los niños si se especifica un parentid. Tenga en cuenta que las entradas de tabla dadas son solo datos de muestra y pueden tener muchas más filas. Oracle tiene una cláusula "CONNECT BY PRIOR", pero no encontré nada similar para MySQL. ¿Alguien puede por favor asesorar?

Gracias

+0

creo "CON" le puede ayudar con consultas recursivas. – FUD

+0

¿puedes por favor elaborar? Gracias – Jake

+1

MySQL no tiene CTE ('CON') –

Respuesta

10

MySQL no soporta consultas recursivas por lo que tiene que hacerlo de la manera difícil:

  1. seleccionar las filas donde ParentID = X donde X es su raíz.
  2. Recoge los valores Id de (1).
  3. Repita (1) para cada Id de (2).
  4. Mantenga la recurrencia a mano hasta que encuentre todos los nodos de hoja.

Si conoce una profundidad máxima, puede unir su mesa a sí mismo (utilizando UNIONES EXTERNAS IZQUIERDAS) a la profundidad máxima posible y luego limpiar los valores NULL.

También podría cambiar su representación de árbol a nested sets.

1

Se trata de un viejo hilo, pero desde que llegué a la pregunta en otro foro que pensé lo agregaré aquí. Para este caso, creé un procedimiento almacenado que está codificado para manejar el caso específico. Esto tiene, por supuesto, algunos inconvenientes, ya que no todos los usuarios pueden crear procedimientos almacenados a voluntad, pero sin embargo.

Considérese la siguiente tabla con nodos y niños:

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 esta tabla, el procedimiento almacenado siguiente será calcular un conjunto de resultados que consiste en todos los descendientes del nodo prestados:

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

El siguiente select enumera todas las plantas y sus parentid hasta 4 niveles (y, por supuesto, puede ampliar el nivel):

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 

y luego puede usar esta consulta para obtener el resultado final. por ejemplo, se pueden obtener todos los niños de "Frutas" por el sql a continuación:

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

El orden siguiente procedimiento almacenado una tabla que tiene filas con referencia de nuevo a la anterior. Observe que en el primer paso copie las filas en la tabla temporal, esas filas coinciden con alguna condición. En mi caso, esas son filas que pertenecen al mismo lineal (carretera que se utiliza en la navegación GPS).El dominio comercial no es importante. Solo en mi caso estoy clasificando segmentos que pertenecen a la misma carretera

PROCEDIMIENTO DE CAÍDA SI EXISTE orderLocations; DELIMITER //

CREATE orderLocations PROCEDIMIENTO (_full_linear_code VARCHAR (11)) frases 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; 
Cuestiones relacionadas