Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 从数据库中的父ID创建嵌套的树结构_Sql Server_Coldfusion_Cfquery - Fatal编程技术网

Sql server 从数据库中的父ID创建嵌套的树结构

Sql server 从数据库中的父ID创建嵌套的树结构,sql-server,coldfusion,cfquery,Sql Server,Coldfusion,Cfquery,这似乎是我想做的一项非常常见的任务,但我不能对cfloops和cfquerys掉以轻心 我有一个充满照片库的数据库。它们都有一个ID和一个ParentID,除了根库-它们的ParentID是空的,并且它们可以深入到多个级别。下面是画廊结构的一个示例: 1. 1-1 1-2 2. 2-1 2-1-1 2-1-2 2-2 我想自动将上面的结构输出到嵌套的ul和li中,就像上面一样。这是怎么做到的?我不知道ul和li的位置如何才能正确显示层次结构级别。我想最简单的解决方案是使用查询查询 如果数据集很大

这似乎是我想做的一项非常常见的任务,但我不能对cfloops和cfquerys掉以轻心

我有一个充满照片库的数据库。它们都有一个ID和一个ParentID,除了根库-它们的ParentID是空的,并且它们可以深入到多个级别。下面是画廊结构的一个示例:

1. 1-1 1-2 2. 2-1 2-1-1 2-1-2 2-2
我想自动将上面的结构输出到嵌套的ul和li中,就像上面一样。这是怎么做到的?我不知道ul和li的位置如何才能正确显示层次结构级别。

我想最简单的解决方案是使用查询查询


如果数据集很大,请尝试按需填充叶子。

我将使用查询查询递归地完成此操作

注意:下面的代码未经测试,因此请将其视为示例psuedocode

<cfquery query="qReadAllData">
  select * from your_table
</cfquery>

<!--- Read all roots (no parent ID) --->
<cfquery query="qReadRoots" dbtype="query">
  select nodeID from qReadAllData
  where parentID is null
</cfquery>

<ul>
  <cfloop query="qReadRoots">

    <cfset processNode(qReadRoots.nodeID) />

  </cfloop>
</ul>


<cffunction name="processNode" output="true">
  <cfargument name="nodeID" type="any" />

  <!--- Check for any nodes that have *this* node as a parent --->
  <cfquery query="LOCAL.qFindChildren" dbtype="query">
    select nodeID from qReadAllData
    where parentID = #ARGUMENTS.nodeID#
  </cfquery>

  <cfif LOCAL.qFindChildren.recordcount>

    <!--- We have another list! --->
    <li>
      <ul>
        <!--- We have children, so process these first --->
        <cfloop query="LOCAL.qFindChildren">

          <!--- Recursively call function --->
          <cfset processNode(LOCAL.qFindChildren.nodeID) />

        </cfloop>

      </ul>
    <li>


  <cfelse>

     <!--- We have no more children, so we just output the value --->
     <li>#nodeID#<li>

  </cfif>

</cffunction>
很晚了。我累了。我希望这是正确的:

以下是您需要的:

如果您需要帮助在表中实现它,请告诉我


更新:查看带有查询的新答案,以便使用深度进行更新,以便于选择/输出。

在这里,如果您给出实际数据结构,我将更改以匹配您的实际字段:

您可以向表中添加一个深度和完整路径列,然后只需执行一个简单的选择即可获得继承人权限并相应地输出它。一个问题,完成

WHILE EXISTS (SELECT * FROM Tree WHERE levelDeep Is Null) 
UPDATE T SET T.levelDeep = P.levelDeep + 1, 
T.fullPath= P.fullPath+ Ltrim(Str(T.ParentNode,6,0)) + '/' 
FROM Tree AS T 
INNER JOIN Tree AS P ON (T.ParentNode=P.Node) 
WHERE P.levelDeep >=0 
AND P.fullPathIs Not Null 
AND T.levelDeep Is Null

这是SQL和Coldfusion的混合。在SQLServer中格式化标签可能不是最好的方法,但它确实提供了所需的格式

SQL:

Coldfusion:

