按两列的最小值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不是通用的。 它有重要的限制:
- 如果列是
Date
types(如果使用01/01/1753
之前的date),则01/01/1753
。 - 如果其中一列是
NULL
,它将不起作用。 它将NULL
值解释为最小datetime
值。 但是这是真的吗? 这是不是datetime
,这是什么。 - 如果我们使用两个以上的列,
IF
expression式将会复杂得多 。
根据这个问题:
这种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))
这个代码的输出如下:
COALESCE
解决scheme 不会以这种方式对表格进行sorting。 它混淆了至less有一个NULL
值的单元格的行。 它的输出如下:
希望这有助于和等待批评。
这可能是一个不需要像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其中一个列) – 由触发器维护,或者如果意义足够独立,列可能在某些情况下不可能被手动维护。
我认为当你想在date1
和date2
两个字段上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
- 当两者都为空时
- 当date1为空时
- 当date2为空时
- 分钟(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问题