SQL Server返回所有子类别

时间:2014-11-11 10:21:53

标签: sql sql-server-2008 stored-procedures

我在SQL Server 2008 R2中有两个表:

tblCategories

  • cat_id
  • cat_name

tblCategoryHierarchy

  • cat_parent_id
  • cat_child_id

每个类别下可以有任意数量的级别和任意数量的子类别。无法更改表结构。

我要做的是,提供一个cat_id并在层次结构中返回所有cat_id,无论有多少级别。

例如(tblCategoryHierarchy):

cat_parent_id cat_child_id 101 200 101 201 101 202 101 203 202 300 202 301

  • 100
  • 101
    • 200
    • 201
    • 202
      • 300
      • 301
    • 203
  • 102

如果我提供cat_id 101,我需要返回:200,201,202,300,301和203.

我用VB尝试过这个但是我有很多很多查询而且速度非常慢。所以我正在寻找一个纯粹的SQL解决方案,我希望它能够快速而不占用太多的服务器资源。

商店程序对我来说听起来不错,那么有没有一种方法可以达到我需要的方式..?

2 个答案:

答案 0 :(得分:2)

您可以使用递归公用表表达式(CTE)执行此操作。

下面这样的事情应该这样做。这里X = 4是一个 常数:您的输入cat_id(在您的示例中为200)。

WITH CatCTE (cat_id) AS
(
    SELECT t.cat_id
    FROM tblCategories t
    WHERE t.cat_id = 4

    UNION ALL

    SELECT P.cat_child_id as cat_id
    FROM CatCTE AS m
    JOIN tblCategoryHierarchy AS P on m.cat_id = P.cat_parent_id

)
SELECT cat_id
FROM CatCTE
WHERE
cat_id <> 4;


SCRIPT创建了一些测试数据:

create table tblCategories(cat_id int, cat_name varchar(20));

create table tblCategoryHierarchy(cat_parent_id int, cat_child_id int);

insert into tblCategories(cat_id, cat_name) values ( 1, 'cat 1');
insert into tblCategories(cat_id, cat_name) values ( 2, 'cat 2');
insert into tblCategories(cat_id, cat_name) values ( 3, 'cat 3');
insert into tblCategories(cat_id, cat_name) values ( 4, 'cat 4');
insert into tblCategories(cat_id, cat_name) values ( 5, 'cat 5');

insert into tblCategories(cat_id, cat_name) values ( 6, 'cat 6');
insert into tblCategories(cat_id, cat_name) values ( 7, 'cat 7');
insert into tblCategories(cat_id, cat_name) values ( 8, 'cat 8');
insert into tblCategories(cat_id, cat_name) values ( 9, 'cat 9');
insert into tblCategories(cat_id, cat_name) values (10, 'cat 10');

insert into tblCategories(cat_id, cat_name) values (11, 'cat 11');
insert into tblCategories(cat_id, cat_name) values (12, 'cat 12');

insert into tblCategoryHierarchy (cat_parent_id, cat_child_id) values ( 1, 2);
insert into tblCategoryHierarchy (cat_parent_id, cat_child_id) values ( 1, 3);

insert into tblCategoryHierarchy (cat_parent_id, cat_child_id) values ( 4, 6);
insert into tblCategoryHierarchy (cat_parent_id, cat_child_id) values ( 4, 8);

insert into tblCategoryHierarchy (cat_parent_id, cat_child_id) values ( 8, 10);
insert into tblCategoryHierarchy (cat_parent_id, cat_child_id) values ( 8, 11);

insert into tblCategoryHierarchy (cat_parent_id, cat_child_id) values (11, 12);

insert into tblCategoryHierarchy (cat_parent_id, cat_child_id) values ( 5, 7);
insert into tblCategoryHierarchy (cat_parent_id, cat_child_id) values ( 5, 9);

答案 1 :(得分:0)

这应该对您有所帮助,获得所有层次结构一次将提供更好的性能,然后通过多次调用一次获得一个分支。

-- Here we will store the hierarchy
Dim parentToChild As New Dictionary(Of Integer, IList(Of Int))()

...

-- How you get to here depends on how you access your database,
-- somewhere between ADO.Net and EF.
-- The command simply retrieves all rows from [tblCategoryHierarchy]
-- Column 0 is [cat_parent_id], Column 1 is [cat_child_id]
Using reader As SqlDataReader = command.ExecuteReader()
    While reader.Read()
        Dim parent = reader.GetInt32(0)
        If Not parentToChild.ContainsKey(parent) Then
            parentToChild.Add(parent, New List(Of Integer))
        End If

        parentToChild(parent).Add(reader.GetInt32(1))
    End While
End Using

...

通过这种方式,您可以将层次结构加载到字典中,以便快速查找。

下一步取决于你想对层次结构做些什么。

如果您使用此扩展方法

<Extension()>
Public Shared Function Traverse(Of MyNode)( _
        ByVal root As MyNode,
        ByVal childSelector As Function(Of MyNode, IEnumerable(Of MyNode))
            As IEnumerable(Of MyNode)

    Dim stack = New Stack(Of MyNode)()
    stack.Push(root)
    While stack.Count > 0
        Dim current = stack.Pop()
        Yield current
        For Each Dim child In childSelector(current)
            stack.Push(child)
        Next
    End While
End Function

你可以轻易地遍历200的所有孩子,例如,通过这样做,

Dim children = 200.Traverse(Function(parent) parentToChild(parent))
For Each child In children
    ...
Next

如果层次结构经常更改,在多个线程上,或者您只需要层次结构的一个分支或谱系,请使用Peter Petrov's answer。