【问题标题】:Get all child nodes from table从表中获取所有子节点
【发布时间】:2016-06-30 03:09:54
【问题描述】:

我正在尝试从表中获取所有子节点,但我的查询得到了一些额外的结果,我不确定为什么

SELECT [pkID]
    ,[parentID]
    ,[CategoryName]
FROM [tblCategory]
WHERE [pkID] = 6
UNION ALL
SELECT [Sub].[pkID]
    ,[Sub].[ParentID]
    ,[Sub].[CategoryName]
FROM [tblCategory] [Sub]
INNER JOIN [tblCategory] AS [Sub2] ON [Sub].[ParentID] = [Sub2].[pkID]

运行此查询时,我正在获取其他子节点 注意* 在我的 VB.Net 应用程序中(需要调用此 SQL)ParentID 为 0 是树视图中的根节点。

表格

pkID | ParentID | CategoryName
1    | 6        | Category1
2    | 0        | Category2
3    | 0        | Category3
4    | 0        | Category4
5    | 0        | Category5
6    | 0        | Category6
7    | 0        | Category7
8    | 0        | Category8
9    | 7        | Category9

结果

pkID | parentID | CategoryName
6    | 0        | Category6
1    | 6        | Category1
9    | 7        | Category9 <-- not a child of pkID=6

【问题讨论】:

  • 这是当前的结果还是想要的结果? (同时指定)
  • 这是递归 CTE 吗?因为看起来你错过了 CTE
  • 通过您的编辑,您需要递归 cte 并适当锚定我会更改。
  • 也许你应该让你的例子更大。您是否需要 6 的第一个孩子 .... 与 6 相关的每个节点或以 6 开头的每个结束叶子。
  • 这适用于哪个 RDBMS?请添加标签以指定您使用的是mysqlpostgresqlsql-serveroracle 还是db2 - 或其他完全不同的东西。

标签: sql parent-child


【解决方案1】:

这是因为您需要在底部选择 tblcategory WHERE [pkID] = 6 的相同 where 语句。没有它,您将获得整个表的孩子。

所以这样的事情应该可以工作:

SELECT [pkID]
    ,[parentID]
    ,[CategoryName]
FROM [tblCategory]
WHERE [pkID] = 6
UNION ALL
SELECT [Sub].[pkID]
    ,[Sub].[ParentID]
    ,[Sub].[CategoryName]
FROM [tblCategory] [Sub]
INNER JOIN [tblCategory] AS [Sub2] ON [Sub].[ParentID] = [Sub2].[pkID]
WHERE [sub].[pkID] = 6

正如 Juan 所说,我应该想到可以在同一个 select 语句上作为单个 where 条件完成。

SELECT [pkID]
    ,[parentID]
    ,[CategoryName]
FROM [tblCategory]
WHERE [pkID] = 6
     or ParentId = 6

这是一个递归 cte 方法,用于获取 parentid 的所有孩子、孙子、曾孙等。

;WITH cte AS (
    SELECT [pkID]
       ,[parentID]
       ,[CategoryName]
       -- ,1 AS [Level]
    FROM [tblCategory]
    WHERE [pkID] = 6


    UNION ALL

    SELECT
       t.pkId
       ,t.[parentID]
       ,t.CategoryName
       -- ,[Level] + 1 AS [Level]
    FROM
       [tblCategory] t
       INNER JOIN cte c
       ON t.ParentId = c.pkId
)

SELECT *
FROM cte  

【讨论】:

  • 我之前试过用Level,但是说ssms中的列名无效
  • 您运行的是什么版本的 sql-server?无论如何,如果您将列别名更改为其他名称或只是将其括起来,它将为您工作。
  • 由于问题未指定数据库,请参阅接受 CTE sql-workbench.eu/dbms_comparison.html 的数据库表的链接。也可能某些数据库可能需要表达式“with recursive”而不仅仅是“with”
【解决方案2】:

假设第二个节点也可能有子节点,我建议使用递归查询。像这样的东西(未经测试):

DECLARE @SearchID int = 6;

WITH cteTree AS(
SELECT pkID, parentID, CategoryName
  FROM tblCategory
  WHERE pkID = @SearchID
UNION ALL
SELECT pt.pkID, pt.parentID, pt.CategoryName
  FROM tblCategory AS pt
  JOIN cteTree AS ct ON ct.pkID = pt.parentID
)
SELECT *
  FROM cteTree

【讨论】:

  • 递归 cte 在您发布之前大约 10 分钟已经是我答案的一部分,我错过了什么吗?
  • 对不起!当我偶然发现这个问题时,它没有显示出来。然后我输入了我的答案,必须更正格式等等,当我提交我的答案时,你的答案就显示出来了......我猜我太慢了。再次:对不起!无意用已经提供的想法重新回答。
  • 无后顾之忧。在这里发布一些答案的速度真是太快了。
【解决方案3】:

看起来您尝试进行递归 cte,但随后您改变了主意。

该查询可以简化为

SELECT [pkID]
    ,[parentID]
    ,[CategoryName]
FROM [tblCategory]
WHERE [pkID] = 6
   OR [ParentID] = 6

【讨论】:

  • 是的,我应该更深入地研究它以正确修复,而不是对他的声明进行微小的更改,我知道这会起作用。给你很好的追赶投票。
  • 是的,我看到了丢失的 CTE,但不确定 OP 想要什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 2014-07-16
  • 1970-01-01
相关资源
最近更新 更多