использованная структура таблиц: [sql]create table mo_node_list (id integer primary key, parentid int, type int, name text, data text); create table mo_node_links (anc int, desc int);[/sql] + [sql]create index mo_node_links_anc on mo_node_links (anc); create index mo_node_links_desc on mo_node_links (desc); create index mo_node_list_parent on mo_node_list (parentid);[/sql]
всё переписал... на объединения забил - всё сделал через подзапросы. тесткейс и сорцы: http://dark-demon.jino-net.ru/directree/ вкратце по методам: в качестве параметров им можно передавать число-идентификатор, либо ассоциативный массив с полями как в таблице. лучше передавать массив, если он есть, ибо в первом случае некоторые методы формируют sql-подзапрос для получения нужных данных. методы формирующие sql-подзапросы, либо по возможности сразу возвращающие данные: SQLid - идентификатор узла SQLparent - идентификатор родителя узла SQLancs - список идентификаторов предков (исключая сам узел) SQLchilds - список непосредственных детей узла SQLdescsets - список внутренних узлов (то есть не, листьев) являющихся потомками узла (включая сам узел) SQLdescs - список всех потомков узла (исключая сам узел) пара геттеров: GETancs - получить всех предков в виде массива ассоциативных массивов, с опциональной возможностью фильтрации GETdescs - получить всех потомков в виде массива ассоциативных массивов, с опциональной возможностью фильтрации прочие методы: checkoff - проверяет является ли один узел потомком другого addselflink - добавляет линк от узла на самого себя inheritlinks - линкует узел со всеми предками (родитель должен быть уже прилинкован) addnode - добавляет новый узел movenode - перемещает узел со всеми его детьми к другому родителю downchilds - удаляет всех потомков узла downbranch - удаляет сам узел и всех его потомков install - заполняет таблицу связей основываясь на таблице узлов выполненной ввиде таблицы смежностей вот с последней функцией возникли серьёзные сложности: PHP: <?php function install ($rootid) { $this->db->_table($this->linktable,array('anc'=>'int','anc'=>'int')); $rootlink= $this->db->get0d(" select count(*) from {$this->linktable} where desc={$rootid} "); if (!$rootlink) $this->addselflink($rootid); $descs= $this->SQLdescsets($rootid); $this->addselflink($rootid); while ($this->db->_numaffect()) { $this->db->_begin(); $this->db->query(" insert into {$this->linktable} select l.anc, a.{$this->idfield} from {$this->listable} as a, {$this->listable} as d, {$this->linktable} as l where a.{$this->idfield}=d.{$this->parentfield} and a.{$this->parentfield} in ({$descs}) and a.{$this->idfield} not in ({$descs}) and l.desc= a.{$this->parentfield} "); $this->db->query(" insert into {$this->linktable} select desc, desc from {$this->linktable} where desc not in ( select anc from {$this->linktable} where anc=desc ) group by desc "); $this->db->_commit(); } return true; } ?> чувствую это сильно неоптимально... транзакцию приходится проводить внутри цикла, ибо при большом числе узлов скрипт так и наровит завершиться по таймауту. никого головоломки не интересуют? задача: есть таблица смежностей и пустая таблица связей. нужно организовать связи каждого узла (кроме листьев - не имеющих детей) со всеми его предками. сейчас у меня: 1. добавляется линк с корня на самого себя (если его нет); 2. ищутся узлы не засвеченные в таблице связей ("фронт"), но родители которых в таблице связей присутствуют и у которых есть хотябы 1 потомок, для каждого узла находятся идентификаторы узлов являющимися предками родителя (в том числе и сам родитель), которые линкуются с "фронтальными" узлами; 3. добавляются линки с фронтальных узлов на самих себя (ищутся узлы, которые засвечены в таблце связей, но не входят в число узлов ссылающихся на самих себя); всё это повторяется, пока в таблице связей не перестанут добавляться новые узлы. так что, кому-нибудь интересно попробовать? если да, то могу написать драйвер под мускул...
пока мускул жив - можно посмотреть статистику http://dark-demon.jino-net.ru/directree/ там правда mysql4 и sqlite2...