Подтвердить что ты не робот

Подключить по предшествующему эквиваленту для 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

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

Спасибо

4b9b3361

Ответ 1

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

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

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

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

Ответ 3

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

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

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

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

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 ;

Ответ 4

Ниже 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

а затем вы можете использовать этот запрос для получения окончательного результата. например, вы можете получить всех детей из "Фруктов" по ​​нижнему 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

Ответ 5

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

ПРОЦЕДУРА РАЗРЕШЕНИЯ, ЕСЛИ СУЩЕСТВУЕТСЯ orderLocations; DELIMITER//

CREATE PROCEDURE 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;

Ответ 6

Может быть, поздно сообщение.

С MySQL8 вы можете достичь этого с помощью рекурсивного предложения. Вот пример.

 with recursive cte (id, name, parent_id) as (
  select     id,
             name,
             parent_id
  from       products
  where      parent_id = 19
  union all
  select     p.id,
             p.name,
             p.parent_id
  from       products p
  inner join cte
          on p.parent_id = cte.id
)
select * from cte;

Для получения дополнительной помощи найти другую ветку, надеюсь, это поможет кому-то.