2014-05-22 72 views
1

我想解决一个递归SQL问题,本质上是聚合一组记录的状态。递归SQL,SQL服务器2012

出于问题的目的 - 有两个表格。一个维护聚合/层次结构“GROUP_MEMBERS”,另一个包含单个项目“ITEMS”。

“GROUP_MEMBERS” 看起来类似于(ID为GROUPID,CHILDTYPE为一组,1为单独的项目是0,和ID是子项ID(因此GROUPID为0型,商品ID为类型1)

ID | CHILDTYPE | CHILDID 

1  0  2 
1  1  1 
2  1  2 
2  1  3 
2  1  4 

在这个例子中,我的“项目”表将只有两列:

ID | STATUS 

1  0 
2  1 
3  0 
4  0 
5  0 

有效什么,我试图做的是拉了回来所有“项目”,ID和状态,一组递归下(因为组可以包含其他组)。因此,对于我提供的示例数据,如果我通过了GROUPI D为1,它会返回ITEMS 1-4的状态; GROUPID 2将是ITEMS 2-4与他们的状态,等等。

我假设我需要通过函数来​​做这件事,并返回一个表,但我甚至不知道从哪里开始。

+0

您是否需要每个组的ITEMS(如表值函数)或所有组的ITEMS的总列表? – martennis

+0

另外,你是否只有1级递归,或者更多? – martennis

+0

可能有超过1级的递归 - 我更愿意为每个组的ITEMS获得一个TVF,我认为。我想对返回的状态执行一些数学运算。 – user1695263

回答

3

这是一个很好的谜题,得告诉你:) 希望它是你想要它做的。

DECLARE @GroupRootID INT = 1 
DECLARE @GROUP_MEMBERS TABLE (ID int, CHILDTYPE int, CHILDID int) 
DECLARE @ITEMS TABLE (ID int, STATUS int) 

INSERT INTO @GROUP_MEMBERS VALUES 
(1,0,2), (1,1,1), (2,1,2), (2,0,3), (2,0,4), (2,1,3), (2,1,4), (3,1,5), (4,1,5) 

INSERT INTO @ITEMS VALUES 
(1,0), (2,1), (3,0), (4,0), (5,1) 

--    1 
--   / \ 
--   2  items   items: 1 => 1,1,1 
--  /| \ 
--  3 4 items   items: 2,3,4 => 2,1,2 - 2,1,3 - 2,1,4 
--  | \ 
-- items items    items (3): 5 => 3,1,5 
--        items (4); 5 => 4,1,5 

/* Recursivly build the GROUP tree (groups that have subgroups, CHILDTYPE=0), but NOT the lead nodes (CHILDTYPE = 1) */ 
;WITH GROUP_TREE 
AS 
(
    /* SELECT all parents */ 
    SELECT ParentGroups.*, 0 AS LEVEL 
    FROM @GROUP_MEMBERS AS ParentGroups 
    WHERE ParentGroups.CHILDTYPE = 0 
    AND ParentGroups.ID = @GroupRootID 

    UNION ALL 

    /* SELECT all childs groups for the parents */ 
    SELECT ChildGroups.*, LEVEL + 1 
    FROM @GROUP_MEMBERS AS ChildGroups 
    INNER JOIN GROUP_TREE AS Parent ON Parent.CHILDID = ChildGroups.ID 
    WHERE ChildGroups.CHILDTYPE = 0 
) 

/* We now have all groups with their subgroups (not leaf nodes) */ 
/* Then join the leaf nodes (groups that are no subtree) */ 
/* Finally union the items from the root node and join the ITEMS to the leaf nodes to get the status */ 
/* Mind you though that ITEM 5 is linked double and will be returned NON-distinct */ 

SELECT ITEMS.* 
FROM (
    SELECT GROUPS.* 
    FROM @GROUP_MEMBERS AS GROUPS 
    INNER JOIN GROUP_TREE ON GROUP_TREE.CHILDID = GROUPS.ID 
    WHERE GROUPS.CHILDTYPE = 1 

    UNION ALL 

    SELECT GROUPS.* 
    FROM @GROUP_MEMBERS AS GROUPS 
    WHERE GROUPS.CHILDTYPE = 1 
    AND GROUPS.ID = @GroupRootID 
) AS GROUP_ITEMS 
INNER JOIN @ITEMS AS ITEMS ON GROUP_ITEMS.CHILDID = ITEMS.ID 
+0

+1是我在一段时间内看到的最好解释的答案之一。 –