2009-02-05 2 views
14

я реализовал связанный список как автореферентная таблица базы данных:Как отсортировать связанный список в sql?

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

где Id является первичным ключом, и ParentId является Id предыдущего узла в списке. Первый узел имеет ParentId = NULL.

Теперь я хочу ВЫБРАТЬ из таблицы, сортируя строки в том же порядке, в каком они должны появиться, в качестве узлов в списке.

Например .: если таблица содержит строки

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 

Затем сортировочных его, используя критерии, должны привести к:

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 

Вы должны использовать SomeData Колум как контроль, поэтому, пожалуйста, не читай делать ЗАКАЗАТЬ по Некоторым Датам :-)

+0

Ваш не обманывать комментарий: было бы лучше, если бы вы выбрали образцы данных, которые не получили бы правильный результат при сортировке самостоятельно. Таким образом, «обман» не был бы вариантом. – AnthonyWJones

+1

Хм ... Я не думаю, что вы поняли мое намерение, добавив эту колонку. Я просто хотел облегчить жизнь людям, которые могли бы получить ответ. Назовите это «инструментом тестирования». –

ответ

9

В 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. Это плохая практика, чтобы использовать в качестве NULLParentID, как это не для поиска по индексам. Вставьте суррогатный корень с идентификатором 0 или -1 вместо этого и используйте START WITH ParentID = 0.

+0

Это очень хороший ответ. Как мне сделать то же самое в SQL Server 2005? –

+0

+1, но не для комментария против NULL: использование 0 или -1 исключает наличие внешнего ключа для обеспечения целостности. –

+0

Вы всегда можете хранить суррогатный корень и хранить его в базе данных. Полное сканирование для первой записи будет слишком медленным, если таблица содержит много записей. – Quassnoi

10

Я нашел решение для SQLServer, но выглядит большим и гораздо менее элегантно, чем 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

На самом деле, имя SortedList немного запутанно - это на самом деле не отсортировано - просто рекурсивно ... вам нужно ЗАКАЗАТЬ ПО ЗАВЕРШЕНИЮ конечного SELECT (см. Мой ответ) –

+0

Достаточно справедливо, я добавил столбец Level и ORDER BY в конечном SELECT. –

+0

Можно ли использовать аналогичный подход с SQLite? – Michael

5

(редактирование: d'ой Пока я отладки вы нашли его!)

В SQL Сервер:

;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 - неверно разобрал вопрос; Я думал, что вы хотите заказать его SomeData; если вы хотите, чтобы он был в связанном порядке, тогда [Уровень] - это способ пойти –

+1

Почему полуколока в начале? – Greg

+3

@Greg, потому что CTE являются разборчивыми; вы почти всегда в конечном итоге нуждаетесь в руководстве; поэтому я мог бы также добавить его. Добавьте * что-нибудь * над примером, и он идет бум –

Смежные вопросы