在一个SQL查询中向后调度父项?

时间:2009-10-20 18:49:42

标签: php sql mysql wordpress

我有一个MySQL数据库(由Wordpress创建),这与它的外观类似:

ID    parentID     otherStuff
54    55           this is a test
55    56           another test
56    0            last test

我需要做的是检查页面的深度。我知道当它到达parentID 0时就已经完成了。

我可以编写3个查询然后检查何时等于0,但如果只有1个查询可能会更好。可能吗?怎么样?

以下是一个例子:

  • ID:56有父0,深度为0.(现在是1个查询)
  • ID:55有父56然后是0并且有DEPTH 1.(现在是2个查询)
  • ID:54有父55然后56然后0并且有DEPTH 2.(现在3查询)

我在这里解决了“错误的方式”(每个深度级别有一个查询)get_depth()

问题在于它是一个递归函数,每个深度都需要一个查询。

8 个答案:

答案 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)的形式,或者在您编写的前端代码中。由于往返数据库,前端将变慢。

General solutions for handling Hierarchical MySQL data

答案 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