Как проще всего получить всех родителей записи, используя модель id / parent_id в mysql / php?
Я ищу простейший способ рекурсивного получения всех родительских элементов из базы данных с использованием модели наследования смежности/одиночной таблицы ( id, parent_id ). Мой выбор в настоящее время выглядит следующим образом:
$sql = "SELECT e.id, TIME_FORMAT(e.start_time, '%H:%i') AS start_time, $title AS title, $description AS description, $type AS type, $place_name AS place_name, p.parent_id AS place_parent_id, p.city AS place_city, p.country AS place_country FROM event AS e LEFT JOIN place AS p ON p.id = e.place_id LEFT JOIN event_type AS et ON et.id = e.event_type_id WHERE e.day_id = '$day_id' AND e.private_flag = 0 ORDER BY start_time";
Каждый event связан с place , и каждый place может быть дочерним по отношению к другому place (примерно до 5 уровней) Возможно ли это в одном select с mysql? В настоящий момент я думаю, что это может быть отдельная функция, которая проходит через возвращаемый массив $events , добавляя элементы place_parent_X , как он есть, но я не уверен, как это реализовать.
3 ответа
CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value INT) RETURNS INT NOT DETERMINISTIC READS SQL DATA BEGIN DECLARE _id INT; DECLARE _parent INT; DECLARE _next INT; DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL; SET _parent = @id; SET _id = -1; IF @id IS NULL THEN RETURN NULL; END IF; LOOP SELECT MIN(id) INTO @id FROM place WHERE parent = _parent AND id > _id; IF @id IS NOT NULL OR _parent = @start_with THEN SET @level = @level + 1; RETURN @id; END IF; SET @level := @level - 1; SELECT id, parent INTO _id, _parent FROM place WHERE END LOOP; END SELECT id, parent FROM ( SELECT hierarchy_connect_by_parent_eq_prior_id(id) AS id, @level AS level FROM ( SELECT @start_with := 0, @id := @start_with, @level := 0 ) vars, t_hierarchy WHERE @id IS NOT NULL ) ho JOIN place hi ON hi.id = ho.id
В последнем запросе будут выбраны все потомки заданного node (который вы должны установить в переменной @start_with )
Чтобы найти всех предков данного node, вы можете использовать простой запрос без функций:
SELECT @r AS _id, @r := ( SELECT parent FROM place WHERE ) AS parent FROM ( SELECT @r := @node_id ) vars, place
Эта статья в моем блоге описала этот запрос более подробно:
Чтобы оба этих решения работали в разумные сроки, вам нужно иметь индексы как для id , так и parent .
Убедитесь, что ваш id определяется как PRIMARY KEY , и у вас есть второй индекс на parent .
MySQL SELECT Tree Parent IDs
Как я могу сортировать записи инструкции SELECT, чтобы они представляли действительное дерево?
Все мои попытки показывают под-узлы, вложенные под неправильные родительские узлы. Какой самый надежный способ добиться этого заказа?
ID Parent ID Title -------------------------------------------- 0 NULL Root 1 0 Node A 2 0 Node B 3 1 Sub-Node C 4 1 Sub-Node D 5 3 Sub-Node E
ID Parent ID Title -------------------------------------------- 0 NULL Root 1 0 Node A 3 1 Sub-Node C 5 3 Sub-Node E 4 1 Sub-Node D 2 0 Node B
Визуализация данных
Root Node A Sub-Node C Sub-Node E Sub-Node D Node B
Solutions Collecting From Web of «MySQL SELECT Tree Parent IDs»
Вы можете использовать вложенные наборы. Ознакомьтесь с этой статьей:
Управление иерархическими данными в MySQL
Автор описывает несколько разных методов построения иерархии в SQL, в комплекте с примерами запросов. Это очень хорошо читать об этом предмете!
Следуя совету @Blindy, я реализовал этот вид с PHP. Вот две функции, которые, похоже, довольно легко решают эту проблему.
protected function _sort_helper(&$input, &$output, $parent_id) < foreach ($input as $key =>$item) if ($item->parent_id == $parent_id) < $output[] = $item; unset($input[$key]); // Sort nested!! $this->_sort_helper(&$input, &$output, $item->id); > > protected function sort_items_into_tree($items) < $tree = array(); $this->_sort_helper(&$items, &$tree, null); return $tree; >
сprotected function _sort_helper(&$input, &$output, $parent_id) < foreach ($input as $key =>$item) if ($item->parent_id == $parent_id) < $output[] = $item; unset($input[$key]); // Sort nested!! $this->_sort_helper(&$input, &$output, $item->id); > > protected function sort_items_into_tree($items) < $tree = array(); $this->_sort_helper(&$items, &$tree, null); return $tree; >
Мне было бы интересно услышать, есть ли более простой подход, но, похоже, это работает.
MySQL не поддерживает рекурсивные запросы
Вам нужно будет присоединяться к таблице столько раз, сколько максимальный уровень иерархии, но все же довольно уродливо получить одну строку для каждого уровня иерархии таким образом.
См. Эти сообщения для некоторых идей и примеров:
Иерархия категорий (PHP / MySQL)
как мы можем написать mysql-запрос, где у родительского идентификатора есть дочерний идентификатор, а в следующий раз дочерний id – родительский идентификатор, как я могу это сделать?
Я только что закончил эту рекурсивную функцию и подумал, что это изящный способ решить эту проблему. Вот что я сделал, как только я сделал базовый запрос SELECT mysql:
function orderChildren($data)< $tree = array(); foreach($data as $value)< if($value['parent_id'] == null)< // Values without parents $tree[$value['id']] = $this->goodParenting($value, $data); > > return $tree; > private function goodParenting($parent, $childPool)< foreach($childPool as $child)< if($parent['id'] == $child['parent_id'])< $parent['children'][$child['id']] = $this->goodParenting($child, $childPool); > > return $parent; >
Вот еще один способ сделать вашу функцию PHP.
function buildTree() < $data = array(); $pointers = array(); $sql = "SELECT ID,PARENT,TITLE FROM TREE ORDER BY TITLE ASC"; $res = $this->db->query($sql); while ($row = $res->fetch(PDO::FETCH_ASSOC)) < if(!isset($pointers[$row['ID']])) < $pointers[$row['ID']] = $row; >if(!empty($row['PARENT'])) < if(!isset($pointers[$row['PARENT']])) < $pointers[$row['PARENT']] = $row; >$pointers[$row['PARENT']][$row['ID']] = &$pointers[$row['ID']]; > else < $data[$row['ID']] = &$pointers[$row['ID']]; // This is our top level >> unset($pointers); return $data; >
этотfunction buildTree() < $data = array(); $pointers = array(); $sql = "SELECT ID,PARENT,TITLE FROM TREE ORDER BY TITLE ASC"; $res = $this->db->query($sql); while ($row = $res->fetch(PDO::FETCH_ASSOC)) < if(!isset($pointers[$row['ID']])) < $pointers[$row['ID']] = $row; >if(!empty($row['PARENT'])) < if(!isset($pointers[$row['PARENT']])) < $pointers[$row['PARENT']] = $row; >$pointers[$row['PARENT']][$row['ID']] = &$pointers[$row['ID']]; > else < $data[$row['ID']] = &$pointers[$row['ID']]; // This is our top level >> unset($pointers); return $data; >
неfunction buildTree() < $data = array(); $pointers = array(); $sql = "SELECT ID,PARENT,TITLE FROM TREE ORDER BY TITLE ASC"; $res = $this->db->query($sql); while ($row = $res->fetch(PDO::FETCH_ASSOC)) < if(!isset($pointers[$row['ID']])) < $pointers[$row['ID']] = $row; >if(!empty($row['PARENT'])) < if(!isset($pointers[$row['PARENT']])) < $pointers[$row['PARENT']] = $row; >$pointers[$row['PARENT']][$row['ID']] = &$pointers[$row['ID']]; > else < $data[$row['ID']] = &$pointers[$row['ID']]; // This is our top level >> unset($pointers); return $data; >
- Ошибка модуля входа: свойство «LoginForm._id» не определено
- Разрешения файла и CHMOD: Как установить 777 в PHP при создании файла?
- Как сделать NAT с сокетами PHP
- как вызвать ajax на интерфейсе wordpress
- установить кодировку при сохранении файлов с помощью php
- Использование нескольких модулей в одном представлении
- Как я могу использовать буферизацию var_dump + output без ошибок памяти?
- Как установить расширение mbstring
- Нужна помощь в вычислении MySQL-запроса для подсчета, если определенное число
- Как изменить формат по умолчанию на created_at и update_at значение laravel
- PHP Strtotime -1month -2month
- Обновление JQuery Progressbar с ответом JSON в запросе ajax
- как вставлять видео в код laravel
- Yii: Как управлять видео при использовании расширения multuploadfiles
- не удалось открыть поток: не найдено подходящей обертки