2

我正在从页面列表构建导航菜单。表格是这样的:

Table name: pages

id | type | parent | name
-------------------------------
1,    1,     null,   root1
2,    1,     null,   root2
3,    2,     2,      home
4,    2,     3,      child
5,    2,     4,      sub_child
6,    3,     5,      sub_sub_child


type:
1 = root page / site
2 = page
3 = ...

我的问题是,从任何页面,我都必须找到根页面。我有一个列父级,它引用父级页面,根页面除外。

我可以在表中有多个根页面,但每个页面只有一个父页面。

有人可以帮我写一个递归查询吗?

我正在尝试使用此查询,但它不起作用:

with recursive pages (id, parent) as 
(
    select pages.id, 
    pages.parent, 
    from pages
    where pages.id = 4

union all
    select pages.id, 
    pages.parent,
    from pages
    inner join pages p on p.id = pages.parent
)
select id
from pages;

谢谢

4

4 回答 4

1

正如其他海报所评论的那样,MySQL 似乎不支持这一点。您可以使用嵌套集模型重构您的表,从而摆脱对分层查询的需求。

例子

而不是列,parent您有leftid和。rightidis_root

id | type | leftid | rightid | is_root |  name
------------------------------------------------
1,    1,     1,      2         1          root1
2,    1,     3,      12        1          root2
3,    2,     4,      11        0          home
4,    2,     5,      10        0          child
5,    2,     6,      9         0          sub_child
6,    3,     7,      8         0          sub_sub_child

然后要查找任何给定记录的父项,您只需找到leftid小于和rightid大于该记录的记录。使用该is_root列获取最终的根记录。

于 2012-06-20T11:58:12.600 回答
1

我在数据库中处理树状结构数据的方法是向表中添加一列FullID以避免复杂的(可能是递归的)SQL/存储过程。

FullID     id  parent   name
-----------------------------
1          1   null     root1
2          2   null     root2
2.3        3   2        home
2.3.4      4   3        child
2.3.4.5    5   4        sub_child
2.3.4.5.6  6   5        sub_sub_child

FullID因此,要查找根页面 id,只需通过 SQL 或您的应用程序语言提取第一部分。

如果使用 SQL,则可以使用以下 SQL 获取 root id。

-- MySQL dialect
select substring_index(FullID,'.',1) as RootID from table;

-- SQL Server dialect
select case charindex('.', FullID) when 0 then FullID else substring(FullID, 1, charindex('.', FullID)-1) end as RootID from table

删除节点及其子节点

DELETE table WHERE id=<CURRENT_NODE_ID> OR FullID LIKE '<CURREN_NODE_FULLID>.%'

移动节点及其子节点

-- change the parent of current node:
UPDATE table
SET parent=<NEW_PARENT_ID>
WHERE id=<CURRENT_NODE_ID>

-- update it's FullID and all children's FullID:
UPDATE table
SET FullID=REPLACE(FullID,<CURRENT_NODE_PARENT_FULLID>, <NEW_PARENT_FULLID>)
WHERE (id=<CURRENT_NODE_ID> OR FullID LIKE '<CURRENT_NODE_FULLID>.%')

笔记

此技巧仅适用于有限的树级别情况,或者FullID如果树级别太深则无法容纳长内容。

于 2012-06-20T12:12:43.390 回答
0

您使用的WITH RECURSIVE子句适用于 PostgreSQL 数据库,不适用于 MySQL。Oracle 拥有它CONNECT BY ... START WITH ...,而且似乎在每个数据库中递归查询的执行方式都不同。

然而,MySQL 不支持递归/分层查询。您需要在程序上循环遍历行以查找到根的父级。

了解如何在 MySQL 中模拟分层查询(如 Oracle 的CONNECT BY) 。

于 2012-06-20T11:53:47.550 回答
0

我想我会对我的数据库进行一些修改。谈完之后,我可以删除列类型并添加一些表格来对不同的页面进行分类。所以结构发生了变化。我想我会使用一个 php 循环。它不漂亮,但它有效,而且不会太慢......永远不会有 200 个孩子比别人低......但我记住了START WITH

谢谢你们

于 2012-06-20T13:09:18.810 回答