Фильтрация детей в таблице с парентидой - PullRequest
2 голосов
/ 19 июня 2009

Мне нужна помощь в построении запроса, который позволит мне отфильтровать следующие данные.

Table: MyTree
Id  ParentId  Visible
=====================
1   null      0
2   1         1
3   2         1
4   3         1
5   null      1
6   5         1

Ожидается следующий результат запроса:

Id  ParentId  Visible
=====================
5   null      1
6   5         1

То есть все дочерние элементы скрытого узла не должны быть возвращены. Более того, глубина иерархии не ограничена. Теперь не отвечайте «просто установите 2, 3 и 4 в visible = 0» по неоправданным причинам, что невозможно ... Как будто я исправляю ужасную «устаревшую систему».

Я думал о чем-то вроде:

SELECT *
FROM MyTree m1
JOIN MyTree m2 ON m1.ParentId = m2.Id
WHERE m1.Visible = 1
AND (m1.ParentId IS NULL OR m2.Id IS NOT NULL)

Извините за любые синтаксические ошибки

Но это отфильтрует только первый уровень, верно? Надеюсь, что вы можете помочь.

Редактировать: Закончил заголовок, упс. Сервер является совершенно новым сервером MSSQL 2008, но база данных работает в режиме совместимости 2000.

Ответы [ 4 ]

2 голосов
/ 19 июня 2009

В SQL Server 2005+:

WITH    q (id, parentid, visible) AS
        (
        SELECT  id, parentid, visible
        FROM    mytree
        WHERE   id = 5
        UNION ALL
        SELECT  m.id, m.parentid, m.visible
        FROM    q
        JOIN    mytree m
        ON      m.parentid = q.id
        WHERE   q.visible = 1
        )
SELECT  *
FROM    q
1 голос
/ 19 июня 2009

Я думаю, что Кассной был близок к тому, что хочет спрашивающий, но не совсем. Я думаю, что это то, что ищет спрашивающий (SQL Server 2005 +):

WITH    q (id) AS
        (
        SELECT  id
        FROM    mytree
        WHERE   parentid is null and visible=1
        UNION ALL
        SELECT  m.id
        FROM    q
        JOIN    mytree m
        ON      m.parentid = q.id
        WHERE   q.visible = 1
        )
SELECT  *
FROM    q

Общие табличные выражения отлично подходят для такого рода работы.

1 голос
/ 19 июня 2009

Я согласен с фокусом @ Quassnoi на рекурсивных CTE (в SQL Server 2005 или более поздней версии), но я думаю, что логика отличается от ответа на оригинальный вопрос:

WITH visall(id, parentid, visible) AS
   (SELECT  id, parentid, visible
    FROM    mytree
    WHERE   parentid IS NULL
        UNION ALL
    SELECT  m.id, m.parentid, m.visible & visall.visible AS visible
    FROM    visall
    JOIN    mytree m
      ON    m.parentid = visall.id
   )
SELECT  *
FROM    visall
WHERE   visall.visible = 1

Вероятно, более оптимизированный способ выразить ту же логику должен состоять в том, чтобы как можно больше иметь видимые проверки в WHERE - остановить рекурсию по невидимым "поддеревьям" как можно скорее. I.e.:

WITH visall(id, parentid, visible) AS
   (SELECT  id, parentid, visible
    FROM    mytree
    WHERE   parentid IS NULL AND visible = 1
        UNION ALL
    SELECT  m.id, m.parentid, m.visible
    FROM    visall
    JOIN    mytree m
      ON    m.parentid = visall.id
    WHERE   m.visible = 1
   )
SELECT  *
FROM    visall

Как обычно в случае проблем с производительностью, сравнительный анализ обеих версий на реалистичных данных необходим для уверенного принятия решения (это также помогает проверить, действительно ли они дают идентичные результаты ;-) - поскольку оптимизаторы механизмов БД иногда делают странные вещи для странных причины; -)

.
0 голосов
/ 19 июня 2009

Я не думаю, что то, что вам нужно, возможно из одного запроса. Это больше похоже на то, что можно сделать из кода, и все же это потребует нескольких запросов к БД.

Если вам действительно нужно сделать это из SQL, я думаю, что вам лучше всего использовать курсор и построить таблицу со скрытыми идентификаторами. Если данные меняются не часто, вы можете сохранить эту «временную» таблицу как своего рода кеш.

Редактировать : Я исправлен (для SQL 2005), а также узнал что-то новое сегодня:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...