SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 07.07.2011 22:53:11

Mikel
Участник
Зарегистрирован: 07.07.2011
Сообщений: 4

Запрос 3 уровней дерева

Хотелось бы извлечь 3 уровня дерева хранящегося в таблице одним запросом в формате (данные n уровня, данные n+1 уровня, данные n+2 уровня в одной строке, т.е. 3 записи в строке), или хотя бы просто по одной записи в строчке.

Структура таблицы:
id:int;
p_id:int (id родителя);
name: varchar;

LEFT JOIN вроде как не подходит, поскольку может быть например только два уровня, соответственно в 3 уровне будет null и ничего не вернется. Если объединять через UNION ALL чтобы в одной строке был только один уровень, то выходит несколько одинаковых запросов. Т.е. сначала делаем SELECT по первому уровню, потом UNION ALL и SELECT второго уровня, а условие для p_id- снова перебор первого уровня... В общем совсем запутался smile

Неактивен

 

#2 08.07.2011 01:16:29

pixmaster
Участник
Зарегистрирован: 08.07.2011
Сообщений: 5

Re: Запрос 3 уровней дерева

Мне кажется, что для такой структуры таблицы можно сортировать только по корневая (пид=0 или =нул) или дочерняя запись.
А разворачивать в древовидную структуру уже в приложении.

Неактивен

 

#3 08.07.2011 08:49:16

Mikel
Участник
Зарегистрирован: 07.07.2011
Сообщений: 4

Re: Запрос 3 уровней дерева

Ок, но тогда все равно хотелось бы получить список всех нодов одним запросом. У меня пока один вариант для этого не оптимальный-
(SELECT * FROM tree WHERE p_id=%n)
UNION
(SELECT * FROM tree WHERE p_id in (SELECT `id` FROM tree WHERE p_id=%n) )

А третий уровень соотв. еще больше вложенных запросов.

Отредактированно Mikel (08.07.2011 08:49:47)

Неактивен

 

#4 09.07.2011 22:56:28

vladislav
Участник
Зарегистрирован: 26.10.2010
Сообщений: 17

Re: Запрос 3 уровней дерева

можно попробовать так:

$res = mysql_query("SELECT * FROM tree");
$data = array();
if (mysql_num_rows($res) > 0)
{
  while ($row = mysql_fetch_assoc($res))
  {
    $data[$row['parent_id']][] = $row;
  }
}

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

пример для первого уровня.
foreach ($data[0] as $item)
{
  echo $item['name'];
}

вместо нуля подставляем нужный id категории и выводим ее подкатегории.

так будет намного быстрее, чем большое кол-во запросов. (надеюсь что категорий не миллион)

З.Ы. У меня первый уровень (parent_id) всегда равен нулю. Если у вас NULL то тогда можно использовать null.

Неактивен

 

#5 10.07.2011 12:33:59

Mikel
Участник
Зарегистрирован: 07.07.2011
Сообщений: 4

Re: Запрос 3 уровней дерева

Возможно Вы правы. Если в дереве будет записей порядка сотни, обрабатывать потом уже в php. Пока остановлюсь на этом варианте. Спасибо! smile

Неактивен

 

#6 10.07.2011 15:52:53

evgeny
Гуру
Зарегистрирован: 04.05.2009
Сообщений: 335

Re: Запрос 3 уровней дерева

Если я правельно понял то вам нужно это:

SELECT
id 'id_level_1',
pid 'id_level_2',
(SELECT pid FROM trees WHERE id=a.pid) AS 'id_level_3'
FROM trees a

Неактивен

 

#7 25.07.2011 20:55:09

Mikel
Участник
Зарегистрирован: 07.07.2011
Сообщений: 4

Re: Запрос 3 уровней дерева

evgeny написал:

Если я правельно понял то вам нужно это:

SELECT
id 'id_level_1',
pid 'id_level_2',
(SELECT pid FROM trees WHERE id=a.pid) AS 'id_level_3'
FROM trees a

Не совсем то. Это только два уровня и надо вытаскивать еще другие данные узла помимо его идента, а в этой структуре можно добавить в результат только один столбец из внутреннего селекта.

Неактивен

 

#8 26.07.2011 11:14:08

evgeny
Гуру
Зарегистрирован: 04.05.2009
Сообщений: 335

Re: Запрос 3 уровней дерева

Не совсем то. Это только два уровня

Вот 3, аналогично можно сделать и 4 и 5 и 6.


SELECT
b.*,
(SELECT pid FROM trees WHERE id=b.id_level_3) AS 'id_level_4'
FROM (
    SELECT
    id 'id_level_1',
    pid 'id_level_2',
    (SELECT pid FROM trees WHERE id=a.pid) AS 'id_level_3'
    FROM trees a
) b



надо вытаскивать еще другие данные узла помимо его идента

SELECT
b.*,
(SELECT pid FROM trees WHERE id=b.id_level_3) AS 'id_level_4'
FROM (
    SELECT
    id 'id_level_1',
    pid 'id_level_2',
    (SELECT pid FROM trees WHERE id=a.pid) AS 'id_level_3'
    FROM trees a
) b
LEFT JOIN tree_data t1 ON(b.id_level_1=t1.id)
LEFT JOIN tree_data t2 ON(b.id_level_2=t2.id)
...
 

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson