【问题标题】:Count parents backwords in one SQL Query?在一个 SQL 查询中倒数父母?
【发布时间】:2009-10-20 18:49:42
【问题描述】:

我有一个 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()get_depth() 处以“错误的方式”解决了它(每个深度级别一个查询)

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

【问题讨论】:

标签: php sql mysql wordpress


【解决方案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)

【讨论】:

    【解决方案2】:

    这将需要某种形式的循环来处理任意深度。

    循环可能采用过程 SQL (LOOP/LEAVE) 的形式,或者在您编写的前端代码中。由于往返数据库,前端会变慢。

    General solutions for handling Hierarchical MySQL data

    【讨论】:

      【解决方案3】:
      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】:

        您拥有的表类型称为Adjacency List。在 MySQL 中,不可能对邻接列表进行任意深度查询。

        通常的解决方法(假设您不想使用嵌套集并且您可以控制数据库架构)是将节点的深度存储为节点行中的字段(或存储分隔字符串表示节点的路径)。当您无法控制表结构时,最好的办法是构建一个脚本来查询直到它达到 parent_id=0

        【讨论】:

          【解决方案5】:

          你可以做这样的事情。它并不完整,但这可能会让您了解如何使用 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】:

            如果要查询关系数据库中的树,请使用nested set 来表示关系。这将允许您使用单个查询来查找项目的深度、完整的祖先列表、查找所有相关案例等等。

            【讨论】:

            • 这是一个 wordpress 数据库。可能无法随意更改架构。
            • 他用的是mysql,不是sql server。
            • @Byron 不错;只是我马虎。
            • 链接失效了。因此,这个答案是相当无用的。
            【解决方案7】:

            我找到了一个非常简单的方法来解决它,即使没有 SQL。在我的例子中,我使用的 Wordpress 有很多标签和类。

            <?php $depth = count($post->ancestors); echo $depth; ?>
            

            简单但有效。

            您对这个问题的解决方案不仅仅适用于 Wordpress,如果它们有效的话。我是否应该将我的解决方案设置为正确的,您认为呢?

            【讨论】:

            【解决方案8】:

            此查询将为您返回任何给定节点的深度级别:

            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。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-12-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多