Возможна ли эта неприятная рекурсия в T-SQL? - PullRequest
2 голосов
/ 21 марта 2012

У меня есть 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
)

Таблица регионов является рекурсивной в том смысле, что регионы могут иметь родительские регионы, а если родительский идентификатор равен нулю, это регион верхнего уровня. Регионы переходят на 4 возможных уровня.

Мне нужно получить количество предметов для каждого региона на каждом уровне. Если регион является родителем - мне нужно подсчитать количество его дочерних элементов на всех уровнях и ветвях. Другими словами, если у региона 255 есть родитель 130, а у 130 родитель 67, а у 67 родитель 2, мне нужно рассчитать 2 (включая все дочерние элементы и ветви) и 67, включая все его дочерние элементы и ветви и так далее. Мне нужно получить это для всех регионов за один звонок. Возможно ли это с помощью рекурсивного запроса?

Ответы [ 2 ]

3 голосов
/ 21 марта 2012

Попробуйте это:

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 голос
/ 21 марта 2012

Один из способов сделать это - включить дополнительные столбцы в начальную часть рекурсивного запроса. Это позволяет вам «пройти» там, где началась рекурсия. В приведенном ниже примере дополнительные столбцы запоминают 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

Рабочий пример с данными SE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...