2009-06-16 30 views
3

OK、これは私がやろうとしていることです。私はMSSQL2005でCTEクエリを使用しています。このクエリの目的は、製品カテゴリの親子関係を再帰し、各カテゴリ(これには子カテゴリに含まれる製品を含む)の数を返すことです。SQL Server 2005でのCTEを使用した再帰的クエリ

現在のバージョンでは、表示されます。その子供の中に含まれるかもしれない製品を考慮していない。

問題を再現するために、データベース・ダンプ、私が使用し、説明は以下の次のクエリと一緒に:

CREATE TABLE [Categories] (
    [CategoryID] INT, 
    [Name] NCHAR(150) 

    ) 
    GO 

/* Data for the `Query_Result` table (Records 1 - 5) */ 


INSERT INTO [Categories] ([CategoryID], [Name]) 
VALUES (942, N'Diagnostic Equipment') 
GO 

INSERT INTO [Categories] ([CategoryID], [Name]) 
VALUES (943, N'Cardiology') 
GO 

INSERT INTO [Categories] ([CategoryID], [Name]) 
VALUES (959, N'Electrodes') 
GO 

INSERT INTO [Categories] ([CategoryID], [Name]) 
VALUES (960, N'Stress Systems') 
GO 

INSERT INTO [Categories] ([CategoryID], [Name]) 
VALUES (961, N'EKG Machines') 
GO 

CREATE TABLE [Categories_XREF] (
    [CatXRefID] INT, 
    [CategoryID] INT, 
    [ParentID] INT 
) 
GO 


/* Data for the `Query_Result` table (Records 1 - 5) */ 


INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID]) 
VALUES (827, 942, 0) 
GO 

INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID]) 
VALUES (828, 943, 942) 
GO 

INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID]) 
VALUES (928, 959, 943) 
GO 

INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID]) 
VALUES (929, 960, 943) 
GO 

INSERT INTO [Categories_XREF] ([CatXRefID], [CategoryID], [ParentID]) 
VALUES (930, 961, 943) 
GO 


CREATE TABLE [Products_Categories_XREF] (
    [ID] INT, 
    [ProductID] INT, 
    [CategoryID] INT 
) 
GO 


/* Data for the `Query_Result` table (Records 1 - 13) */ 


INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252065, 12684, 961) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252066, 12685, 959) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252067, 12686, 960) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252068, 12687, 961) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252128, 12738, 961) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252129, 12739, 959) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252130, 12740, 959) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252131, 12741, 959) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252132, 12742, 959) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252133, 12743, 959) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252134, 12744, 959) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252135, 12745, 959) 
GO 

INSERT INTO [Products_Categories_XREF] ([ID], [ProductID], [CategoryID]) 
VALUES (252136, 12746, 959) 
GO 

CREATE TABLE [Products] (
    [ProductID] INT 
) 
GO 


/* Data for the `Query_Result` table (Records 1 - 13) */ 


INSERT INTO [Products] ([ProductID]) 
VALUES (12684) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12685) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12686) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12687) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12738) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12739) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12740) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12741) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12742) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12743) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12744) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12745) 
GO 

INSERT INTO [Products] ([ProductID]) 
VALUES (12746) 
GO 

ここで私が使用していたCTEクエリです:

WITH ProductCategories (CategoryID, ParentID, [Name], Level) 
AS 
(
-- Anchor member definition 
    SELECT 
    C.CategoryID, 
    CXR.ParentID, 
    C.Name, 
    0 AS Level 
    FROM 
    Categories C, 
    Categories_XRef CXR 
    WHERE 
    C.CategoryID = CXR.CategoryID 
    AND CXR.ParentID = 0 
    UNION ALL 
-- Recursive member definition 
SELECT 
    C.CategoryID, 
    CXR.ParentID, 
    C.Name, 
    Level + 1 
    FROM 
    Categories C, 
    Categories_XRef CXR, 
    ProductCategories AS PC 
    WHERE 
    C.CategoryID = CXR.CategoryID 
    AND CXR.ParentID = PC.CategoryID 

) 
SELECT 
    PC.ParentID, 
    PC.CategoryID, 
    PC.Name, 
    PC.Level, 
    (SELECT 
     Count(P.ProductID) 
    FROM 
     Products P, 
     Products_Categories_XREF PCXR 
     WHERE 
     P.ProductID = PCXR.ProductID 
     AND PCXR.CategoryID = PC.CategoryID 
    ) as ProductCount 
