2017-07-25 2 views
1

Ich möchte alle Vorfahren, ausgewählte Kategorie und direkte Kinder darin, und zählen Sie alle Elemente in jeder Kategorie und alle Kinder.So erhalten Sie alle Vorfahren, ausgewählte Kategorie und direkte Kinder in dieser SQL-Abfrage

ist es das, was ich getan habe:

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 

gibt es das, was ich will, aber ein kleines Problem ist darin. zum Beispiel, wenn @CategoryId = 8, sollte diese Abfrage angezeigt:

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

aber es gibt:

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

Vorfahren nicht angezeigt werden, wenn eine Unterkategorie ausgewählt ist.

  1. Wo ist das Problem?
  2. Wie wird diese Abfrage optimiert?

Ich werde irgend ein dankbares sein helfen mir

+0

Was ist Ihre Probe Eingangsdaten? –

+0

Beispiel Eingabedaten in dieser Abfrage oder in einer meiner Tabellen? – Masoud

+0

Für diese erwartete Ausgabe –

Antwort

0

Ihre Anfrage nicht, wie Sie wegen des Problems mit RootId (siehe Kommentare unten) beschreiben funktioniert Ihr CTE muss dies geändert werden:

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 

ich habe folgende Daten verwendet:

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 
+0

Vielen Dank. es funktioniert gut. Ich habe WHERE Re.Relation IN ('Root', 'Child') zu WHERE Re.Relation IN ('Root', 'Child') und C.ParentId = @CategoryId geändert und jetzt ist es genau das, was ich will. – Masoud

+0

@Masoud - Ich bin mir nicht sicher, ob Sie es brauchen. Meine Probe funktioniert in jedem Fall gut ohne. – Alex

+0

Ich war auf der Suche nach allen Eltern und nur direkt Kind der ausgewählten KategorieId. Ihre Abfrage funktioniert gut und hat mich gewundert, aber es gibt alle Kinder von 8 nicht sein direktes Kind zurück. Wenn zum Beispiel 13 ein Kind hat und @CategoryId = 8 gibt es 13 und sein Kind zurück, das wird nicht benötigt. aber die Lösung ist sehr sehr nützlich für mich und vielen Dank. – Masoud

Verwandte Themen