使用hierarchyid查找叶节点

时间:2013-07-29 11:58:35

标签: sql-server-2008 tsql hierarchyid

我有一个Locations表,它使用hierarchyid列来映射城市/地区/国家/大陆。该表如下所示:

declare @Locations table (
  LocationNodeID hierarchyid,
  LocationID int,
  LocationName varchar(50)
)

insert into @Locations (LocationNodeID, LocationID, LocationName) values
  (cast('/0/' as hierarchyid), 1, 'World'),
  (cast('/0/1/' as hierarchyid), 2, 'North America'),
  (cast('/0/1/1/' as hierarchyid), 3, 'United States'),
  (cast('/0/1/1/1/' as hierarchyid), 4, 'California'),
  (cast('/0/1/1/1/1/' as hierarchyid), 5, 'Los Angeles'),
  (cast('/0/1/1/1/2/' as hierarchyid), 6, 'San Francisco'),
  (cast('/0/1/1/2/' as hierarchyid), 7, 'Ohio'),
  (cast('/0/1/1/2/1/' as hierarchyid), 8, 'Cleveland'),
  (cast('/0/1/1/2/2/' as hierarchyid), 9, 'Toledo');

我有第二个表将事件映射到位置。此表展平了层次结构,每个级别有一条记录(我以这种方式继承它)。因此,如果活动在洛杉矶,则此表中有4个事件记录:洛杉矶,加利福尼亚,美国,北美。同一事件也可以在多个地点举行。

declare @EventLocations table (
  EventID int,
  LocationID int
)

insert into @EventLocations (EventID, LocationID) values
  (1, 2),  -- North America
  (1, 3),  -- United States
  (1, 4),  -- California
  (1, 5),  -- Los Angeles (leaf)

  (2, 2),  -- North America
  (2, 3),  -- United States
  (2, 7),  -- Ohio (leaf)

  (3, 2),  -- North America
  (3, 3),  -- United States (leaf)

  (4, 2),  -- North America
  (4, 3),  -- United States
  (4, 4),  -- California (leaf)
  (4, 7),  -- Ohio
  (4, 9);  -- Toledo (leaf)

我正在尝试创建一个查询,从@EventLocations中选择我已识别为叶节点的记录。这些是每个事件的记录,它们与@Locations层次结构没有后代。因此,位置可能是@EventLocations中的“叶子”,但在@Locations中有后代。我已尝试过下面的查询,但它只会拉出@Locations表中的叶子记录。

select ep.EventID, p.*, p2.*
from @EventLocations ep
  inner join @Locations p on ep.LocationID = p.LocationID
  left outer join @Locations p2 on p.LocationNodeID = p2.LocationNodeID.GetAncestor(1)
where p2.LocationID is null
order by ep.EventID, ep.LocationID

1 个答案:

答案 0 :(得分:0)

我认为你正在寻找类似下面的查询。如果我正确地关注你,你必须在同一事件中寻找父母。

顺便提一下,您通常希望提供示例数据和架构信息。它使我们更容易提供帮助,并且我们可以测试我们建议的代码。

WITH el AS
    (
        SELECT
            e.eventid
            , l.locationid
            , l.locationnodeid
            , l.locationnodeid.GetAncestor(1) parent
        FROM 
            @EventLocations e
        JOIN
            @Locations l
            ON 
                l.locationid = e.locationid
    )
SELECT
    ep.eventid
    , p.*
FROM 
    el
JOIN
    @EventLocations ep
    ON 
        ep.eventid = el.eventid
        AND 
        ep.locationid = el.locationid
JOIN
    @Locations p
    ON 
        p.locationid = ep.locationid
LEFT JOIN
    el e2
    ON 
        el.eventid = e2.eventid
        AND e2.parent = el.locationnodeid
WHERE
    e2.eventid IS NULL

编辑:

使用NOT EXISTS而不是LEFT JOIN到CTE的简单版本:

    SELECT
        ep.EventID
        , p.*
    FROM 
        @EventLocations ep
    JOIN
        @Locations p
        ON 
            p.locationid = ep.locationid    
    WHERE
        NOT EXISTS
            (
                SELECT 
                    NULL
                FROM 
                    @EventLocations el2
                JOIN 
                    @Locations l2
                    ON l2.LocationID = el2.LocationID
                WHERE
                    el2.EventID = ep.EventID
                    AND
                    l2.LocationNodeID.GetAncestor(1) = p.locationnodeid
            );