FROM  
    Categories C, 
    ProductCategories PC 
WHERE 
PC.CategoryID = C.CategoryID 
AND PC.ParentID = 943 
ORDER BY 
    Level, PC.Name 

まず、 "を変更PC.ParentID "を943に設定します。表示されている各カテゴリの商品数を示す3つのレコードが返されます。

今度は、ParentIDをからに変更してから再実行してください。 「心臓病学」と呼ばれる結果が1件表示されますが、0個の商品が表示されます このカテゴリの下には、商品を含む子供がいます。私の大きな疑問は、このレベル(親942)で、下の子どもに含まれる製品を「ProductCount」として表示するにはどうすればいいのですか?ちょっと考えてみましょう。私はそれを試みたが、成功しなかった。

私が探しているものを実行するストアドプロシージャは公開されています。私は1つの特定の方法で設定されていません。だから、他の提案をいただければ幸いです。

答えて

4

編集 OKが実際に要件を読んで、これは実際には非常に簡単であるビットが思った

ポイントは、我々は二つのことしたいということである(と思う!):カテゴリ階層、および製品の数を。階層は再帰CTEで行われ、カウントがその外で行われます。

-- The CTE returns the cat hierarchy: 
-- one row for each ancestor-descendant relationship 
-- (including the self-relationship for each category) 
WITH CategoryHierarchy AS (
    -- Anchor member: self relationship for each category 
    SELECT CategoryID AS Ancestor, CategoryID AS Descendant 
    FROM Categories 
UNION ALL 
    -- Recursive member: for each row, select the children 
    SELECT ParentCategory.Ancestor, Children.CategoryID 
    FROM 
     CategoryHierarchy AS ParentCategory 
     INNER JOIN Categories_XREF AS Children 
     ON ParentCategory.Descendant = Children.ParentID 
) 
SELECT CH.Ancestor, COUNT(ProductID) AS ProductsInTree 
-- outer join to product-categories to include 
-- all categories, even those with no products directly associated 
FROM CategoryHierarchy CH 
LEFT JOIN Products_Categories_XREF PC 
ON CH.Descendant = PC.CategoryID 
GROUP BY CH.Ancestor 

結果は以下のとおりです。

Ancestor ProductsInTree 
----------- -------------- 
942   13 
943   13 
959   9 
960   1 
961   3 

私は私の思考は、キック入門用this article by the inestimable Itzik Ben-Ganにお世話になっています。彼の著書「Inside MS SQL Server 2005:T-SQL Querying」を強くお勧めします。

+0

他のいくつかのエラーを平滑化した後、この基本的なものが残っています:GROUP BY、HAVING、または集合関数は再帰的な共通テーブル式 'ProductCategories'の再帰部分には使用できません – Andomar

+0

Andomar、 。どうやら、再帰的なクエリで基本的な選択肢だけを持つことはできません。 –

+0

AakashM - これは完全に動作しますが、質問はどのようにして943の下のすべてにクエリの結果を制限するのですか?次の答えとしてwhere句を追加すると、うまくいきません。 – Marty

2

WHEREステートメントは結果を1つの親に限定します。 942未満のすべての子を表示するには、CTEのルートとして942を指定します。例:

WITH CTE (CategoryID, ParentID, [Name], [Level]) 
AS 
(
    SELECT C.CategoryID, CXR.ParentID, C.Name, 0 AS Level 
    FROM Categories C 
    INNER JOIN Categories_XRef CXR ON C.CategoryID = CXR.CategoryID 
    WHERE CXR.CategoryID = 943 
    UNION ALL 
    SELECT C.CategoryID, CXR.ParentID, C.Name, Level + 1 
    FROM Categories C 
    INNER JOIN Categories_XRef CXR ON C.CategoryID = CXR.CategoryID 
    INNER JOIN CTE PC ON PC.CategoryID = CXR.ParentID 
) 
SELECT * FROM CTE 

ところで、カテゴリーは複数の親を持つことができますか?そうでない場合は、Categories_XREFテーブルを削除し、CategoriesテーブルにParentIDを格納することを検討してください。

+0

Andomar、はい、複数の親が存在する可能性があります。そうでなければ、あなたが提案したものを正確に行います。 –

関連する問題