сложные строки дерева sql - PullRequest
       21

сложные строки дерева sql

2 голосов
/ 11 августа 2009

структура стола

id    |    message    |    reply_id
1     |    help me!   |    0
434   |    love to    |    1
852   |    didn't work |    434
0110  |    try this   |    852
2200  |    this wont  |    0
5465  |    done. :)   |    0110

У меня есть идентификатор "852", который является серединой древовидного меню, но я хочу получить все предыдущие связанные и следующие связанные строки, поэтому я хочу получить следующие результаты, подобные этому:

помоги мне! > любовь к> не сработала> попробуй это> сделано. :) (этот результат показывается так же после цикла php, но начинается цикл с идентификатора стартера 1 с идентификатором ответа 0.

ПРИМЕЧАНИЕ: идентификатор 2200 не отображается в результате, поскольку он не входит в группу.

Ответы [ 3 ]

3 голосов
/ 11 августа 2009

Существует несколько альтернатив для упрощения работы с иерархической информацией в SQL:

  • Общие табличные выражения (в соответствии со стандартом SQL-2003) поддерживают рекурсивные SQL-запросы к типу данных родительского идентификатора, которые вы используете. Пока что MySQL не поддерживает эту функцию. PostgreSQL 8.4, Microsoft SQL Server и IBM DB2 являются примерами брендов СУБД, которые поддерживают синтаксис CTE. Oracle также имеет проприетарное расширение синтаксиса SQL, поддерживающее рекурсивные запросы.

  • Вложенные множества (левое / правое решение, которое упоминает @phantombrain) - решение, подробно описанное в книге Джо Селко «Деревья и иерархии в SQL для умных людей», а также в многочисленных статьях и публикациях в блогах в интернете.

  • Перечисление пути (он же Материализованный путь) сохраняет строку в каждой строке в иерархии, чтобы отметить путь предков этой строки. Объедините это с LIKE запросами, чтобы сравнить строку пути с путями его предков и путями потомков.

  • Таблица закрытия (он же Transitive Closure Relation) использует вторую таблицу для хранения всех отношений предка-потомка, а не только непосредственного родителя, как в используемом дизайне. Многие типы запросов становятся проще, если у вас есть все сохраненные пути.

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

1 голос
/ 11 августа 2009

Предполагая, что это пункты меню, а не что-то очень динамичное, например форум, я бы порекомендовал изменить схему, чтобы добавить левые и правые значения для каждого элемента. Все идентификаторы между левым и правым значениями являются дочерними узлами запрашиваемого узла. Таким образом, легко сделать один запрос, чтобы получить левые / правые значения, и второй запрос, чтобы получить подчиненные элементы.

См. http://www.sitepoint.com/print/hierarchical-data-database/ для получения дополнительной информации

0 голосов
/ 11 августа 2009

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

CREATE TEMPORARY TABLE tbl (myid int, ViewOrder int); 
Set @ifoundID=IdYourLookingFor;
Set @iStartID=@ifoundID;
Set @iOrder=0;
INSERT INTO tbl(myid,ViewOrder)VALUES(@ifoundID,@iOrder);

BEGIN --get the ones going up
 WHILE (@ifoundID Is Not Null) DO 
  SELECT @ifoundID=reply_id FROM YourTable WHERE id=@ifoundID; --find the next id
  SET @iOrder1=@iOrder-1; --increment the order
  INSERT INTO tbl(myid,ViewOrder)VALUES(@ifoundID,@iOrder);--save the nextid
 END WHILE;
END

Set @ifoundID=@iStartID;
BEGIN --get the ones going down
 WHILE (@ifoundID Is Not Null) DO 
  SELECT @ifoundID=id FROM YourTable WHERE reply_id=@ifoundID; --find the next id
  SET @iOrder1=@iOrder+1; --increment the order
  INSERT INTO tbl(myid,ViewOrder)VALUES(@ifoundID,@iOrder);--save the nextid
 END WHILE;
END

SELECT * FROM tbl INNER JOIN YourTable ON tbl.myid=YourTable.id ORDER BY ViewOrder

Надеюсь, что поможет

...