Alle Ahnenknoten einer HierarchyId mit einer einzigen SQL-Anweisung finden?

7

Ich versuche, mithilfe von HierarchyID einen Weg zu finden, um alle Ahnenknoten eines bestimmten Knotens abzurufen. Jede Lösung, die ich mit HierarchyID gesehen habe, scheint entweder einen CTE oder eine Variable zu verwenden. Gibt es eine Möglichkeit, dies mit einer einzelnen select-Anweisung zu tun?

Um die Dinge einfacher zu machen:

CREATE TABLE Employee
(
    EmpId INT PRIMARY KEY IDENTITY,
    EmpName VARCHAR(100) NOT NULL,
    Position HierarchyID NOT NULL
)

INSERT INTO Employee (EmpName, Position)
VALUES ('CEO', '/'),
    ('COO', '/1/'),
    ('CIO', '/2/'),
    ('CFO', '/3/'),
    ('VP Financing', '/3/1/'),
    ('Accounts Receivable', '/3/1/1/'),
    ('Accountant 1', '/3/1/1/1/'),
    ('Accountant 2', '/3/1/1/2/'),
    ('Accountant 3', '/3/1/1/3/'),
    ('Accounts Payable', '/3/1/2/'),
    ('Accountant 4', '/3/1/2/1/'),
    ('Accountant 5', '/3/1/2/2/'),
    ('DBA', '/2/1/'),
    ('VP of Operations', '/1/1/')
Richard
quelle
Eine CTE-Lösung ist eine einzelne select-Anweisung, nicht wahr?
Jack sagt, versuchen Sie topanswers.xyz
Im Allgemeinen sind die Lösungen, die ich mit CTEs gesehen habe, rekursiv, was verwirrend ist. Außerdem gibt es eine Auswahl zum Definieren des CTE (eher zwei für die Rekursion) und eine zum Abrufen der Daten. Ich habe mich gefragt, ob es eine einzige Aussage gibt, die ohne Verwendung von CTEs gemacht werden könnte.
Richard

Antworten:

10

So erhalten Sie "alle übergeordneten Knoten eines bestimmten Knotens":

select *, position.GetAncestor(1), position.GetAncestor(1).ToString()
from employee
where position=hierarchyid::Parse('/3/1/')

EmpId  EmpName       Position  (No column name)  (No column name)
5      VP Financing  0x7AC0    0x78              /3/

aber aufgrund der Natur der Hierarchien wird es immer nur eine geben.

Wenn Sie wirklich alle unmittelbaren untergeordneten Knoten eines bestimmten Knotens erhalten möchten :

select * 
from employee 
where position.IsDescendantOf(hierarchyid::Parse('/3/1/'))=1
      and position.GetLevel()=hierarchyid::Parse('/3/1/').GetLevel()+1

EmpId  EmpName              Position
6      Accounts Receivable  0x7AD6
10     Accounts Payable     0x7ADA

- BEARBEITEN

Ich sehe, dass Sie alle Ahnenknoten wollen. Versuchen Sie vielleicht einen Ansatz wie diesen:

select * 
from employee
where hierarchyid::Parse('/3/1/2/1/').IsDescendantOf(Position) = 1

oder

select * from employee
where ( select position 
        from employee 
        where empname='Accountant 4' ).IsDescendantOf(Position) = 1

Hier ist eine CTE-Methode zum Vergleich:

with w as ( select * from employee where empname='Accountant 4'
            union all
            select e.*
            from employee e join w on(w.position.GetAncestor(1)=e.Position) )
select * from w;
Jack sagt, versuchen Sie es mit topanswers.xyz
quelle
Ich mag die wirklich. Sie sind sehr sauber und leicht zu verstehen. Viel besser als das, was ich mir ausgedacht habe.
Richard