题
表结构
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
我有一个 id“852”,它位于树形菜单的中间,但我想获取所有先前的相关行和下一个相关行,所以我想获得以下结果:
帮我!> 喜欢 > 没用 > 尝试一下 > 完成。:) (这个结果在 php 循环之后显示,但从起始 ID 1 和回复 ID 0 开始循环。
笔记:2200 id 没有显示在结果中,因为它不属于该组。
解决方案
有几种替代方法可以使层次结构信息更容易在 SQL 中使用:
通用表表达式 (根据 SQL-2003 标准)支持针对您正在使用的父 ID 类型的数据进行递归 SQL 查询。目前为止,MySQL还不支持该功能。PostgreSQL 8.4、Microsoft SQL Server 和 IBM DB2 是支持 CTE 语法的 RDBMS 品牌的示例。Oracle 还拥有支持递归查询的 SQL 语法专有扩展。
嵌套集 (@phantombrain 提到的左/右解决方案)是 Joe Celko 的书“Trees and Hierarchies in SQL for Smarties”以及互联网上的许多文章和博客文章中详细介绍的解决方案。
路径枚举 (又名物化路径)在层次结构中的每一行中存储一个字符串,以记录该行的祖先的路径。将此与
LIKE
查询以将路径字符串与其祖先路径和后代路径进行比较。关闭表 (又名传递闭包关系)使用第二个表来存储所有祖先-后代关系,而不仅仅是您正在使用的设计中的直接父级关系。一旦存储了所有路径,许多类型的查询就会变得更容易。
混合解决方案 也存在。例如,像您正在做的那样存储直接父 ID,但也存储树的根。现在,您可以获取同一层次结构中的所有其他行,将它们提取到应用程序代码中,并使用传统数据结构对树进行排序。
其他提示
假设这些菜单项和不是很动态的,比如一个论坛,我会建议模式更改为每个项目添加左边和右边的值。左,右值之间的ID是要查询的节点的所有孩子。因此,很容易做一个查询来获取左/右值,和第二查询得到子项目。
请参阅 http://www.sitepoint.com/print/hierarchical-data -database / 了解详情
递归是最优雅的方式来做到这一点,但我不认为MySQL支持它的自定义函数或storedprocedures。我建议一环到一个临时表或表变量,让您的ID,然后加入表和结果查询回来。我不知道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
希望帮助