2015-01-21 5 views
0

Итак, давайте предположим, что У меня есть БД MySQL со следующими таблицами:MySQL: Категория Дерево и продукты в п уровней

продукта

  • идентификатор
  • имя
  • category_id

Категория

  • идентификатор
  • имя
  • parent_id

Какой самый лучший способ для запроса DB для того, чтобы получить все продукты, идущие вниз от определенной категории ид. Например, если у меня есть дерево подкатегорий, где базовая категория id = 1, как я могу получить все продукты под подкатегориями id = 1 для неопределенного количества подкатегорий.

Я мог бы сделать это:

SELECT * FROM `Product` WHERE category_id IN (
    SELECT `id` FROM `Category` WHERE parent_id = 1 
) 

Однако это работает только для прямых детей категории ид = 1 и не для 2 детей п уровня.

спасибо.


Редактировать

Некоторые люди предложили прочитать a blog article об этом, у меня было посмотреть на эту статью о прошлом также, и я сделал это sqlfiddle:

http://sqlfiddle.com/#!2/be72ec/1

Как вы можете видеть по запросу, даже самый простой способ, которым они учат, получить дерево категорий, ничего не выводит. Что мне не хватает? Другие методы имеют одинаковую проблему.

спасибо.

+1

Посмотрите на эту статью «Иерархические данные в MySQL: родители и дети в одном запросе»: HTTP: // explainextended .com/2009/07/20/hierarchical-data-in-mysql-parents-and-children-in-one-query /. Я думаю, это могло бы ответить на ваш вопрос. – stefan

+0

@stefan Я пробовал эти сообщения в прошлом, но по какой-то причине они не возвращают никаких данных ... И в комментариях есть еще кто-то, говорящий, что у него такая же проблема. – TCB13

+0

@stefan, пожалуйста, проверьте мои изменения ... – TCB13

ответ

1

Я посмотрел на ваш sqlfiddle и пришел к следующему выводу.

Проблема с вашим кодом заключается в том, что вы используете значения NULL. Посмотрите на этот sqlfiddle, чтобы увидеть рабочий пример: http://sqlfiddle.com/#!2/07ef7/1/0

Я сделал некоторые исправления в ваших заявлениях, и теперь все работает.
Вот список с изменениями я сделал:

  • Изменить "parent_id BIGINT (11) без знака DEFAULT NULL," к "parent_id BIGINT (11) без знака NOT NULL DEFAULT 0," в создании заявления
  • Удалите ограничение внешнего ключа, но я не получил его работы с «0», как parent_id
  • Вставить «0» вместо «NULL» как parent_id
  • Изменить тип данных INT в BigInt внутри функции, потому что вы используют этот тип в вашем заявлении о создании
  • Извлечь предложение WHERE из выписки

Я надеюсь, что это поможет!

Вот заявления, только в случае, если sqlfiddle не работает прямо сейчас:

CREATE TABLE `Category` (
    `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(100) DEFAULT NULL, 
    `parent_id` bigint(11) unsigned NOT NULL DEFAULT 0, 
    PRIMARY KEY (`id`), 
    KEY `parent_id` (`parent_id`), 
    KEY `ix_hierarchy_parent` (`parent_id`, `id`) 
)// 


INSERT INTO `Category` (`id`, `name`, `parent_id`) 
VALUES 
    (1,'Cat Name 1',0), 
    (2,'Cat Name 2',0), 
    (3,'Cat Name 3',2), 
    (4,'Cat Name 4',2), 
    (7,'Cat Name 5',4), 
    (8,'Cat Name 6',4), 
    (9,'Cat Name 7',4), 
    (10,'Cat Name 8',4), 
    (11,'Cat Name 9',4), 
    (12,'Cat Name 10',4), 
    (13,'Cat Name 11',2), 
    (16,'Cat Name 12',13), 
    (17,'Cat Name 13',13), 
    (18,'Cat Name 14',13), 
    (19,'Cat Name 15',13), 
    (20,'Cat Name 16',13), 
    (21,'Cat Name 17',13)// 


CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value BIGINT) RETURNS INT 
NOT DETERMINISTIC 
READS SQL DATA 
BEGIN 
     DECLARE _id BIGINT; 
     DECLARE _parent_id BIGINT; 
     DECLARE _next BIGINT; 
     DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL; 

     SET _parent_id = @id; 
     SET _id = -1; 

     IF @id IS NULL THEN 
       RETURN NULL; 
     END IF; 

     LOOP 
       SELECT MIN(id) 
       INTO @id 
       FROM `Category` 
       WHERE parent_id = _parent_id 
         AND id > _id; 
       IF @id IS NOT NULL OR _parent_id = @start_with THEN 
         SET @level = @level + 1; 
         RETURN @id; 
       END IF; 
       SET @level := @level - 1; 
       SELECT id, parent_id 
       INTO _id, _parent_id 
       FROM `Category` 
       WHERE id = _parent_id; 
     END LOOP;  
END// 

SELECT CONCAT(REPEAT(' ', level - 1), CAST(hi.id AS CHAR)) AS treeitem, hi.name, parent_id, 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, `Category` 
     WHERE @id IS NOT NULL 
     ) ho 
JOIN `Category` hi 
ON  hi.id = ho.id 
+1

Это действительно работает, однако вещь с значениями «null» была всего лишь способом ограничения fk для базовых категорий. Если я устанавливаю 'parent_id' по умолчанию' 0', это не будет работать из-за fk. – TCB13

Смежные вопросы