문제

좋아, 여기 내가하려고하는 일이있다. MSSQL2005에서 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 개의 레코드가 반환됩니다.

이제 부모를 바꾸십시오 943 에게 942 그리고 그것을 다시 실행하십시오. 이제 "Cardiology"라는 1 개의 결과가 반환되었지만이 범주에 따라 0 개의 제품이 표시되며 제품이 포함 된 어린이 (이전에 본 사람)가 있습니다. 나의 가장 큰 문제는,이 수준에서 (부모 942) 아래 어린이들에 포함 된 제품을 어떻게 계산하여 13을 "ProductCount"로 표시 할 수있는 방법입니다. 나는 그것을 시도했지만 성공하지 못했습니다.

나는 내가 찾고있는 일을하는 저장된 절차에 열려 있습니다. 나는 하나의 특별한 방식으로 설정되어 있지 않습니다. 그래서 다른 제안은 감사 할 것입니다.

도움이 되었습니까?

해결책

편집하다 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

나는 빚을졌다 이 기사에서는 무시할 수없는 Itzik Ben-Gan 의이 기사 내 생각을 시작하여 시작했습니다. 그의 책 'Inside MS SQL Server 2005 : T-SQL 쿼리'가 적극 권장됩니다.

다른 팁

귀하의 Where 진술은 결과를 한 부모로 제한합니다. 942 미만의 모든 어린이를보고 싶다면 942를 CTE의 뿌리로 지정하십시오. 예를 들어:

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

그건 그렇고, 카테고리가 여러 부모를 가질 수 있습니까? 그렇지 않은 경우 카테고리 _xref 테이블을 제거하고 카테고리 테이블에 Parentid를 저장하는 것이 좋습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top