Encontrar nodos de hojas en arbol jerárquico.
Pregunta
Tengo una tabla en mi base de datos que almacena una estructura de árbol. Aquí están los campos relevantes:
mytree (id, parentid, otherfields...)
Quiero encontrar todos los nodos de hoja (es decir, cualquier registro cuyo id
no sea el parentid
de otro registro)
He intentado esto:
SELECT * FROM mytree WHERE `id` NOT IN (SELECT DISTINCT `parentid` FROM `mytree`)
Pero eso devolvió un conjunto vacío. Extrañamente, eliminando el " NOT " devuelve el conjunto de todos los nodos que no son hojas.
¿Alguien puede ver dónde me equivoco?
Actualización: Gracias por las respuestas, todos han sido correctos y han funcionado para mí. He aceptado la de Daniel ya que también explica por qué mi consulta no funcionó (lo que es NULO).
Solución
Su consulta no funcionó porque la subconsulta incluye NULL
. La siguiente modificación leve funciona para mí:
SELECT * FROM `mytree` WHERE `id` NOT IN (
SELECT DISTINCT `parentid` FROM `mytree` WHERE `parentid` IS NOT NULL)
Otros consejos
No hay idea de por qué su consulta no funcionó. Esto es lo mismo en la sintaxis de la combinación externa izquierda: inténtelo de esta manera.
select a.*
from mytree a left outer join
mytree b on a.id = b.parentid
where b.parentid is null
SELECT * FROM mytree AS t1
LEFT JOIN mytree AS t2 ON t1.id=t2.parentid
WHERE t2.parentid IS NULL
Seleccione * de mytree donde id no está en (seleccione un parentid distinto de mytree donde parentid no es nulo)
http://archives.postgresql.org/pgsql-sql /2005-10/msg00228.php
la estructura de mi tabla es
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