Запрос в древовидной структуре

DeltaDIM

Новичок
Запрос в древовидной структуре

Доброго времени суток!
Имеется простое дерево представленное в виде id, имени, и идентификатора родтеля:
id---name---parent_id
1---n1---0
2---n1.1---1
3---n1.2---1
4---n1.2.1---3
5---n1.3---1
6---n2---0
7---n3---0
8---n3.1---7
9---n3.1.1---8
10---n3.1.1.1---9
11---n3.1.1.2---9
12---n3.1.1.3---9
13---n4---0
14---n5---0

Для этого дерева нужен весьма нетривиальный запрос: необходимо выбрать такие элементы, у которых есть дочерние элементы, но с таким условием, чтобы ни у одного этого дочернего элемента не было своих дочерних элементов.
В нашем примере подходящие записи это:
3---n1.2---1 (с одним дочерним элементом 4---n1.2.1---3)
9---n3.1.1---8 (у него три дочерних элемента)

Насколько это вообще можно реализовать sql запросом?
 

Beavis

Banned
DeltaDIM
ну я думаю в пару джойнов можно уложиться)
первым джойном получаешь все элементы у которых нет дочерних, а потом к ним джойнишь их "родителей"
 

DeltaDIM

Новичок
Beavis
да, я тоже думал над таким вариантом. а если мне потребуется эту проверку проводить на каком либо уровне? например я хочу найти такие элементы у записи 8---n3.1---7
 

Beavis

Banned
DeltaDIM
вообще SQL это не лучшее средство работы со списками смежности...
выбирай всё дерево (оно же у тебя не огромное?) и работай с ним в PHP

если нужны всякие извращённые выборки, то больше подойдет nested sets (можешь почитать об этом по ссылке которую тебе дали выше)
 

DeltaDIM

Новичок
Beavis
я уже сделал вариант средствами PHP, но все же хочется более изящного решения, чтобы можно было еще дополнительные условия задавать.
А размеры дерева переменчевы, возможно придется работать с порядка 3000 записями, и грузить их в PHP будет тяжеловато.

По сути я так понял джойнами нужно, я не особо силен в таких конструкциях...
 

iceman

говнокодер
в оракле для этого есть connect by, неужели в мускуле такое сделать не могут о_О
 

podbeltsev

Новичок
SELECT t1 . *
FROM tree t1
INNER JOIN tree t2 ON t2.parent_id = t1.id
LEFT JOIN tree t3 ON t3.parent_id = t2.id
GROUP BY t1.id
HAVING count( t2.id ) >0
AND count( t3.id ) =0
 
Сверху