【问题标题】:use hierarchyid to find leaf nodes使用 hierarchyid 查找叶节点
【发布时间】:2013-07-29 11:58:35
【问题描述】:

我有一个 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

【问题讨论】:

    标签: sql-server-2008 tsql hierarchyid


    【解决方案1】:

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

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

    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
                );
    

    【讨论】:

    • 这不是我想要的。我正在尝试使用@Locations 层次结构来查找每个事件的叶节点。我认为我在包含填充数据的表变量方面做得很好:)
    • 是的,创建/插入到表变量是可移植的并且易于使用。我可以发誓当我看的时候他们不在那里。可能是我。抱歉,如果他们一开始就在那里,我想念他们。编辑后的代码(针对区分大小写的方法名称和对 EventLocations 的不完整连接进行了调整)返回您在问题中指定的集合。 HTH
    • 太棒了。正是我需要的。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    • 2010-09-17
    • 2023-02-16
    相关资源
    最近更新 更多