Я работаю с mySQL, и я в ситуации, когда мне нужно выбрать данные из одной таблицы, которая соответствует идентификатору на любом уровне в родительской -> иерархии дочерних данных в другой таблице.
Более того, я хотел бы разрешить это с хорошо написанным SQL-запросом, а не с рекурсивной функцией в моем PHP-коде, так как эта функция будет использоваться совсем немного.
Я попытался выполнить поиск, и я наткнулся на множество подобных проблем (большинство из них были разрешены), однако никто из них не помог мне.
Чтобы проиллюстрировать ситуацию, вот моя текущая настройка
таблицы "статьи":
таблицы категорий
Мне нужно выбрать все статьи из «статей», где «articles.category_id» – это, скажем, 10. Но также получать все статьи из всех категорий из дерева, к которому принадлежит категория «categories.category_id» 10.
Значение, где «10» – родитель и все его дети, и вверх, где 10 – ребенок и все его родители.
Возможно без рекурсивной функции php?
Спасибо.
Это можно сделать в MySQL
, но это требует немного усилий. Вам нужно написать такую функцию:
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 categories 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 categories WHERE id = _parent; END LOOP; END
и использовать его в запросе:
SELECT id, parent, level 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, categories WHERE @id IS NOT NULL ) ho JOIN categories hi ON hi.id = ho.id
Просмотрите эту запись в своем блоге для получения более подробной информации:
Невозможно получить целое дерево в одном запросе с использованием используемого вами проекта списка Adjacency List, учитывая, что вы используете MySQL.
Некоторые другие базы данных поддерживают SQL-расширения для обработки такого дизайна. Oracle, Microsoft SQL Server, IBM DB2 и PostgreSQL 8.4 (в настоящее время в бета-версии) поддерживают расширения SQL.
Существуют другие структуры баз данных, которые позволяют более эффективно запрашивать деревья. Этот вопрос неоднократно рассматривался в StackOverflow, в блогах и в статьях.
Вы также можете прочитать « Деревья и иерархии в SQL для Smarties » Джо Селко, который углубляется в несколько таких проектов.
Наиболее распространенные шаблоны для хранения иерархических данных в реляционной базе данных – это либо смежный список, либо измененный предварительный заказ (ака вложенный набор) . Альтернативой является использование материализованного пути, который в основном является механизмом кэширования, сидящим поверх смежного списка. См. Также эту таблицу для сравнения плюсов и минусов .
Я не знаю, насколько это вам поможет, но я написал небольшую функцию, которая генерирует иерархическое дерево, используя один запрос MySQL. В принципе, вся важная логика перемещается в PHP. Мое решение использует модель списка смежности, а затем использует ссылки PHP для построения структуры древовидных данных с помощью плоской. Взгляните на суть внизу и посмотрите, есть ли у вас вдохновение. Я бы помог вам больше, но есть некоторые проблемы, с которыми мне приходится иметь дело на своей работе.