2008-10-15 12 views
14

Tengo una tabla en mi base de datos que almacena una estructura de árbol. Estos son los campos pertinentes:Buscar nodos de hoja en árbol jerárquico

mytree (id, parentid, otherfields...) 

Quiero encontrar todos los nodos hoja (es decir, cualquier registro cuyo id no es de otro registro parentid)

He intentado esto:

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

Pero eso devolvió un conjunto vacío. Extrañamente, eliminar el "NO" devuelve el conjunto de todos los nodos de hoja.

¿Alguien puede ver dónde me está yendo mal?

Actualización: Gracias por las respuestas, todos han sido correctos y funcionó para mí. Acepté el de Daniel porque también explica por qué mi consulta no funcionó (lo NULO).

+0

Realmente es mucho mejor usar la sintaxis de unión sugerida en lugar de una subconsulta. – Draemon

+0

En realidad, no. Cualquier RDBMS a mitad de camino optimizará uno en el otro según sea necesario. La mejor práctica es usar cualquier forma que exprese tu intención más claramente. En este caso, esa forma es casi incuestionablemente una subconsulta. –

Respuesta

17

Su consulta no ha funcionado 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) 
+1

¿Cómo podemos obtener nodos de hojas de un antepasado específico? –

6

No hay idea de por qué su consulta no funcionó. Aquí está lo idéntico en la sintaxis de la combinación externa izquierda: pruébalo de esta manera.

select a.* 
from mytree a left outer join 
    mytree b on a.id = b.parentid 
where b.parentid is null 
4
SELECT * FROM mytree AS t1 
LEFT JOIN mytree AS t2 ON t1.id=t2.parentid 
WHERE t2.parentid IS NULL 
-2

mi estructura de la 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 [email protected]) 
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 
+1

hmm .. pregunta o respuesta o qué? Honestamente no entiendo lo que estás tratando de decir :) – kleopatra

Cuestiones relacionadas