Sql获取每个类别的计数

时间:2014-07-31 07:08:01

标签: sql sql-server sql-server-2012

考虑以下2个表

分类

CatId       CatName         HigerCatId
1           Clothing        0
2           Jackets         1      
3           T-Shirts        1
4           BlueT-Shirts    3
5           White-Jackates  2

如果更高的HigerCatId为0,则意味着我们到达了最高父母,我们应该停止

产品

ProductId   CatId
0           3
1           1
2           1
3           2
4           2
5           3
6           4
7           3
8           4

预期结果是

CatName         ChildCats      ProductsCount   ProductIds(Not needed just to give an idea)
Clothing        2,3,4,5        9               0,1,2,3,4,5,6,7,8
Jackets         5              2               3,4
T-Shirts        4              5               0,5,6,7,8
BlueT-Shirts    none           2               6,8 
White-Jackates  none           0               none

我所需要的只是获得属于某一类别的产品总数,父母的总数应包含其下所有类别的总数。 我能够用c#中的递归来做到这一点,我不知道它是否可以直接来自sql,我的问题是子类别可以有产品,即使它们有更深的子类别,这个结果是以完全动态的方式生成的sql server无论级别的深度如何,或者我应该坚持从外部sql执行它?

如果有可能请你给我一些想法吗?

当我开始获得200赏金时,我将获得奖励。

2 个答案:

答案 0 :(得分:3)

您需要CTE

WITH cte
     AS
     (
         SELECT CatId    AS ParentCatId,
                CatName,
                CatName  AS ParentName,
                HigherCatId,
                CatId,
                CAST(CatName AS VARCHAR(255)) AS PATH
         FROM   Categories
         UNION ALL 
         SELECT c.CatId    AS ParentCatId,
                cte.CatName,
                c.CatName  AS ParentName,
                c.HigherCatId,
                cte.CatId,
                CAST(cte.path + ', ' + c.CatName AS VARCHAR(255)) AS PATH
         FROM   cte
                INNER JOIN Categories c
                     ON  c.CatId = cte.HigherCatId
     )

SELECT c.parentName,
       COUNT(p.ProductId) AS ProductsCount
FROM   cte c
       LEFT OUTER JOIN products p
            ON  c.CatId = p.CatId
GROUP BY
       c.ParentCatId,
       c.ParentName
ORDER BY
       c.ParentCatId

有一些额外的列用于调试目的,您可以在最终代码中删除它们。

查看SQL Fiddle,您可以在哪里看到结果和一些中间输出。

答案 1 :(得分:2)

CTE可以创建层次结构。

XML路径可以连接列。

计数(p.CatId)与GROUP BY结合将获得确切的匹配数(ProductCount)

;WITH cte AS
(
  SELECT 
    CatId parent, 
    CatId 
  FROM Categories
  UNION ALL 
  SELECT 
    cte.parent, 
    c.CatId
  FROM cte
  JOIN
    Categories c 
  ON cte.CatId = c.HigherCatId
)
SELECT c.CatName, 
    Coalesce(STUFF(( 
        SELECT 
          ',' + cast(t1.CatId as varchar(10))
        FROM 
          cte t1 
        WHERE 
          t1.parent = c.CatId and
          t1.CatId <> c.CatId
        ORDER BY 
          t1.CatId
        for xml path(''), type 
    ).value('.', 'varchar(max)'), 1, 1, ''), 'none') ChildCats,
    COUNT(p.CatId) ProductCount,
    COALESCE(STUFF(( 
        SELECT ',' + cast(p.ProductId as varchar(10))
        FROM cte t1 
        LEFT JOIN
          Products p 
        ON
          t1.CatId = p.CatId
        WHERE 
          t1.parent = c.CatId 
        ORDER BY 
          p.ProductId
        for xml path(''), type 
    ).value('.', 'varchar(max)'), 1, 1, ''), 'none') ProductIds
FROM 
  Categories c 
JOIN
  cte 
ON 
  c.CatId = cte.parent
LEFT JOIN
  Products p
ON
  cte.CatId = p.CatId
GROUP BY 
  c.CatId, 
  c.CatName
ORDER BY 
  c.CatId

FIDDLE

结果:

CatName        ChildCat   ProductCount  ProductIds
Clothing       2,3,4,5    9             0,1,2,3,4,5,6,7,8
Jackets        5          2             3,4
T-Shirts       4          5             0,5,6,7,8
BlueT-Shirts   none       2             6,8
White-Jackates none       0             none