2012-06-20 3 views
2

Я создаю меню навигации из списка страниц. таблица выглядит так:MySql sql recursive loop

Table name: pages 

id | type | parent | name 
------------------------------- 
1, 1,  null, root1 
2, 1,  null, root2 
3, 2,  2,  home 
4, 2,  3,  child 
5, 2,  4,  sub_child 
6, 3,  5,  sub_sub_child 


type: 
1 = root page/site 
2 = page 
3 = ... 

Моя проблема заключается в том, что с любой страницы, я должен найти корневую страницу. У меня есть столбец parent, который ссылается на родительскую страницу, за исключением корневых страниц.

Я могу иметь несколько корневых страниц в таблице, но каждая страница имеет только один родитель.

Может ли кто-нибудь помочь мне написать рекурсивный запрос?

Я пытаюсь использовать этот запрос, но он не работает:

with recursive pages (id, parent) as 
(
    select pages.id, 
    pages.parent, 
    from pages 
    where pages.id = 4 

union all 
    select pages.id, 
    pages.parent, 
    from pages 
    inner join pages p on p.id = pages.parent 
) 
select id 
from pages; 

Благодаря

+2

1. Отправьте запрос по этому вопросу. 2. Какую базу данных вы используете? – npe

+0

Я использую MySql 5.5.8 – blaazzze

+1

AFAIK mysql не поддерживает ничего подобного. – Matzi

ответ

1

Мой фаворитовый трюк для обработки структурированных данных дерева в базе данных добавляет столбец FullID в таблицу, чтобы избежать сложных (редуцирующих) SQL-запросов/хранимых процедур.

FullID  id parent name 
----------------------------- 
1   1 null  root1 
2   2 null  root2 
2.3  3 2  home 
2.3.4  4 3  child 
2.3.4.5 5 4  sub_child 
2.3.4.5.6 6 5  sub_sub_child 

Таким образом, чтобы найти корень идентификатор страницы, просто извлечь первую часть FullID через SQL или ваш язык приложения.

При использовании SQL вы можете использовать следующий SQL для получения идентификатора корня.

-- MySQL dialect 
select substring_index(FullID,'.',1) as RootID from table; 

-- SQL Server dialect 
select case charindex('.', FullID) when 0 then FullID else substring(FullID, 1, charindex('.', FullID)-1) end as RootID from table 

Чтобы удалить узел и дети

DELETE table WHERE id=<CURRENT_NODE_ID> OR FullID LIKE '<CURREN_NODE_FULLID>.%' 

Чтобы переместить узел и дети

-- change the parent of current node: 
UPDATE table 
SET parent=<NEW_PARENT_ID> 
WHERE id=<CURRENT_NODE_ID> 

-- update it's FullID and all children's FullID: 
UPDATE table 
SET FullID=REPLACE(FullID,<CURRENT_NODE_PARENT_FULLID>, <NEW_PARENT_FULLID>) 
WHERE (id=<CURRENT_NODE_ID> OR FullID LIKE '<CURRENT_NODE_FULLID>.%') 

Обратите внимание

Этот трюк применяется только к ограниченным случаям уровня дерева, или FullID не может содержать длинный контент, если уровень дерева слишком глубокий.

+0

другой трюк, но звук большой. Это будет проще, чем простое решение «с использованием php». Есть одна вещь, которая мне не нравится ... Когда я перехожу на страницу, мне придется менять всех детей и подчинов. И в это время мне придется использовать рекурсивный запрос. Поэтому мы возвращаемся к началу проблемы. В любом случае, спасибо :-) – blaazzze

+0

Чтобы изменить родительский элемент узла, вы также можете использовать два простых SQL, 1. изменить «parent» текущего узла: 'UPDATE table SET parent = WHERE id = ' , 2. обновите его «FullID» и «полный идентификатор» всех детей: 'UPDATE table SET FullID = REPLACE (FullID, , ) ​​WHERE (FullID LIKE '.%' ИЛИ ​​id = ) ' –

+0

Да, спасибо. Я не знал функцию 'replace'. При этом это будет очень просто. Спасибо вам ! – blaazzze

0

WITH RECURSIVE положение, которое вы используете применяется для баз данных PostgreSQL, а не для MySQL. У Oracle есть CONNECT BY ... START WITH ..., и кажется, что рекурсивные запросы выполняются по-разному в каждой базе данных.

Однако MySQL не поддерживает рекурсивные/иерархические запросы. Вам необходимо пройти через строки, чтобы найти родителей до корня.

См. how hierarchical queries (like Oracle's CONNECT BY) can be emulated in MySQL.

+0

спасибо за ответ, который объясняет, почему он не работает. И спасибо за ссылку, но я понятия не имею, что я читаю ... – blaazzze

+0

Ну, вы можете сделать это с помощью Java/PHP/Какой бы язык вы ни использовали, выбрав «parent id» и применяя его как ' id' в следующей итерации цикла, пока вы не получите 'parent id = null', что означает, что вы указали' id' на элемент _root_. Довольно неэффективно, но работает. Или, попробуйте понять, что вы читаете ;-) – npe

+0

Да, я могу использовать php, это будет легко, но я стараюсь красивого кода. Поэтому я пытаюсь использовать «START WITH». Я не часто использую SQL, поэтому немного понять, что он сказал, и потому, что английский не мой естественный язык. Но я пытаюсь ;-) – blaazzze

1

Как прокомментировали другие плакаты, в MySQL, похоже, не поддерживается. Вы можете реструктурировать свою таблицу, используя nested set model, чтобы избавиться от необходимости в иерархических запросах.

Пример

Вместо parent колонки, у вас есть leftid, rightid и is_root.

id | type | leftid | rightid | is_root | name 
------------------------------------------------ 
1, 1,  1,  2   1   root1 
2, 1,  3,  12  1   root2 
3, 2,  4,  11  0   home 
4, 2,  5,  10  0   child 
5, 2,  6,  9   0   sub_child 
6, 3,  7,  8   0   sub_sub_child 

Тогда, чтобы найти родителей той или иной записи, вы просто найти записи с leftid меньше и rightid больше, чем эту запись. Используйте столбец is_root, чтобы получить окончательную запись корня.

0

Я думаю, что добавлю некоторые изменения в мою базу данных. После разговора я могу удалить столбец типа и добавить таблицу в класс для разных страниц. Таким образом, структура изменена. Я думаю, что я буду использовать петлю php. Это не красиво, но это работает, и это не слишком медленно ... никогда не будет 200 детей под другим ... Но я помню START WITH.

Благодарю вас, ребята