<cfscript>
    qs = new query();
    qs.setDatasource("datasource");
    qs.setSQL("
        ;WITH cte AS
        (
            SELECT t.ID, t.parentID, 1 AS level, 
                CAST(DENSE_RANK() OVER (PARTITION BY t.parentID ORDER BY t.ID) AS varchar(max)) AS label
            FROM testTable t
            WHERE parentID IS NULL

            UNION ALL 

            SELECT t.ID, t.parentID, cte.level + 1 AS level, 
                CAST(cte.label AS varchar(max)) + ' - ' + CAST(DENSE_RANK() OVER (PARTITION BY t.parentID ORDER BY t.ID) AS varchar(max)) AS label
            FROM testTable t
                INNER JOIN cte ON cte.ID = t.parentID
        )
        SELECT *,
            DENSE_RANK() OVER (PARTITION BY parentID ORDER BY ID) AS [order]
        FROM cte
        ORDER BY label
    ");
    qMenu = qs.execute().getResult();

    oldLevel = 0;

    for (i=1;i<=qMenu.recordCount;i++){        
        if (qMenu.level[i] > oldLevel) {
            WriteOutput("<ul>");
        }

        while (qMenu.level[i] < oldLevel) {
            WriteOutput("</ul>");
            oldLevel--;
        }

        WriteOutput("<li>" & qMenu.label[i] & "</li>");

        oldLevel = qMenu.level[i];

    }

    do {
        WriteOutput("</ul>");
        oldLevel--;
    } while (oldLevel > 0);
</cfscript>

实际上,您可以使用堆栈在数据库查询中完全执行此操作,如果我可以看到您的表结构和正在使用的数据库,我可以告诉您如何执行此操作。基本上,查询将按顺序返回该结果集,以及一列,告诉您该项的深度。Yipes可能重复。不需要使用游标。如果真的需要递归,那么在集合中处理数据会更有效。尽管可能有更简单的选项,如CTE,但这取决于数据库和结构。数据集?这个层次堆栈方法非常快速和高效,并且没有深度限制,sp递归地调用它。嗯?链接中的过程被递归调用。它还使用程序性的逐行处理ie游标。使用基于集合的处理进行重构更有效,并且不需要递归。重新注释忽略问题页面的标题,它不是真正的递归。进程称自己为。。。一行一行;是的,我错过了执行官,你不用打电话给程序就可以做到。我认为问题是一个标准的堆栈实现,您可以在这里看到:他当时使用的是cfquery dbtype=queryI编校,但仍然不喜欢在查询上循环,即使是QoQ@Nate当前位置还好不是你问的问题。使用QofQ没有限制,因此这是一种合法的方法。这种方法实际上创建了HTML列表——这就是问题作者所要求的。谢谢!但是我遇到了一个问题:我的老板设置了数据库,所以所有根照片库的ParentID都不是空的;他们的ParentID=PhotoGalleryID。因此,我将ReadRoots查询更改为“WHERE PhotoGalleryID=ParentID”,这是可行的,但FindChildren查询出现了问题。我假设我需要将其更改为“WHERE ParentID=Arguments.PhotoGalleryID和ParentID PhotoGalleryID”,但这只会循环到树的底部一个分支,然后给我一个查询错误:遇到ParentID=AND。不正确的条件表达式。。。
<cfscript>
    qs = new query();
    qs.setDatasource("datasource");
    qs.setSQL("
        ;WITH cte AS
        (
            SELECT t.ID, t.parentID, 1 AS level, 
                CAST(DENSE_RANK() OVER (PARTITION BY t.parentID ORDER BY t.ID) AS varchar(max)) AS label
            FROM testTable t
            WHERE parentID IS NULL

            UNION ALL 

            SELECT t.ID, t.parentID, cte.level + 1 AS level, 
                CAST(cte.label AS varchar(max)) + ' - ' + CAST(DENSE_RANK() OVER (PARTITION BY t.parentID ORDER BY t.ID) AS varchar(max)) AS label
            FROM testTable t
                INNER JOIN cte ON cte.ID = t.parentID
        )
        SELECT *,
            DENSE_RANK() OVER (PARTITION BY parentID ORDER BY ID) AS [order]
        FROM cte
        ORDER BY label
    ");
    qMenu = qs.execute().getResult();

    oldLevel = 0;

    for (i=1;i<=qMenu.recordCount;i++){        
        if (qMenu.level[i] > oldLevel) {
            WriteOutput("<ul>");
        }

        while (qMenu.level[i] < oldLevel) {
            WriteOutput("</ul>");
            oldLevel--;
        }

        WriteOutput("<li>" & qMenu.label[i] & "</li>");

        oldLevel = qMenu.level[i];

    }

    do {
        WriteOutput("</ul>");
        oldLevel--;
    } while (oldLevel > 0);
</cfscript>