2016-04-22 4 views
1

У меня есть дерево категорий, которое структурировано двумя способами: каждая категория имеет путь и родительский идентификатор. Путь осуществляется из идентификаторов (вверху) категорий. Исходный идентификатор ссылается на другую категорию. Поэтому мой стол выглядит так:Структура дерева обратная (MySQL)

id | name  | path | parentID 
---+-------------+---------+--------- 
1 | Root  | NULL | NULL 
2 | Main  | NULL | 1 
3 | Electronics | |2|  | 2 
4 | Computers | |3|2| | 3 
5 | PCs   | |4|3|2| | 4 
6 | Macs  | |4|3|2| | 4 
7 | Cameras  | |3|2| | 3 
8 | Canon  | |7|3|2| | 7 

Теперь мне не нужны категории «Корень» и «Главная». То, что я пытаюсь достичь, это выход, как это:

id | resolved_path 
---+----------------------------- 
3 | Electronics 
4 | Electronics_Computers 
5 | Electronics_Computers_PCs 
6 | Electronics_Computers_Macs 
7 | Electronics_Cameras 
8 | Electronics_Cameras_Canon 

Так что я изменяющаяся глубина и мне нужна категории, чтобы быть в обратном порядке. Я не очень много об этом узнал в Интернете. Все, что я получил это фрагмент, который показывает глубину категории:

SELECT 
*, 
(ROUND(
    (LENGTH(cat.path) - LENGTH(REPLACE(cat.path, '|', '')))/LENGTH('|') 
) - 2) depth 
FROM 
    categories cat 
WHERE 
    cat.path IS NOT NULL 

Я не знаю, что легче: проходя через parentIDs рекурсивно или делать некоторые магии на пути.

+1

вы могли бы адаптировать этот ответ работать в обратном порядке: http://stackoverflow.com/a/5928675/1503505 – Preuk

+0

@Preuk Моя проблема заключается в том, что я имею различную глубину. Поэтому мне понадобится какой-то цикл, чтобы сделать это с помощью этого решения. Есть ли способ сделать это? – jkrzefski

+1

Почему вы не создаете промежуточную таблицу (categories_parents), которую вы можете использовать для поиска родительских категорий ?. Это быстрее. –

ответ

0

Вы можете использовать эту функцию (не оптимизированное) в качестве основы:

DELIMITER // 
DROP FUNCTION IF EXISTS extract_path // 
CREATE FUNCTION extract_path(idlist VARCHAR(255)) 
RETURNS LONGTEXT 
BEGIN 
    DECLARE result LONGTEXT; 
    DECLARE tmplist VARCHAR(255); 
    DECLARE buffer VARCHAR(255); 
    DECLARE lastpos INT; 

    -- reverse and trim last separator (that first of reversed string) 
    SELECT TRIM(BOTH FROM SUBSTRING(REVERSE(idlist), 2)) INTO tmplist; 

    mainloop: LOOP 
     -- split on separator 
     SELECT LOCATE('|', tmplist) INTO lastpos; 
     -- detect end 
     IF lastpos IS NULL OR lastpos < 2 
     THEN LEAVE mainloop; 
     END IF; 

     -- resolve next id 
     SELECT cat.name INTO buffer 
     FROM categories cat 
     WHERE cat.id = TRIM(REVERSE(SUBSTRING(tmplist, 1, lastpos - 1))); 

     -- append new element 
     SELECT CONCAT(COALESCE(CONCAT(result, '_'), ''), buffer) INTO result; 

     -- prepare for next iteration 
     SELECT TRIM(BOTH FROM SUBSTRING(tmplist, lastpos + 1)) INTO tmplist; 

     -- detect end (corner case) 
     IF tmplist IS NULL 
     THEN LEAVE mainloop; 
     END IF; 

    END LOOP; 

    RETURN result; 
END // 

SELECT extract_path('|1|2|3|'); 
-- with categories 1 -> foo ; 2 -> bar ; 3 -> baz 
-- output is 'baz_bar_foo' 
DELIMITER ; 
+0

@jkrzefski не проблема, просто спросите, нужны ли вам разъяснения. Во всяком случае, я предлагаю вам подумать о том, чтобы зафиксировать вашу модель, как прокомментировал Хуан Лаго. Вы можете извлекать элементы из моей функции для создания промежуточной таблицы. – Preuk

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