按两列的最小值sorting

我使用SQL Server 2008 R2

我需要通过两列的最小值对表格进行sorting。

表格看起来像这样:

 ID: integer; Date1: datetime; Date2: datetime. 

我希望我的数据按照最less两个datesorting。

这种sorting方式最简单的方法是什么?

NOT NULL列 。 您需要将CASE语句添加到以下的ORDER BY子句中:

 SELECT Id, Date1, Date2 FROM YourTable ORDER BY CASE WHEN Date1 < Date2 THEN Date1 ELSE Date2 END 

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 

你可以在这里阅读关于ANSI标准的dateformat 1753-01-01

ORDER BY使用CASE

  ORDER BY case when date1 < date2 then date1 else date2 end 

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

 SELECT ID, Date1, Date2 FROM YourTable ORDER BY (SELECT MIN(v) FROM (VALUES (Date1), (Date2)) AS value(v)) 

这个代码适用于所有的情况,甚至可以使用列。

编辑:

COALESCE关键字的解决scheme不是通用的。 它有重要的限制:

  • 如果列是Datetypes(如果使用01/01/1753之前的date),则01/01/1753
  • 如果其中一列是NULL ,它将不起作用。 它将NULL值解释为最小datetime值。 但是这是真的吗? 这是不是datetime ,这是什么。
  • 如果我们使用两个以上的列, IFexpression式将会复杂得多

根据这个问题:

这种sorting方式最简单的方法是什么?

最简单和最简单的解决scheme就是上面描述的那个,因为:

  • 它不需要太多的编码来实现它 – 只需添加一行。
  • 不需要关心列是否可以空。 你只是使用代码,它的工作原理。
  • 只需在逗号后面添加一个, 就可以扩展查询中的列数。
  • 适用Date列,您不需要修改代码。

编辑2:

Zohar Peledbuild议采取以下的方式:

我会按这个规则sorting行:首先,当null,second,date1为null时,third,date 2为null时,第四,min(date1,date2)

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

 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)) 

这个代码的输出如下:

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

COALESCE 解决scheme 不会以这种方式对表格进行sorting。 它混淆了至less有一个NULL值的单元格的行。 它的输出如下:

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

希望这有助于和等待批评。

这可能是一个不需要像CASE WHEN那样分支的替代解决scheme。 这是基于这里描述的公式max(a,b)=1/2(a+b+|a−b|) 。 我们使用DATEDIFF和参考date( '1773-01-01' )得到a和b的绝对值。

 ORDER BY (DATEDIFF(d,'17730101' ,isnull(Startdate,enddate)) + DATEDIFF(d,'17730101' ,isnull(EndDate,Startdate)) - ABS(DATEDIFF(d,isnull(Startdate,enddate),isnull(EndDate,Startdate)))) 

testing数据

 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') 

完整的查询

 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)))) 

如果您不想在Order By使用Case statement ,那么这是另一种方法,只需将Case statement移动到Select

 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 

我更喜欢这种方式来处理可空列:

 SELECT Id, Date1, Date2 FROM YourTable ORDER BY CASE WHEN Date1 < Date2 OR Date1 IS NULL THEN Date1 ELSE Date2 END 

代码为最大

我正在使用CROSS APPLY ,我不确定其性能,但CROSS APPLY在我的经验中往往有更好的performance。

 CREATE TABLE #Test (ID INT, Date1 DATETIME, Date2 DATETIME) INSERT INTO #Test SELECT 1, NULL, '1/1/1';INSERT INTO #Test SELECT 2, NULL, NULL;INSERT INTO #Test SELECT 3, '2/2/2', '3/3/1';INSERT INTO #Test SELECT 4, '3/3/3', '11/1/1' SELECT t.ID, Date1, Date2, MinDate FROM #TEST t CROSS APPLY (SELECT MIN(d) MinDate FROM (VALUES (Date1), (Date2)) AS a(d)) md ORDER BY MinDate DROP TABLE #Test 

我会把重点从如何做到这一点, 为什么你需要这个 – 并build议改变模式。 经验法则是:如果您需要拉动特技来访问您的数据,那么就会有一个糟糕的devise决定。

正如你所看到的,这个任务对于SQL来说是非常不典型的,尽pipe这是可能的,但是与普通的ORDER BY相比,所有提出的方法都是痛苦的缓慢。

  • 如果您需要经常这样做,那么这两个date中的最小值对于您的应用程序必须具有一些独立的物理意义。
    • 这certificate了一个单独的列(或者可能是一个列replace其中一个列) – 由触发器维护,或者如果意义足够独立,列可能在某些情况下不可能被手动维护。

我认为当你想在date1date2两个字段上sorting时,你应该在ORDER BY部分中包含它们,就像这样:

 SELECT * FROM aTable ORDER BY CASE WHEN date1 < date2 THEN date1 ELSE date2 END, CASE WHEN date1 < date2 THEN date2 ELSE date1 END 

结果可以是这样的:

 date1 | date2 -----------+------------ 2015-04-25 | 2015-04-21 2015-04-26 | 2015-04-21 2015-04-25 | 2015-04-22 2015-04-22 | 2015-04-26 

要有一个完美的结果与Null值使用:

 SELECT * FROM aTable ORDER BY CASE WHEN date1 IS NULL THEN NULL WHEN date1 < date2 THEN date1 ELSE date2 END ,CASE WHEN date2 IS NULL THEN date1 WHEN date1 IS NULL THEN date2 WHEN date1 < date2 THEN date2 ELSE date1 END 

结果会是这样的:

 date1 | date2 -----------+------------ NULL | NULL NULL | 2015-04-22 2015-04-26 | NULL 2015-04-25 | 2015-04-21 2015-04-26 | 2015-04-21 2015-04-25 | 2015-04-22 

还有一个select。 您可以根据需要的逻辑来计算结果列,并按照您的列进行sorting来覆盖外部列表。 在这种情况下,代码如下:

 select ID, x.Date1, x.Date2 from ( select ID, Date1, Date2, SortColumn = case when Date1 < Date2 then Date1 else Date2 end from YourTable ) x order by x.SortColumn 

这个解决scheme的好处是,你可以添加必要的过滤查询(在内部select),仍然索引将是有用的。

我会按这个规则sorting

  1. 当两者都为空时
  2. 当date1为空时
  3. 当date2为空时
  4. 分钟(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, CASE WHEN Date1 < Date2 THEN Date1 ELSE Date2 END 

您可以按条件使用min函数:

 select * from [table] d order by ( select min(qt) from ( select d.date1 t union select d.date2) q ) 

您还可以order by子句的order by使用case语句,但是如果您知道使用null比较( >< )任何值(null或none null)的结果是不true即使您已将ansi_nulls设置为off 。 所以为了保证你想要的types,你需要处理null ,正如你在case子句中所知道的,如果when的结果是true那么when语句不被评估的时候,你可以说:

 select * from [table] order by case when date1 is null then date2 when date2 is null then date1 when date1<date2 then date1 -- surely date1 and date2 are not null here else date2 end 

此外,这里有一些其他的解决scheme,如果你的情况是不同的也许也许你评估比较多个列(或一个计算)在一个分离的领域内的结果,并最终命令的计算字段,而不使用任何条件,

 SELECT ID, Date1, Date2 FROM YourTable ORDER BY (SELECT TOP(1) v FROM (VALUES (Date1), (Date2)) AS value(v) ORDER BY v) 

非常类似于@dyatchenko答案但没有NULL问题