如何在多列上执行稳定排序?

时间:2017-12-01 21:58:36

标签: sql-server sql-server-2008-r2 stable-sort

想象一下,我有一个包含以下内容的数据集:

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不会这样做:

enter image description here

有一个订购

有一个顺序可以满足我所需的排序顺序的结果:

  • 日期列始终在增加
  • id列值始终在增加

enter image description here

当然,这不是一个独特的订单:

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

编程语言可以做到

我知道我可以在客户端完成此任务。在函数式函数编程语言中:使用stable sorting algorithm

  

稳定排序是保留输入原始顺序的排序   set,其中比较算法不区分两者   或更多项目。

     

考虑一种排序算法,按 rank 对卡进行排序,但不是   适合。稳定的排序将保证卡的原始顺序   保持相同等级;不稳定的排序不会。

     

enter image description here

不幸的是我有

  • 910万行
  • 1.8 GB

单调增加行以尽可能按时间顺序排序。显然我更喜欢在服务器上执行此操作 - 这非常适合处理大量数据。

如何在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 个答案:

答案 0 :(得分:0)

这是一个可以解决的问题。 You不必举起手来说计算机不能用来解决问题。

从数据开始,添加新的代理“Rank”列。

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

然后对于带有日期的剩余项目项目,我们需要将其分配给“next”排名:

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

答案是在第三方托管,直到星期一,所以我可以给人们机会赢得解决一个独特问题的声誉。