在T-SQL中这种令人讨厌的递归是否可行?

时间:2012-03-21 18:17:05

标签: sql-server-2005 tsql recursion

我有3张桌子:

Region
(
    Region_id int,
    Parent_id int,
    Region_name varchar(50)
)

RegionStore
(
    Region_id int,
    Store_id int
)

StoreItems
(
    Store_id int,
    Item_id int
)

Region表是递归的,因为区域可以有父区域,如果父id是null,那么它是顶级区域。区域可能达到4个级别。

我需要为每个级别的每个区域获取一个项目计数。如果一个地区是父母 - 我需要将所有孩子的数量减少到尽可能多的水平和分支。换句话说,如果区域255具有父级130并且130具有父级67并且67具有父级2,则我需要2的计数(包括所有子级和分支)以及67的计数,包括其所有子级和分支等等。我需要在一次通话中为所有地区获取此信息。这是否可以使用递归查询?

2 个答案:

答案 0 :(得分:3)

试试这个:

DECLARE @Region TABLE 
( 
    Region_id int, 
    Parent_id int, 
    Region_name varchar(50) 
) 

DECLARE @RegionStore  TABLE
( 
    Region_id int, 
    Store_id int 
) 

DECLARE @StoreItems TABLE
( 
    Store_id int, 
    Item_id int 
) 

INSERT @Region
SELECT 2, NULL, '2' UNION ALL
SELECT 67, 2, '67' UNION ALL
SELECT 130, 67, '130' UNION ALL
SELECT 255, 130, '255' UNION ALL
SELECT 1, NULL, '1' UNION ALL
SELECT 68, 2, '68' 

-- add more test data here

;WITH CTE AS (
    SELECT  
        Region_id,
        Parent_id,
        Region_name,
        Region_id AS Region_id_calc
    FROM @Region

    UNION ALL   

    SELECT  
        r.Region_id,
        r.Parent_id,
        r.Region_name,
        CTE.Region_id_calc AS Region_id_calc
    FROM CTE
    INNER JOIN @Region AS r
        ON r.Region_id = CTE.Parent_id
)
SELECT  
    CTE.Region_id,
    Region_name,
    COUNT(DISTINCT Item_Id)
FROM CTE
INNER JOIN @RegionStore AS s
    ON CTE.Region_id_calc = s.Region_id
INNER JOIN @StoreItems AS i
    ON s.Store_id = i.Store_id
GROUP BY
    CTE.Region_id,
    Region_name
ORDER BY 
    CTE.Region_id

答案 1 :(得分:1)

这样做的一种方法是在递归查询的初始部分中包含额外的列。这允许您“传递”递归开始的位置。在下面的示例中,额外的列记住Root_id和Root_name。这应该列出所有地区及其总项目数:

; with  Regions as 
        (
        select  Region_id as Root_id
        ,       Region_name as Root_name
        ,       *
        from    @Region
        union all
        select  p.Root_id
        ,       p.Root_name
        ,       c.*
        from    Regions p
        join    @Region c
        on      p.Region_id = c.Parent_id
        )
select  r.Root_name
,       count(distinct si.Item_id) as ItemCount
from    Regions r
left join 
        @RegionStore rs 
on      rs.Region_id = r.Region_id
left join 
        @StoreItems si 
on      si.Store_id = rs.Store_id
group by
        r.Root_name

Working example on SE Data.