Как выполнить стабильную сортировку по нескольким столбцам?
Представьте, что у меня есть набор данных, который содержит:
Date Id
-------------- ----
11/1/2017 null
11/4/2017 3
11/5/2017 null
11/12/2017 10
null 1
null 2
null 7
null 8
null 9
Я хочу, чтобы строки были упорядочены так, чтобы оба столбца увеличивались.
Используя наивный ORDER BY Date, ID
не делает это:
Есть заказ
Существует порядок, который удовлетворяет результатам моего желаемого порядка сортировки:
- столбец даты всегда увеличивается
- значение столбца id всегда увеличивается
Или, конечно, это не уникальный порядок:
Date Id
-------------- ---------------
null 1
11/1/2017 null
null 2
11/4/2017 3
null 7
null 8
null 9
11/5/2017 null
11/12/2017 10
Язык программирования может сделать это
Я знаю, что могу сделать это на стороне клиента. В функционально-функциональном языке программирования: используйте алгоритм стабильной сортировки:
Стабильная сортировка - это та, которая сохраняет исходный порядок входного набора, где алгоритм сравнения не различает два или более элементов.
Рассмотрим алгоритм сортировки, который сортирует карточки по рангу, но не по масти. Стабильная сортировка гарантирует, что первоначальный порядок карт одинакового ранга сохраняется; нестабильная сортировка не будет.
К сожалению у меня есть
- 9,1 миллиона строк
- 1,8 ГБ
монотонно увеличивающихся рядов, чтобы поместить в лучший возможный хронологический порядок сортировки. Очевидно, я бы предпочел сделать это на сервере - который хорошо подходит для обработки больших объемов данных.
Как я могу выполнить стабильную сортировку в SQL Server?
Пример данных
CREATE TABLE #SortDemo (Date datetime NULL, Id int NULL)
INSERT INTO #SortDemo (Date, Id)
VALUES
('20171101', null),
('20171104', 3),
('20171105', null),
('20171112', 10),
(null, 1),
(null, 2),
(null, 7),
(null, 8),
(null, 9)
SELECT * FROM #SortDemo
ORDER BY Date, Id
1 ответ
Это решаемая проблема. SMor не нужно поднимать руки и говорить, что компьютеры не могут быть использованы для решения проблем.
Начните с данных и добавьте новый суррогатный столбец "Ранг".
Date Id Rank
-------------- ---- ----
null 7 null
null 1 null
null 9 null
null 2 null
null 8 null
11/1/2017 null null
11/4/2017 3 null
11/5/2017 null null
11/12/2017 10 null
11/13/2017 null null
Тогда семя Rank
к Id
:
UPDATE SortDemo SET Rank = Id
WHERE Id IS NOT NULL
Date Id Rank
-------------- ---- ----
null 7 7
null 1 1
null 9 9
null 2 2
null 8 8
11/1/2017 null null
11/4/2017 3 3
11/5/2017 null null
11/12/2017 10 10
11/13/2017 null null
Затем для оставшихся элементов с датой нам нужно присвоить ему "следующий" ранг:
Date Id Rank
-------------- ---- ----
null 7 7
null 1 1
null 9 9
null 2 2
null 8 8
11/1/2017 null null <-- 3
11/4/2017 3 3
11/5/2017 null null <-- 10
11/12/2017 10 10
11/13/2017 null null <-- ?
с
UPDATE SortDemo SET Rank = (
SELECT MIN(Rank) FROM SortDemo s2
WHERE s2.Date >= SortDemo.Date)
WHERE SortDemo.Date IS NOT NULL
Date Id Rank
-------------- ---- ----
null 7 7
null 1 1
null 9 9
null 2 2
null 8 8
11/1/2017 null 3 <--
11/4/2017 3 3
11/5/2017 null 10 <--
11/12/2017 10 10
11/13/2017 null null <-- ?
Есть также крайний случай, когда нет предметов "после" нас; который мы можем исправить, вернувшись назад к одному из самых высоких предыдущих уровней:
UPDATE SortDemo SET Rank = (
SELECT MAX(Rank) FROM SortDemo s2
WHERE s2.Date <= SortDemo.Date)
WHERE SortDemo.Date IS NOT NULL
Date Id Rank
-------------- ---- ----
null 7 7
null 1 1
null 9 9
null 2 2
null 8 8
11/1/2017 null 3
11/4/2017 3 3
11/5/2017 null 10
11/12/2017 10 10
11/13/2017 null 10 <--10
И мы сделали
Теперь мы можем сортировать по суррогатным Rank
и разрывать связи, сортируя по Date
:
SELECT * FROM SortDemo
ORDER BY Rank, Date
Date Id Rank
-------------- ---- ----
null 1 1
null 2 2
11/1/2017 null 3
11/4/2017 3 3
null 7 7
null 8 8
null 9 9
11/5/2017 null 10
11/12/2017 10 10
11/13/2017 null 10
Решение завершено. Sql Fiddle
Ответ на условном депонировании до понедельника, поэтому я могу дать людям возможность заработать репутацию для решения уникальной проблемы.