我使用SQL Server 2008 R2
。
我需要按两列的最小值对表进行排序。
表格如下:
ID: integer;
Date1: datetime;
Date2: datetime.
我希望我的数据按最少两个日期排序。
以这种方式对此表进行排序的最简单方法是什么?
答案 0 :(得分:57)
非空列。您需要在 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 标准日期格式1753-01-01
here。
答案 1 :(得分:33)
在CASE
:
ORDER BY
表达式
ORDER BY case when date1 < date2 then date1 else date2 end
修改强>
如果需要考虑空值,请添加coalesce()
:
ORDER BY case when date1 < date2 then date1 else coalesce(date2,date1) end
说明:
如果date1&lt; date2然后按date1排序。 (这里的两个日期都是非空的。)就像以前一样工作。
否则使用COALESCE()
按date2(当date2不为null时)或date1(当date2为null时)或null(如果两个日期都为空)。
答案 2 :(得分:8)
最简单的方法是使用VALUES
关键字,如下所示:
SELECT ID, Date1, Date2
FROM YourTable
ORDER BY (SELECT MIN(v) FROM (VALUES (Date1), (Date2)) AS value(v))
此代码适用于所有情况,即使使用可空列也是如此。
修改:
带有COALESCE
关键字的The solution不是通用的。它有重要的限制:
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))
此代码的输出如下:
COALESCE
solution 不会以这种方式对表格进行排序。它弄乱至少有一个NULL
值单元格的行。它的输出如下:
希望这有助于等待批评者。
答案 3 :(得分:5)
如果您不想在Case statement
中使用Order By
,那么这是另一种方法,只需将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
答案 4 :(得分:5)
这可能是一种替代解决方案,不需要像CASE WHEN
这样的分支。这基于here所述的公式max(a,b)=1/2(a+b+|a−b|)
。我们使用DATEDIFF
和参考日期('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))))
测试数据
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))))
答案 5 :(得分:4)
我更喜欢这种方式来处理可空列:
SELECT Id, Date1, Date2
FROM YourTable
ORDER BY
CASE
WHEN Date1 < Date2 OR Date1 IS NULL THEN Date1
ELSE Date2
END
答案 6 :(得分:4)
我正在使用CROSS APPLY
,我不确定效果,但CROSS APPLY
通常会有更好的表现。
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
答案 7 :(得分:2)
我认为,当您要对date2
和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
结果将如下:
cout << ch1 << '\t' << ch2 << ch3;
答案 8 :(得分:2)
我将焦点从如何转移到为什么你需要这个 - 并建议改变架构。经验法则是:如果您需要拉动特技来访问您的数据,那么设计决定就会很糟糕。
正如您所见,此任务对于SQL来说非常不典型,因此尽管可能,但与普通ORDER BY
相比,所有提议的方法都非常缓慢。
答案 9 :(得分:1)
我会按照这条规则订购行:
为此,嵌套的案例将简单有效(除非表格非常大)according to this post。
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
答案 10 :(得分:1)
还有另一种选择。您可以根据需要的逻辑计算结果列,并按列排序选择外部列。在这种情况下,代码如下:
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
此解决方案的好处是您可以添加必要的过滤查询(在内部选择中),但索引仍然有用。
答案 11 :(得分:0)
您可以在min
子句中使用order by
函数:
select *
from [table] d
order by ( select min(q.t) from (
select d.date1 t union select d.date2) q
)
你也可以在case
子句中使用order by
语句,但是你知道比较(>
和<
)任何值(null或none null)的结果即使您已将true
设置为ansi_nulls
,null也不会为off
。因此,为了保证您想要的排序,您需要处理null
,如case
子句中when
true
的结果为when
然后进一步{{1}没有评估语句,所以你可以说:
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
如果您的场景不同,这里还有一些其他解决方案,也许您可以评估在分离字段内比较多列(或计算)的结果,最后按计算字段排序,而不使用order by子句中的任何条件。
答案 12 :(得分:0)
SELECT ID, Date1, Date2
FROM YourTable
ORDER BY (SELECT TOP(1) v FROM (VALUES (Date1), (Date2)) AS value(v) ORDER BY v)
非常类似@dyatchenko答案,但没有NULL问题