递归连接

Recursive joins

我在下面定义了两个 table(请注意 Regions table 是递归的,并且递归可能有很多级别)。

地区

Id ParentId Name
1 null EU
2 1 Germany
3 1 France

城市

Id Name RegionId
1 Berlin 2
2 Hamburg 2
3 Paris 3
4 Nice 3

我想看看某个地区有多少个城市。所需输出如下:

Region CityCount
EU 4
Germany 2
France 2

此查询为我提供了每个子区域中的城市数量,但我如何加入递归 table 以获得父区域(在本例中为 EU)区域?

select R.Name, count(C.Id)
from Regions R
join Cities C on C.RegionId = R.Id
group by R.Name
having count(C.Id) > 1

我试图简化我面临的现实问题,这显然是简化。

您可以使用递归 CTE 来展平您的 regions 树:

with flatregions as
(
  select t.ID, t.ParentID, t.Name, 1 as lvl
  from regions t

  union all

  select t.ID, tt.ParentID, tt.Name, t.lvl+1
  from flatregions t
  inner join regions tt on tt.ID = t.ParentID
)
select * FROM flatregions;
ID ParentID Name lvl
1 EU 1
2 1 Germany 1
3 1 France 1
3 EU 2
2 EU 2

然后在 cities table 的 JOIN 中使用该 CTE:

with flatregions as
(
  select t.ID, t.ParentID, t.Name, 1 as lvl
  from regions t

  union all

  select t.ID, tt.ParentID, tt.Name, t.lvl+1
  from flatregions t
  inner join regions tt on tt.ID = t.ParentID
)
select R.Name, count(C.Id) as CityCount
from flatregions R
join Cities C on C.RegionId = R.Id
group by R.Name
having count(C.Id) > 1
Region CityCount
EU 4
Germany 2
France 2

参见 this db<>fiddle

这似乎是您想要的。您可以使用 rCTE 通过层次结构移动到根,但每次迭代都会保留某些信息;在这种情况下,原始节点的名称。然后你仍然可以 JOINRegionID:

WITH rCTE AS(
    SELECT R.ID,
           R.ParentID,
           R.[Name]
    FROM dbo.Regions R
    UNION ALL
    SELECT R.ID,
           R.ParentID,
           C.[Name]
    FROM dbo.Regions R
         JOIN rCTE C ON R.ParentID = C.ID)
SELECT r.[Name],
       COUNT(*) AS CityCount
FROM rCTE r
     JOIN dbo.Cities C ON r.ID = C.RegionID
GROUP BY r.[Name];

db<>fiddle