it-swarm.com.ru

Подключите по предшествующему эквиваленту для MySQL

Все,

У меня есть три поля в таблице, которые определяют родительские дочерние отношения, присутствующие в базе данных MySQL версии 5.0. Имя таблицы - tb_Tree и содержит следующие данные:

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

Как мне написать Query, чтобы получить все дочерние элементы, если указан ParentId. Обратите внимание, что приведенные записи таблицы являются просто примерами данных, и они могут иметь гораздо больше строк. У Oracle есть предложение «CONNECT BY PRIOR», но я не нашел ничего похожего для MySQL. Может кто-нибудь, пожалуйста, посоветуйте?

Спасибо

18
Jake

MySQL не поддерживает рекурсивные запросы, поэтому вы должны сделать это сложным путем:

  1. Выберите строки, где ParentID = X, где X - ваш корень.
  2. Соберите значения Id из (1).
  3. Повторите (1) для каждой Id из (2).
  4. Продолжайте повторять вручную, пока не найдете все листовые узлы.

Если вы знаете максимальную глубину, вы можете соединить вашу таблицу с самим собой (используя LEFT OUTER JOINs) на максимально возможную глубину, а затем очистить NULL.

Вы также можете изменить свое древовидное представление на вложенные множества .

10
mu is too short

Вы также можете заглянуть в этот интересный блог, который демонстрирует, как мы можем получить аналогичные результаты в MySQL

http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/

2
Yashpal Singla

Это старая ветка, но так как я получил вопрос на другом форуме, я решил добавить его сюда. Для этого случая я создал хранимую процедуру, которая жестко запрограммирована для обработки конкретного случая. Это, конечно, имеет некоторые недостатки, поскольку не все пользователи могут создавать хранимые процедуры по желанию, но тем не менее.

Рассмотрим следующую таблицу с узлами и дочерними элементами:

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);

С этой таблицей следующая хранимая процедура будет вычислять результирующий набор, состоящий из всех потомков предоставленного узла:

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 ;
2
Mats Kindahl

Ниже select перечислены все растения и их parentid до 4-х уровней (и, конечно, вы можете расширить уровень): 

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

и затем вы можете использовать этот запрос, чтобы получить окончательный результат. например, вы можете получить всех потомков "Fruits" по приведенному ниже sql:

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
1
user5132533

Приведенная ниже хранимая процедура упорядочивает таблицу, в которой есть строки с обратной ссылкой на предыдущую. Обратите внимание, что на первом шаге я копирую строки во временную таблицу - эти строки соответствуют некоторому условию. В моем случае это строки, которые принадлежат одной и той же линейной линии (дорога, которая используется в GPS-навигации). Бизнес домен не важен. Просто в моем случае я сортирую сегменты, которые принадлежат одной и той же дороге

ПРОЦЕДУРА ОТМЕНЫ, ЕСЛИ СУЩЕСТВУЕТ orderLocations; РАЗДЕЛИТЕЛЬ //

СОЗДАТЬ ПРОЦЕДУРУ orderLocations (_full_linear_code VARCHAR (11)) НАЧАТЬ

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;
0
Stan Sokolov