Извлечь потомка (путь) из дерева с несколькими значениями - PullRequest
0 голосов
/ 07 марта 2012

У меня есть таблица собственных ссылок для хранения иерархических значений, чтобы отобразить их в TreeView или так далее, согласно статье Джеймса Кроули ( Древовидные структуры в ASP.NET и SQL Server )

Our table would look something like this:

Id  ParentId      Name        Depth    Lineage
1   NULL        Root Node       0       /1/
2   1           Child A         1       /1/2/
3   1           Child B         1       /1/3/
4   1           Child C         1       /1/4/
5   2           Child D         2       /1/2/5/

Чтобы получить путь к узлу (например, id = 5), он предлагает следующий запрос к таблице

SELECT *
FROM dfTree
WHERE (SELECT lineage
       FROM dfTree
       WHERE id = 5) LIKE lineage + '%'

результат будет:

Id  ParentId      Name        Depth    Lineage
1   NULL        Root Node       0       /1/
2   1           Child A         1       /1/2/
5   2           Child D         2       /1/2/5/

и является приемлемым

Но как насчет того, чтобы иметь набор результатов, когда есть несколько идентификаторов, которым я хочу указать их путь? поэтому, например, в приведенном выше примере вместо Id = 5 я хотел бы передать несколько значений примерно так:

SELECT *
FROM dfTree
WHERE (SELECT lineage
       FROM dfTree
       WHERE id IN (5,6,8,9)) LIKE lineage + '%'

Но приведенное выше утверждение не имеет смысла и является недопустимым выражением сервера sql
Как я могу решить эту проблему?
Заранее спасибо

Ответы [ 2 ]

1 голос
/ 07 марта 2012

Если вы используете SQL Server 2005 или выше, вы можете переместить подзапрос в CTE:

; with cte as (
    SELECT lineage
    FROM dfTree
    WHERE id IN (5,6,8,9)
)
SELECT d.*
FROM dfTree d
inner join cte on cte.lineage like d.lineage + '%'

Или просто реструктурировать подзапрос:

SELECT d.*
FROM dfTree d
inner join (
    SELECT lineage
    FROM dfTree
    WHERE id IN (5,6,8,9)
) s on s.lineage like d.lineage + '%'
1 голос
/ 07 марта 2012

Этот запрос ...

SELECT DISTINCT T2.*
FROM 
    (
        SELECT lineage
        FROM dfTree
        WHERE id IN (4, 5)
    ) T1
    JOIN dfTree T2
    ON
        T1.Lineage LIKE T2.Lineage + '%'

... возвращает следующий результат для ваших тестовых данных:

Id   ParentId   Name        Depth   Lineage
1    NULL       Root Node   0       /1/
2    1          Child A     1       /1/2/
4    1          Child C     1       /1/4/
5    2          Child D     2       /1/2/5/

Как видите, все пути "объединены" вместе- например, компонент пути Id=1 принадлежит как пути: /1/4/, так и пути: /1/2/5/, но существует в наборе результатов только один раз.


С другой стороны,если вам нужно нужно различать разные пути, вам нужно сделать что-то вроде этого:

SELECT T2.*, T1.Id LeafId
FROM 
    (
        SELECT id, lineage
        FROM dfTree
        WHERE id IN (4, 5)
    ) T1
    JOIN dfTree T2
    ON
        T1.Lineage LIKE T2.Lineage + '%'

Результат:

Id   ParentId   Name        Depth   Lineage    LeafId
1    NULL       Root Node   0       /1/        4
4    1          Child C     1       /1/4/      4
1    NULL       Root Node   0       /1/        5
2    1          Child A     1       /1/2/      5
5    2          Child D     2       /1/2/5/    5

В этом случаекаждый путь идентифицирован своим листом.Это предполагает, что нет никаких ромбовидных зависимостей (т.е. это настоящее дерево, а не просто DAG );если равны , вам нужно будет использовать T1.Lineage вместо T1.Id для определения пути.

...