1

場所の保存にHierarchyIdデータ型を使用しています。ユーザーは場所によって制限される場合があります ( LocationId)。ユーザーに複数のロケーション制限がある場合、HierarchyId データ型の IsDescendantOf メソッドをOR.

例 (LocationId 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 は sqlIN句のように機能しますか?

使用したテーブル:

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

1 に答える 1

8

: 2 番目の解決策 (ポイント 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. 最初の解決策:ここでデモ

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

    INSERT @Location(LocationId, Name, [ノード]) 値 ( 1, N'A', '/1/'), ( 2, N'AA', '/1/1/'), ( 3, N' AA-1', '/1/1/1/'), -- <-- 最初の従業員 @ 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.ノード

結果:

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/
  1. 2 番目の解決策

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

于 2012-05-05T10:58:20.300 に答える