SQL Server Hierarchy类型方法IsDescendantOf可以接受多个输入值吗?

时间:2012-05-05 08:42:23

标签: sql sql-server sql-server-2008 hierarchyid

我使用 HierarchyId 数据类型来存储位置。用户可能受到位置限制(LocationId)。如果用户具有多个位置限制,则必须使用OR再次调用HierarchyId数据类型上的IsDescendantOf方法。

示例(按位置5和6筛选员工):

SELECT * FROM Employee
INNER JOIN Location ON Employee.LocationId = Location.LocationId
WHERE Location.Node.IsDescendantOf((SELECT TOP 1 Node
    FROM Location 
    WHERE LocationId = 5)) = 1
OR 
Location.Node.IsDescendantOf((SELECT TOP 1 Node
    FROM Location 
    WHERE LocationId=6)) = 1`

这适用于2个LocationId过滤器,但如果这种过程增长并且有人说10个过滤器会怎样。 IsDescendantOf可以像sql IN子句一样工作吗?

使用的表:

CREATE TABLE Location (
LocationId int NOT NULL PRIMARY KEY IDENTITY(1,1),
Name       nvarchar(100) NOT NULL,
[Node]  hierarchyid    NOT NULL,
[ParentNode]  AS ([Node].[GetAncestor]((1))) PERSISTED,
[Level]  AS ([Node].[GetLevel]()) PERSISTED,
);
CREATE TABLE [dbo].[Employee] (
[EmployeeId] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
[LocationId] [int] NULL,
[Name] [nvarchar](50) NULL
) ;

1 个答案:

答案 0 :(得分:5)

注意:我加入了第二个解决方案(第6点)。

1)您可以使用表格变量来存储所有搜索过的位置(例如DECLARE @SearchedAncestorLocation TABLE(LocationId INT PRIMARY KEY))。

2)您必须为HIERARCHYID's的每个位置ID找到@SearchedAncestorLocation个节点。

3)您必须使用此过滤器对员工的位置INNER JOIN进行employee_location.Node.IsDescendantOf(searched_location.Node) = 1

4)我认为您应该向UNIQUE(Node)表添加Location约束,以防止重复的位置(重复的节点)。

5)第一个解决方案demo here

DECLARE @Location TABLE(
LocationId  int NOT NULL PRIMARY KEY,
Name        nvarchar(100) NOT NULL,
[Node]      hierarchyid    NOT NULL,
UNIQUE ([Node])
);

DECLARE @Employee TABLE (
[EmployeeId] [int] PRIMARY KEY,
[LocationId] [int] NULL,
[Name] [nvarchar](50) NULL
);

INSERT  @Location(LocationId, Name, [Node])
VALUES  ( 1, N'A',     '/1/'),
        ( 2, N'AA',    '/1/1/'),
        ( 3, N'AA-1',  '/1/1/1/'), -- <-- First employee  @ AA-1
        ( 4, N'AA-2',  '/1/1/2/'),
        ( 5, N'AA-3',  '/1/1/3/'),
        ( 6, N'AB',    '/1/2/'),
        ( 7, N'AA-1',  '/1/2/1/'),
        ( 8, N'AB-2',  '/1/2/2/'),

        ( 9, N'B',     '/2/'),
        (10, N'BA',    '/2/1/'),
        (11, N'BA-1',  '/2/1/1/'), -- <-- Second employee @ BA-1
        (12, N'BA-2',  '/2/1/2/'),
        (13, N'BA-3',  '/2/1/3/'),
        (14, N'BB',    '/2/2/'),
        (15, N'BB-1',  '/2/2/1/');

INSERT  @Employee(EmployeeId, [Name], LocationId)
VALUES  (1,  N'Ion Ionescu',   3), -- AA-1
        (2, N'Geo Georgescu', 11); -- BA-1

DECLARE @SearchedAncestorLocation TABLE(LocationId INT PRIMARY KEY);
INSERT  @SearchedAncestorLocation 
VALUES  (1), --A 
        (2), --AA
        (3), --AA-1
        (9), --B
       (10), --BA
       (14); --BB

SELECT  e.*, 
        el.Name             AS EmpLocationName,
        el.Node.ToString()  AS EmpLocationHID,
        s.LocationId        AS SearchedLocationId,
        sl.Name             AS SearchedLocationName,
        sl.Node.ToString()  AS SearchedLocationHID
FROM    @Employee e
INNER JOIN  @Location el ON e.LocationId = el.LocationId
INNER JOIN  @Location sl ON el.Node.IsDescendantOf(sl.Node) = 1
INNER JOIN  @SearchedAncestorLocation s ON sl.LocationId = s.LocationId 
--AND           sl.Node <> el.Node

结果:

EmployeeId LocationId  Name          EmpLocationName EmpLocationHID SearchedLocationId SearchedLocationName SearchedLocationHID
---------- ----------- ------------- --------------- -------------- ------------------ -------------------- -------------------
1          3           Ion Ionescu   AA-1            /1/1/1/        1                  A                    /1/
1          3           Ion Ionescu   AA-1            /1/1/1/        2                  AA                   /1/1/
1          3           Ion Ionescu   AA-1            /1/1/1/        3                  AA-1                 /1/1/1/
2          11          Geo Georgescu BA-1            /2/1/1/        9                  B                    /2/
2          11          Geo Georgescu BA-1            /2/1/1/        10                 BA                   /2/1/

如果取消注释最后一行(AND sl.Node <> el.Node)的结果:

EmployeeId LocationId  Name          EmpLocationName EmpLocationHID SearchedLocationId SearchedLocationName SearchedLocationHID
---------- ----------- ------------- --------------- -------------- ------------------ -------------------- -------------------
1          3           Ion Ionescu   AA-1            /1/1/1/        1                  A                    /1/
1          3           Ion Ionescu   AA-1            /1/1/1/        2                  AA                   /1/1/
2          11          Geo Georgescu BA-1            /2/1/1/        9                  B                    /2/
2          11          Geo Georgescu BA-1            /2/1/1/        10                 BA                   /2/1/

6)第二个解决方案

SELECT  e.EmployeeId,
        e.LocationId,
        e.Name
FROM    @Employee e
INNER JOIN  @Location el ON e.LocationId = el.LocationId
WHERE EXISTS 
(
        SELECT  *
        FROM    @SearchedAncestorLocation s
        INNER JOIN @Location sl ON s.LocationId = sl.LocationId 
        WHERE   el.Node.IsDescendantOf(sl.Node) = 1
        --AND       el.Node <> sl.Node 
);