按两列的最小值排序

Vas*_*kov 51 sql t-sql sql-server sorting min

我用SQL Server 2008 R2.

我需要按两列的最小值对表进行排序.

该表如下所示:

ID: integer; 
Date1: datetime; 
Date2: datetime.
Run Code Online (Sandbox Code Playgroud)

我希望我的数据按最少两个日期排序.

以这种方式对此表进行排序的最简单方法是什么?

Sta*_*vas 59

NOT NULL列.您需要在以下的ORDER BY子句中添加CASE语句:

SELECT Id, Date1, Date2
FROM YourTable
ORDER BY CASE 
           WHEN Date1 < Date2 THEN Date1 
           ELSE Date2 
         END 
Run Code Online (Sandbox Code Playgroud)

NULLABLE列.正如Zohar Peled在评论中写道,如果列可以为空,那么您可以使用ISNULL(但最好使用COALESCE而不是ISNULL,因为它是ANSI SQL standard)以下内容:

SELECT Id, Date1, Date2
FROM YourTable
ORDER BY CASE 
           WHEN COALESCE(Date1, '1753-01-01') < COALESCE(Date2, '1753-01-01') THEN Date1 
           ELSE Date2 
         END
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读有关ANSI标准日期格式的1753-01-01 信息.

  • 你真的应该使用ANSI标准dateformat.1753年1月1日 (12认同)
  • 你可以停止回滚吗?它反复"碰撞"你的答案,可能被视为滥用编辑功能.它也产生了旗帜.如果这种情况继续下去,我将不得不锁定答案. (7认同)
  • 你为什么要编辑你的答案100次?添加空格删除空格添加空格删除空间? (4认同)
  • 这是假设日期列不可为空.如果它们是,那么正确的order by子句将是`CASE WHEN ISNULL(Date1,'01/01/1753')<ISNULL(Date2,'01/01/1753')那么Date1 ELSE Date2 END` (2认同)
  • 我同意,但OP可能没有意识到这个问题,所以值得一提.无论如何你已经投票了,因为你的答案包含了MSDN相关部分的链接,因此比其他答案更好. (2认同)

jar*_*rlh 35

使用以下CASE表达式ORDER BY:

 ORDER BY case when date1 < date2 then date1 else date2 end
Run Code Online (Sandbox Code Playgroud)

编辑:

如果需要考虑空值,请添加coalesce():

 ORDER BY case when date1 < date2 then date1 else coalesce(date2,date1) end
Run Code Online (Sandbox Code Playgroud)

说明:

如果date1 <date2则按date1排序.(这里的两个日期都是非空的.)就像以前一样工作.

其他用于COALESCE()按date2(当date2不为null)或date1(当date2为null时)或null(如果两个日期都为null)进行排序.

  • @qazifarhan,我很害怕,你错了.简单测试:3行表:`2015-01-10,2015-01-20`; `2015-01-20,2015-01-11`; `2015-01-15,2015-01-15`.这是按两个日期的"MIN"排序时的顺序.如果你只是按date1,date2订购,你会得到不同的结果. (10认同)

dya*_*nko 8

最简单的方法是使用VALUES关键字,如下所示:

SELECT ID, Date1, Date2
FROM YourTable
ORDER BY (SELECT MIN(v) FROM (VALUES (Date1), (Date2)) AS value(v))
Run Code Online (Sandbox Code Playgroud)

此代码适用于所有情况,即使是可以为空的列.

编辑:

使用COALESCE关键字的解决方案不是通用的.它有重要的限制:

  • 如果列是Date类型(如果您使用之前的日期01/01/1753),它将无法工作
  • 如果其中一列是,它将无法工作NULL.它将NULL值解释 为最小值datetime.但它确实是真的吗?它不是偶数datetime,它什么都不是.
  • IF如果我们使用列以上,表达式会复杂得多.

根据问题:

以这种方式对此表进行排序的最简单方法是什么?

最简单和最简单的解决方案是上述解决方案,因为:

  • 它不需要很多编码来实现它 - 只需再添加一行.
  • 无需关心列是否可以为空.你只需使用代码即可.
  • 可以通过在逗号后添加一列来扩展查询中的列数.
  • 适用Date列,您无需修改​​代码.

编辑2:

Zohar Peled建议采用以下方式:

我会按照这个规则对行进行排序:首先,当null为空时,第二个,当date1为null时,第三个,当date2为null时,第四个,min(date1,date2)

因此,对于这种情况,可以通过使用相同的方法来达到解决方案,如下所示:

SELECT ID, Date1, Date2
FROM YourTable
ORDER BY 
CASE WHEN Date1 IS NULL AND Date2 IS NULL THEN 0
     WHEN Date1 IS NULL THEN 1
     WHEN Date2 IS NULL THEN 2
     ELSE 3 END,
(SELECT MIN(v) FROM (VALUES ([Date1]), ([Date2])) AS value(v))
Run Code Online (Sandbox Code Playgroud)

此代码的输出如下:

*Zohar的*订单方式的输出结果

COALESCE 解决方案 将不排序表这种方式.它弄乱了至少有一个NULL值的单元格的行.它的输出如下:

<code> COALESCE </ code>解决方案的奇怪ORDER BY

希望这有助于等待批评者.


pjo*_*obs 5

如果你不希望使用Case statementOrder By,那么这是另一种方法,只需移动Case statementSelect

SELECT Id, Date1, Date2 FROM 
 (SELECT Id, Date1, Date2
  ,CASE WHEN Date1 < Date2 THEN Date1 ELSE Date2 END as MinDate 
FROM YourTable) as T
ORDER BY MinDate
Run Code Online (Sandbox Code Playgroud)


Aru*_*ola 5

这可能是一种不需要分支的替代解决方案CASE WHEN.这基于此处max(a,b)=1/2(a+b+|a?b|)描述的公式.我们使用参考日期()获得a和b的绝对值.DATEDIFF'1773-01-01'

ORDER BY (DATEDIFF(d,'17730101' ,isnull(Startdate,enddate)) + DATEDIFF(d,'17730101' ,isnull(EndDate,Startdate)) 
    -  ABS(DATEDIFF(d,isnull(Startdate,enddate),isnull(EndDate,Startdate))))
Run Code Online (Sandbox Code Playgroud)

测试数据

Create Table #DateData(ID int Identity, Name varchar(15),Startdate datetime,EndDate DateTime)
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-17 18:48:27','2015-04-18 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-19 18:48:27','2015-04-18 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-20 18:48:27','2015-04-18 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-11 18:48:27','2015-04-22 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-05-09 18:48:27','2015-04-18 18:48:27')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-17 19:07:38','2015-04-17 18:55:38')
Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-17 19:07:38','2015-05-12 18:56:29')
Run Code Online (Sandbox Code Playgroud)

完成查询

select *
from #DateData order by (DATEDIFF(d,'17730101' ,isnull(Startdate,enddate)) + DATEDIFF(d,'17730101' ,isnull(EndDate,Startdate)) 
-  ABS(DATEDIFF(d,isnull(Startdate,enddate),isnull(EndDate,Startdate))))
Run Code Online (Sandbox Code Playgroud)