2010-03-25 2 views
1

Допустим, у меня есть следующий MySQL структуру:Каков правильный запрос на получение всех детей в дереве?

CREATE TABLE `domains` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
`domain` CHAR(50) NOT NULL, 
`parent` INT(11) DEFAULT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=MYISAM AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 

insert into `domains`(`id`,`domain`,`parent`) values (1,'.com',0); 
insert into `domains`(`id`,`domain`,`parent`) values (2,'example.com',1); 
insert into `domains`(`id`,`domain`,`parent`) values (3,'sub1.example.com',2); 
insert into `domains`(`id`,`domain`,`parent`) values (4,'sub2.example.com',2); 
insert into `domains`(`id`,`domain`,`parent`) values (5,'s1.sub1.example.com',3); 
insert into `domains`(`id`,`domain`,`parent`) values (6,'s2.sub1.example.com',3); 
insert into `domains`(`id`,`domain`,`parent`) values (7,'sx1.s1.sub1.example.com',5); 
insert into `domains`(`id`,`domain`,`parent`) values (8,'sx2.s2.sub1.example.com',6); 
insert into `domains`(`id`,`domain`,`parent`) values (9,'x.sub2.example.com',4); 

В моей голове, что достаточно, чтобы эмулировать простую структуру дерева:

  .com 
      |    
      example     
     /  \ 
     sub1   sub2 

ЭСТ

Моя проблема заключается в том, что дать SUB1. example.com Я хочу знать всех дочерних элементов sub1.example.com без использования нескольких запросов в моем коде.

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

На работе мы используем MPTT, чтобы сохранить в иерархическом порядке список доменов/поддоменов, однако я считаю, что есть более простой способ сделать это.

Я сделал некоторые копания, и кто-то сделал что-то подобное, но они потребовали использования функции в MySQL. Я не думаю, что для чего-то простого подобного нам нужна целая функция.

Возможно, я просто тупой и не вижу своего рода очевидного решения.

Также не стесняйтесь изменять структуру.

+2

'SELECT * FROM TREEHOUSE' станет моей первой догадкой. –

ответ

0

Решение было простым, хотя и спорным по эффективности.

Я изменил структуру таблицы следующим образом:

CREATE TABLE `domains` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `domain` CHAR(50) NOT NULL, 
    `level` INT(11) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=MYISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 

Уровень относится к глубине в дереве.

Образец данных:

insert into `domains`(`id`,`domain`,`level`) values (1,'.com',0); 
insert into `domains`(`id`,`domain`,`level`) values (2,'example.com',1); 
insert into `domains`(`id`,`domain`,`level`) values (3,'sub1.example.com',2); 
insert into `domains`(`id`,`domain`,`level`) values (4,'sub2.example.com',2); 
insert into `domains`(`id`,`domain`,`level`) values (5,'s1.sub1.example.com',3); 
insert into `domains`(`id`,`domain`,`level`) values (6,'s2.sub1.example.com',3); 
insert into `domains`(`id`,`domain`,`level`) values (7,'sx1.s1.sub1.example.com',4); 
insert into `domains`(`id`,`domain`,`level`) values (8,'sx2.s2.sub1.example.com',4); 
insert into `domains`(`id`,`domain`,`level`) values (9,'x.sub2.example.com',3); 
insert into `domains`(`id`,`domain`,`level`) values (10,'t.sx1.s1.sub1.example.com',5); 

Так позволяет сказать, что нам дано sub1.domain.com и мы хотим знать всех своих детей запрос довольно прост:

SELECT * FROM domains WHERE domain LIKE "%.sub1.example.com" ORDER BY level; 

Конечно, если мы хотим sub1.example.com в нашем наборе результатов мы можем просто сделать:

SELECT * FROM domains WHERE domain LIKE "%sub1.example.com" ORDER BY level; 

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

Чтобы удалить ребенка (и все связанные с ними детей) просто и очень похожий запрос

DELETE FROM domains WHERE domain LIKE "%sub1.example.com"; 

Вставки легко, и это займет всего 2 запросов (при условии, что у пользователя есть выпадающий и выбирает родитель):

SELECT level FROM domains WHERE domain = "sub2.example.com"; 

INSERT INTO domains (domain, level) VALUES ($sub + ".sub2.example.com", $level+1) 

Извините смешанный синтаксис PHP + MySQL, но вы получите эту идею.

1

Mysql имеет a good article for you

Введение

Большинство пользователей на один время или другое имели дело с иерархическими данными в базе данных SQL и, несомненно, узнали, что управление привет Эрархические данные не предназначены для реляционной базы данных. Таблицы реляционной базы данных не являются иерархическими (например, XML), а представляют собой просто плоский список. Иерархические данные имеют отношения родитель-потомок, которые не представлены естественным образом в таблице реляционных баз данных.

Для наших целей иерархические данные представляют собой набор данных, в которых каждый элемент имеет один родительский элемент и ноль или более детей (за исключением корневого элемента, у которого нет родителя). Иерархические данные можно найти в различных приложениях баз данных, включая темы форума и списка рассылки, диаграммы бизнес-организации, категории управления контентом и категории продуктов. Для наших целей мы будем использовать следующую иерархию категорий продуктов из вымышленного магазина электроники:

0

Списки адъективности помогут вам получить неправильные результаты.

a.d.f и b.d.c делает четыре узла «смежными» с d, но не существует ни a.d.c, ни b.d.f. Но закрытие списка смежности будет эффективно притворяться, что они будут.

Таким образом, ваш запрос действительно нужно что-то вроде»... WHERE EndsWith (домен, < параметр >).

Ваша вероятная проблема в том, что этот запрос будет всегда нуждаться в полный просмотр таблицы.

Возможно, это можно решить, создав вторую таблицу (domain1, domain2), которая говорит только, что «domain1 является поддоменом домена2». Вы обновляете эту таблицу, используя триггеры или sprocs, которые запускаются при каждом обновлении вашей базовой таблицы. Вставка «a.b.c.d» вставляет три строки в эту вторую таблицу: (a.b.c.d, b.c.d), (a.b.c.d, c.d), (a.b.c.d, d).

Теперь ваш запрос может быть записан как соединение между ними, которое будет работать достаточно быстро, если соответствующие индексы будут на месте.

EDIT

но существуют серьезные проблемы, возникающие при таком подходе. Если a.b.c.d снова удаляется, тогда остальные три строки, если, конечно, еще не существует какой-либо строки x.b.c.d, которая не удаляется ...

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