如何在此 sql 查询中获取所有祖先、选定类别和直接子项

How to get all ancestors, selected category, and direct children in this sql query

我想获取其中的所有祖先、选定类别和直接子项,并统计每个类别中的所有项目及其所有子项。

这就是我所做的:

DECLARE @CategoryId INT = 8
;WITH Re AS
(
SELECT CategoryId, Name, ParentId, CategoryId RootId, 0 Depth, Sort = CAST(Name AS VARCHAR(MAX))
    FROM Category
WHERE CategoryId = @CategoryId OR ParentId = @CategoryId
UNION ALL
SELECT C.CategoryId, C.Name, C.ParentId, RootId, Depth = Re.Depth + 1, Sort = Re.Sort + CAST(C.Name AS VARCHAR(200))
    FROM Re JOIN Category C ON Re.CategoryId = C.ParentId
)
SELECT Y.CategoryId, Y.Name, Y.ParentId, X.CatCount
    FROM (SELECT RootId, COUNT(I.CategoryId) catCount
            FROM Re LEFT OUTER JOIN Item I ON Re.CategoryId = I.CategoryId
          GROUP BY RootId) X
    JOIN (SELECT Re.CategoryId, Re.ParentId, Name, MAX(Depth) MaxDepth
            FROM Re
          GROUP BY Re.CategoryId, Re.ParentId, Name) Y ON Y.CategoryId = X.RootId
ORDER BY CategoryId

是我想要的returns,就是有点问题。例如,当@CategoryId = 8 时,此查询应显示:

CategoryId  Name    ParentId    CatCount
    0        A        NULL         16
    1        B         0           10
    7        H         1           4
    8        I         7           2
    13       N         8           1

但是 returns:

CategoryId  Name    ParentId    CatCount
    8        I         7           2
    13       N         8           1

选择子类别时不显示祖先。

  1. 问题出在哪里?
  2. 如何优化这个查询?

我会感谢有人帮助我

由于 RootId 的问题,您的查询无法像您描述的那样工作(请参阅下面的评论) 您的 CTE 需要更改为:

DECLARE @CategoryId INT = 8
;WITH Re AS
(
    -- Anchor (this is the starting category)
    SELECT CategoryId, Name, ParentId, CategoryId AS RootId,
        0 AS Depth, Sort = CAST(Name AS VARCHAR(MAX)), CONVERT( VARCHAR( 20 ), 'Root' ) AS Relation
    FROM Category
    WHERE CategoryId = @CategoryId
    UNION ALL
    -- Find children
    SELECT C.CategoryId, C.Name, C.ParentId, C.CategoryId AS RootId, -- Fixed RootId problem
        Depth = Re.Depth + 1, Sort = Re.Sort + CAST(C.Name AS VARCHAR(200)), CONVERT( VARCHAR( 20 ), 'Child' ) AS Relation
    FROM Re
        INNER JOIN Category C ON Re.CategoryId = C.ParentId
    WHERE Re.Relation IN( 'Root', 'Child' )
        -- I do not think this is necessary as we have established the anchor, see above
        AND C.ParentId = @CategoryId
    UNION ALL
    -- Find Ancestors (Parents)
    SELECT C.CategoryId, C.Name, C.ParentId, C.CategoryId AS RootId, -- Fixed RootId problem
        Depth = Re.Depth - 1, Sort = Re.Sort + CAST(C.Name AS VARCHAR(200)), CONVERT( VARCHAR( 20 ), 'Parent' ) AS Relation
    FROM Re
        INNER JOIN Category C ON C.CategoryId = Re.ParentId
    WHERE Re.Relation IN( 'Root', 'Parent' )
)
SELECT * FROM Re

我使用了以下数据:

CREATE TABLE Category( CategoryId INT, Name VARCHAR( 10 ), ParentID INT )
SELECT * FROM Category
INSERT INTO Category
SELECT 0, 'A', NULL UNION ALL
SELECT 1 , 'B', 0 UNION ALL
SELECT 7 , 'H' , 1 UNION ALL
SELECT 8 , 'I' , 7 UNION ALL
SELECT 13 , 'N' , 8
-- DROP TABLE Category