获取父ID的所有嵌套子项

时间:2013-09-03 21:37:19

标签: sql sql-server-2008 tsql

Started Fiddling

Work Table
ProductId, LabelName, CategoryId, ChildCategoryId
------------------------------------
1, Widget A, 1, null
null, Category A, 2, 1 
2, Widget B, 3, null

Categories Table
CategoryId, CategoryName
---------------------------
1, Category A
2, Category B
3, Category C

鉴于上述信息,您如何获得产品ID的所有类别?

例如,如果产品ID为1,则以下是期望的结果。

Desired Results
ProductId, LabelName, CategoryId, ChildCategoryId
------------------------------------
1, Widget A, 1, null
null, Category A, 2, 1 
null, Category B, null, 2

它应该是分层数据,我为无法解释得很好而道歉。这只是让我难以置信。窗口小部件A的产品ID为1,类别ID为1.这意味着包含ChildCategoryId为1的所有记录,这给我们分类A.CatA的类别ID为2,所以像以前一样,所有记录都有ChildCategoryId为2包含在结果中,这就是包含B类的原因。

1 个答案:

答案 0 :(得分:1)

此混乱会从样本数据中生成样本结果。目前还不清楚认为该算法应该是什么。

declare @CategoryItems as Table (
  CategoryName NVarChar(255),
  Label NVarChar(255),
  ProductId Int,
  ChildCategoryId Int,
  CategoryId Int );

declare @Categories as Table (
  CategoryId Int,
  Name NVarChar(100) );

insert into @CategoryItems ( CategoryName, Label, ProductId, ChildCategoryId, CategoryId ) values
  ( 'CategoryA', 'Widget A', 1, 0, 1 ),
  ( 'CategoryB', 'CategoryA', 0, 1, 2 ),
  ( 'CategoryC', 'Widget B', 2, 0, 3 );
insert into @Categories ( CategoryId, Name ) values
  ( 1, 'CategoryA' ),
  ( 2, 'CategoryB' ),
  ( 3, 'CategoryC' );

select * from @Categories;
select * from @CategoryItems;

declare @TargetProductId as Int = 1;

with Leonard as (
  -- Start with the target product.
  select 1 as [Row], ProductId, Label, CategoryId, ChildCategoryId
    from @CategoryItems
    where ProductId = @TargetProductId
  union all
  -- Add each level of child category.
  select L.Row + 1, NULL, CI.Label, CI.CategoryId, CI.ChildCategoryId
    from @CategoryItems as CI inner join
      Leonard as L on L.CategoryId = CI.ChildCategoryId ),
  Gertrude as (
    -- Take everything that makes sense.
    select Row, ProductId, Label, CategoryId, ChildCategoryId
      from Leonard
    union
    -- Then tack on an extra row for good measure.
    select L.Row + 1, NULL, C.Name, NULL, C.CategoryId
      from Leonard as L inner join
        @Categories as C on C.CategoryId = L.CategoryId
      where L.Row = ( select Max( Row ) from Leonard ) )
  select Row, ProductId, Label, CategoryId, ChildCategoryId
    from Gertrude
    order by Row;

我怀疑问题在于您以不平衡的方式混合了数据。类别层次结构通常表示为:

declare @Categories as Table (
  CategoryId Int Identity,
  Category NVarChar(128),
  ParentCategoryId Int Null );

每个层次结构的根由ParentCategoryId is NULL表示。这允许任意数量的独立树在一个表中共存,并且不依赖于任何产品的存在。

如果将产品分配到单个(子)类别,则只需在CategoryId表中包含Products即可。如果可以将产品分配给多个(子)类别(可能在不同的层次结构中),则使用单独的表来关联它们:

declare @ProductCategories as Table (
  ProductId Int,
  CategoryId Int );