我有一个MySQL数据库(由Wordpress创建),这与它的外观类似:
ID parentID otherStuff
54 55 this is a test
55 56 another test
56 0 last test
我需要做的是检查页面的深度。我知道当它到达parentID 0时就已经完成了。
我可以编写3个查询然后检查何时等于0,但如果只有1个查询可能会更好。可能吗?怎么样?
以下是一个例子:
我在这里解决了“错误的方式”(每个深度级别有一个查询)get_depth()
问题在于它是一个递归函数,每个深度都需要一个查询。
答案 0 :(得分:1)
您可以编写一个存储的进程来递增计数器并返回该计数器,而不是尝试在单个查询中执行此操作。与查询相关的瓶颈通常总是在客户端(来回传输数据)。假设嵌套不会太深,那么做这样的事情应该不是一个大问题:
CREATE FUNCTION get_nested_count( start INT ) RETURN INT
BEGIN
DECLARE count INT 0;
DECLARE current INT;
current = start;
DO
count = count + 1;
SELECT * FROM pages where "id"=current;
current = pages.parent
WHILE( pages.parent > 0 && pages.parent != start );
RETURN count;
END
对while进行的第二次检查可防止循环循环(希望:P)
答案 1 :(得分:0)
这将需要某种形式的循环来处理任意深度。
循环可能采用过程SQL(LOOP / LEAVE)的形式,或者在您编写的前端代码中。由于往返数据库,前端将变慢。
答案 2 :(得分:0)
如果要查询关系数据库中的树,请使用nested set来表示关系。这将允许您使用单个查询来查找项目的深度,完整的祖先列表,查找所有相关案例等等。
答案 3 :(得分:0)
WITH RECURSIVE depths(id, parentId, depth) AS (
SELECT stuff.id, stuff.parentId, 0 FROM stuff WHERE parentId = 0
UNION
SELECT stuff.id, stuff.parentId, depths.depth + 1
FROM stuff INNER JOIN depths
ON stuff.parentId = depths.id
) SELECT * FROM depths;
当然,MySQL不支持SQL-99的WITH RECURSIVE
,但你肯定可以迭代地做同样的事情。也许您甚至应该保留一个深度表,或者在现有表中添加一列。
答案 4 :(得分:0)
您拥有的表格类型称为Adjacency List。 MySQL中不可能在邻接列表上进行任意深度查询。
通常可以解决此问题(假设您不想使用嵌套集并且您可以控制数据库模式)是将节点的深度存储为节点行中的字段(或存储分隔的字符串,表示节点的路径)。当您无法控制表结构时,最好的办法是构建一个查询脚本,直到遇到parent_id = 0
答案 5 :(得分:0)
你可以这样做。它并不完整,但这可能会让您了解如何使用SQL Server中的公用表表达式来解决您的问题。
WITH [CTE]
AS ( SELECT * FROM TieredTable t1
UNION ALL
SELECT t1.* FROM [CTE] cte, TieredTable t1
WHERE t1.[Parent_Id] = cte.[Id] )
SELECT COUNT(*) AS cnt, id
FROM [CTE]
WHERE parent_id <> 0
GROUP BY id
这是表格;
CREATE TABLE [dbo].[TieredTable](
[id] [int] NULL,
[parent_id] [int] NULL,
[stuff] [varchar](50) NULL
)
id pid stuff
10 0 One
20 10 Two
30 20 Three
答案 6 :(得分:0)
即使没有SQL,我也找到了一种非常简单的解决方法。在我的情况下,我正在使用Wordpress,它有许多标签和类。
<?php $depth = count($post->ancestors); echo $depth; ?>
简单但有效。
如果这些问题有效,那么您对此问题的解决方案不仅仅适用于Wordpress。我应该将我的解决方案设置为正确的解决方案吗?
答案 7 :(得分:0)
此查询将返回任何给定节点的深度级别:
SELECT COUNT(*)
FROM (
SELECT id,
@r :=
(
SELECT parent
FROM mytable
WHERE id = @r
AND id <> 0
) AS _parent
FROM (
SELECT @r := 56
) vars,
mytable
WHERE @r IS NOT NULL
) q
WHERE _parent IS NOT NULL;
将@r := 56
替换为您想要的节点id
。