2009-02-05 24 views
14

he implementado una lista enlazada como una tabla de base de datos de referencia a sí misma:¿Cómo puedo ordenar una lista vinculada en sql?

CREATE TABLE LinkedList(
    Id bigint NOT NULL, 
    ParentId bigint NULL, 
    SomeData nvarchar(50) NOT NULL) 

donde ID es la clave principal y parentid es el ID del nodo anterior en la lista. El primer nodo tiene ParentId = NULL.

Ahora quiero SELECCIONAR de la tabla, ordenando las filas en el mismo orden en que deberían aparecer, como nodos en la lista.

Ej .: si la tabla contiene las filas

Id  ParentId SomeData 
24971 NULL  0 
38324 24971  1 
60088 60089  3 
60089 38324  2 
61039 61497  5 
61497 60088  4 
109397 109831 7 
109831 61039  6 

Luego de clasificación, utilizando los criterios, debería resultar en:

Id  ParentId SomeData 
24971 NULL  0 
38324 24971  1 
60089 38324  2 
60088 60089  3 
61497 60088  4 
61039 61497  5 
109831 61039  6 
109397 109831 7 

Se supone que debes usar el somedata Colum como control, así que no haga trampa haciendo PEDIDO por SomeData :-)

+0

Tu no hacen trampas comentario: tendría que ser mejor si se ha seleccionado dentro de la muestra de datos que no sería obtener el resultado correcto al ordenar por sí mismo. De esa forma, "hacer trampa" no sería una opción. – AnthonyWJones

+1

Hmm ... No creo que haya entendido mi intención al agregar esa columna. Solo quería hacer la vida más fácil para las personas que pudieran encontrar una respuesta. Llámelo una "herramienta de prueba". –

Respuesta

9

En Oracle:

SELECT Id, ParentId, SomeData 
FROM (
    SELECT ll.*, level AS lvl 
    FROM LinkedList ll 
    START WITH 
    ParentID IS NULL 
    CONNECT BY 
    ParentId = PRIOR Id 
) 
ORDER BY 
    lvl 

P. S. Es una mala práctica utilizar NULL como ParentID, ya que no se puede buscar por índices. Inserte una raíz sustituta con id de 0 o -1 en su lugar, y use START WITH ParentID = 0.

+0

Esa es una muy buena respuesta. ¿Cómo hago lo mismo en SQLServer 2005? –

+0

+1, pero no para el comentario anti-NULL: el uso de 0 o -1 impide tener una clave externa para forzar la integridad. –

+0

Siempre puede mantener una raíz sustituta y mantenerla en la base de datos. La exploración completa de una primera entrada será demasiado lenta si la tabla contiene muchos registros. – Quassnoi

10

he encontrado una solución para SQL Server, pero se ve grande y mucho menos elegante que el de Quassnoi

WITH SortedList (Id, ParentId, SomeData, Level) 
AS 
(
    SELECT Id, ParentId, SomeData, 0 as Level 
    FROM LinkedList 
    WHERE ParentId IS NULL 
    UNION ALL 
    SELECT ll.Id, ll.ParentId, ll.SomeData, Level+1 as Level 
    FROM LinkedList ll 
    INNER JOIN SortedList as s 
     ON ll.ParentId = s.Id 
) 

SELECT Id, ParentId, SomeData 
    FROM SortedList 
ORDER BY Level 
+1

En realidad, el nombre SortedList es un poco confuso, que en realidad no está ordenado, simplemente es recursivo ... debe HACER UN PEDIDO por SELECT final (ver mi respuesta) –

+0

Bastante, he agregado la columna Level y un ORDER BY en la SELECCIÓN final. –

+0

¿Se puede usar un enfoque similar con SQLite? – Michael

5

(edit: d'oh Mientras estaba depurando lo encontró también!)

En SQL servidor:

;WITH cte (Id, ParentId, SomeData, [Level]) AS (
    SELECT Id, ParentId, SomeData, 0 
    FROM LinkedList 
    WHERE ParentId IS NULL 
    UNION ALL 
    SELECT ll.Id, ll.ParentId, ll.SomeData, cte.[Level] + 1 
    FROM LinkedList ll 
    INNER JOIN cte ON ll.ParentID = cte.ID 
) 
SELECT * FROM cte 
ORDER BY [Level] 
+0

ah - leyó mal la pregunta; Pensé que querías pedirlo por SomeData; si lo quiere en orden de enlace, entonces [Nivel] es el camino a seguir –

+1

¿Por qué el punto y coma al comienzo? – Greg

+3

@Greg porque los CTE son quisquillosos; casi siempre terminas necesitando el liderazgo; así que también podría agregarlo. Agrega * cualquier cosa * sobre el ejemplo y se dispara –