在SQL Server中以不同的方式排序NULL结果?

时间:2016-04-07 19:02:34

标签: sql-server tsql sorting

我有一个查询,目前会显示如下数据:

ID | Name | Arrival  | Departure
-----------------------------------
1  | John | NULL     |  2:30:00
2  | John | NULL     | 11:00:00
3  | John | NULL     | 14:00:00
4  | John | 10:30:00 | 11:00:00
5  | John | 12:00:00 | 13:00:00

这是我做的时候:order by Name, Arrival, Departure

但是,我想要的是以下内容:

  1. 如果到货条目为NULL,则应按行排序 出发专栏。
  2. 如果到达条目为NULL AND 有多个行具有相同的Departure数据,然后它 应该在之后对具有到达的其他行进行排序 条目。
  3. 结果:

    ID | Name | Arrival  | Departure
    -----------------------------------
    1  | John | NULL     |  2:30:00
    4  | John | 10:30:00 | 11:00:00
    2  | John | NULL     | 11:00:00
    5  | John | 12:00:00 | 13:00:00
    3  | John | NULL     | 14:00:00
    

    编辑:对于那些认为这是一个重复问题的人 - 由于第二个条件,原来问题不一样。但是,由于我的数据结构的方式(到达时间总是在出发时间之前),相同的答案是适用的。

    编辑2:出发也可以是NULL。当Departure为null时,Arrival条目为非null。如果是这种情况,应该通过抵达订购。如果两行都有相同的Arrival条目,那么NULL应该是非空的。请注意,这与NULL Arrival条目(上面的条件2)相反,其中NULL在非null之后。

5 个答案:

答案 0 :(得分:3)

尝试

DECLARE @tbl TABLE(ID INT,Name VARCHAR(100),Arrival TIME,Departure TIME);
INSERT INTO @tbl VALUES
 (1,'John',NULL,'2:30:00')
,(2,'John',NULL,'11:00:00')
,(3,'John',NULL,'14:00:00')
,(4,'John','10:30:00','11:00:00')
,(5,'John','12:00:00','13:00:00');

SELECT * FROM @tbl
ORDER BY Name,CASE WHEN Arrival IS NULL THEN Departure ELSE Arrival END

结果

1   John    NULL                02:30:00.0000000
4   John    10:30:00.0000000    11:00:00.0000000
2   John    NULL                11:00:00.0000000
5   John    12:00:00.0000000    13:00:00.0000000
3   John    NULL                14:00:00.0000000

您可能会考虑ISNULL(),但您应该阅读“sargable”,特别是如果您处理许多行和索引...

答案 1 :(得分:1)

没有条件表达式和函数的简单ORDER怎么样。

如果您想首先按Departure订购,那么请按顺序排序。 如果您希望在Arrival旁边订购,但最后想要NULL,请使用DESC

即使ArrivalDeparture相同,这也会正常工作,例如,如果第{4}行Arrival11:00:00而不是10:30:00

我要感谢@Shnugo为脚本提供测试数据。

DECLARE @tbl TABLE(ID INT,Name VARCHAR(100),Arrival TIME,Departure TIME);
INSERT INTO @tbl VALUES
 (1,'John',NULL,'2:30:00')
,(2,'John',NULL,'11:00:00')
,(3,'John',NULL,'14:00:00')
,(4,'John','10:30:00','11:00:00')
,(5,'John','12:00:00','13:00:00');

SELECT * 
FROM @tbl
ORDER BY
    Name
    ,Departure
    ,Arrival DESC;

<强>结果

+----+------+------------------+------------------+
| ID | Name |     Arrival      |    Departure     |
+----+------+------------------+------------------+
|  1 | John | NULL             | 02:30:00.0000000 |
|  4 | John | 10:30:00.0000000 | 11:00:00.0000000 |
|  2 | John | NULL             | 11:00:00.0000000 |
|  5 | John | 12:00:00.0000000 | 13:00:00.0000000 |
|  3 | John | NULL             | 14:00:00.0000000 |
+----+------+------------------+------------------+

虽然......目前尚不清楚是否可能有多行非空Arrival且完全相同Departure ...您有什么要求排序在这种情况下?

答案 2 :(得分:0)

您可以按照我认为的顺序执行案例陈述。

ISNULL将是我首选的方式,因为它专门用于处理空值而且它更小。

ORDER BY Name, ISNULL(Arival, Departure)

答案 3 :(得分:0)

为了避免在WHERE子句中使用条件,您可以使用计算列来保留排序条件。此外,使用TIME类型进行到达和离开更有效(空间,比较等):

create table Data 
(
    ID INT NOT NULL,
    Name VARCHAR(100) NOT NULL,
    Arrival TIME NULL,
    Departure TIME NULL,
    ActualTime AS ISNULL(Arrival, Departure) PERSISTED
)
GO

INSERT INTO Data (ID, Name, Arrival, Departure)
VALUES
 (1,'John',NULL,'2:30:00')
,(2,'John',NULL,'11:00:00')
,(3,'John',NULL,'14:00:00')
,(4,'John','10:30:00','11:00:00')
,(5,'John','12:00:00','13:00:00');
GO

select * from Data
order by ActualTime

根据其他查询,您还可以使用ActualTime作为关键字索引。

答案 4 :(得分:0)

要获得null,我认为你可以添加

ORDER BY Name 
       , ISNULL(Arival, dateadd(ss, 1, Departure)) 
       , Departure 

但是如果你到达下一个出发时出现空值,那么你将得到一些可能不理想的结果 你需要准确说明你想要如何处理

如果你有什么

6  | John | 12:30:00 | 11:00:00 

你真的想要吗

5  | John | 12:00:00 | 13:00:00

首先对出发进行排序会更容易

declare @bigdate datetime = cast('2099-01-01' as datetime);
ORDER BY Name  
       , Departure 
       , ISNULL(Arival, @bigdate);