Найти конечные узлы в иерархическом дереве

У меня есть таблица в моей базе данных, в которой хранится древовидная структура. Вот соответствующие поля:

mytree (id, parentid, otherfields...)

Я хочу найти все листовые узлы (то есть любую запись, чья id не является другой записью parentid)

Я пробовал это:

SELECT * FROM mytree WHERE `id` NOT IN (SELECT DISTINCT `parentid` FROM `mytree`)

Но это вернуло пустой набор. Как ни странно, удаление «НЕ» возвращает набор всех нелистовых узлов.

Может ли кто-нибудь увидеть, где я ошибаюсь?

Обновление: Спасибо за ответы, все они были правильными и работали на меня. Я принял вариант Даниэля, так как он также объясняет, почему мой запрос не сработал (вещь NULL).


person nickf    schedule 15.10.2008    source источник
comment
На самом деле гораздо лучше использовать предложенный синтаксис соединения, а не подзапрос.   -  person Draemon    schedule 15.10.2008
comment
Вообще-то, нет. Любая хоть наполовину приличная РСУБД оптимизирует одну в другую по мере необходимости. Лучше всего использовать любую форму, наиболее четко выражающую ваши намерения. В данном случае эта форма почти несомненно является подзапросом.   -  person Daniel Spiewak    schedule 15.10.2008


Ответы (4)


Ваш запрос не сработал, так как подзапрос включает NULL. У меня работает следующая небольшая модификация:

SELECT * FROM `mytree` WHERE `id` NOT IN (
    SELECT DISTINCT `parentid` FROM `mytree` WHERE `parentid` IS NOT NULL)
person Daniel Spiewak    schedule 15.10.2008
comment
Как мы можем получить листовые узлы от определенного предка? - person Oğuz Can Sertel; 16.06.2016

Не знаю, почему ваш запрос не сработал. Вот то же самое в синтаксисе левого внешнего соединения — попробуй так?

select a.*
from mytree a left outer join
     mytree b on a.id = b.parentid
where b.parentid is null
person TheSoftwareJedi    schedule 15.10.2008

Select * from mytree where id not in (Select distinct parentid from mytree where parentid is not null)

http://archives.postgresql.org/pgsql-sql/2005-10/msg00228.php

person fatbuddha    schedule 15.10.2008

моя структура таблицы

memberid    MemberID    joiningposition packagetype
RPM00000    NULL          Root                free
RPM71572    RPM00000       Left           Royal
RPM323768   RPM00000       Right              Royal
RPM715790   RPM71572       Left            free
RPM323769   RPM71572      Right            free
RPM715987   RPM323768      Left             free
RPM323985   RPM323768      Right               free
RPM733333   RPM323985     Right            free
RPM324444   RPM715987     *emphasized text*Right               Royal

--

ALTER procedure [dbo].[sunnypro]
as
DECLARE @pId varchar(40) = 'RPM00000';
Declare @Id int
set @Id=(select id from registration where childid=@pId) 
begin




-- Recursive CTE
    WITH R AS
     (



SELECT 

    BU.DateofJoing,
    BU.childid,
    BU.joiningposition,
    BU.packagetype
    FROM registration AS BU
    WHERE
    BU.MemberID = @pId and
   BU.joiningposition IN ('Left', 'Right')
    or BU.packagetype in('Royal','Platinum','Majestic')
     and BU.Id>@id
    UNION All

-- Recursive part
SELECT

     BU.DateofJoing,
     BU.childid,
     R.joiningposition,
    BU.packagetype


    FROM R
    JOIN registration AS BU
    ON BU.MemberID = R.childid
    WHERE
    BU.joiningposition IN ('Left', 'Right') and
  BU.packagetype in('Royal','Platinum','Majestic')
 and BU.Id>@id
)

INSERT INTO Wallatpayout
       (childid
       ,packagetype

       ,joiningposition
       ,DateofJoing
       ,Total)

-- Final groups of nodes found
SELECT top 3

R.childid,
R.packagetype,
R.joiningposition,
R.DateofJoing,
Total = COUNT_BIG(*)
FROM R where R.packagetype in('Royal','Platinum','Majestic')
GROUP BY R.childid,
R.joiningposition,
R.DateofJoing,
R.packagetype
OPTION (MAXRECURSION 0);
end
person Sunny srivastav    schedule 05.10.2015
comment
хм.. вопрос или ответ что ли? Честно говоря, не понимаю, что вы хотите сказать :) - person kleopatra; 05.10.2015