我正在寻找一对将返回日期列表的 MAX 或 MIN 的 SQL 函数 (MS SQL Server)
Posted
技术标签:
【中文标题】我正在寻找一对将返回日期列表的 MAX 或 MIN 的 SQL 函数 (MS SQL Server)【英文标题】:I'm looking for a pair of SQL functions (MS SQL Server) that will return the MAX or MIN of a list of dates 【发布时间】:2021-01-15 09:31:46 【问题描述】:我正在寻找一对 SQL 函数,它们将返回日期列表的 MAX 和 MIN 值(或者,两个日期的 MAX 和 MIN - 然后我可以堆叠调用以处理整个列表)。我不能使用 MAX() 和 MIN() 函数(据我所知),因为这将返回特定列的最大值或最小值。我需要的是特定行的最大或最小列。
这里有一些示例数据来说明我在寻找什么:
当前查询结果:
MyID Date1 Date2 Date3 Date4
---------------------------------------------------------
ROW1 1/1/2019 4/23/2020 12/4/1980 5/2/2020
ROW2 6/3/2020 1/1/2020 5/3/2021 11/9/1998
ROW3 8/15/1980 7/4/2019 12/1/2030 1/2/2020
想要的查询结果:
MyID MaxDate MinDate
---------------------------------
ROW1 12/4/1980 5/2/2020
ROW2 11/9/1998 5/3/2021
ROW3 8/15/1980 12/1/2030
(这里,我有4个不同的日期列。根据我的实际情况,我需要筛选8个不同的列。)
理想情况下,我希望能够做这样的事情:
SELECT
MyID,
MIN(Date1, Date2, Date3, Date4),
MAX(Date1, Date2, Date3, Date4)
FROM ...
或者,如果有必要,我可以这样做:
SELECT
MyID,
MIN(Date1, MIN(Date2, MIN(Date3, Date4))),
MAX(Date1, MAX(Date2, MAX(Date3, Date4)))
FROM ...
显然,现有的 MIN 和 MAX 函数不能以这种方式工作。有替代功能吗?我可能可以构造某种 CASE 子句来做到这一点,但它看起来会很丑陋……使用嵌套的 IF 语句可能会更干净一些,尽管仍然很丑陋。在我发布这个之后,我会开始搞砸这个。我只是希望有一个更优雅、更清洁的解决方案。
【问题讨论】:
请用您正在运行的数据库标记您的问题。答案取决于供应商。 @GMB 你是对的 - 我应该包括我的平台。在这种情况下,我使用的是 MS SQL Server。 好的,所以你有比union all
更好的选择。看我的回答。
【参考方案1】:
标准的 SQL 解决方案是将所有日期合并
SELECT MyID, MAX(thedate ) AS maxdate, MIN(thedate ) AS mindate
FROM
(
SELECT MyID, Date1 AS thedate FROM table
UNION ALL
SELECT MyID, Date2 AS thedate FROM table
UNION ALL
SELECT MyID, Date3 AS thedate FROM table
UNION ALL
SELECT MyID, Date4 AS thedate FROM table
) T
GROUP BY MyID
可能有更好的其他具有窗口函数的解决方案,具体取决于您未指定的 RDBMS。但是这个应该适用于任何 RDBMS。
【讨论】:
【参考方案2】:大多数(但不是全部)数据库实际上支持least()
和greatest()
:
select t.*,
least(date1, date2, date3, date4) as min_date,
greatest(date1, date2, date3, date4) as max_date
from t;
唯一需要注意的是,如果 任何 值为 NULL
,则返回值为 NULL
。根据您问题中的示例数据,这似乎不是问题。
编辑:
在 SQL Server 上,您将取消透视并使用 apply
:
select t.*, v.*
from t cross apply
(select max(dte) as max_date, min(dte) as min_date
from (values (t.date1), (t.date2), (t.date3), (t.date4)) v(dte)
) v
【讨论】:
有人评论说我应该在我的标签中包含我的数据库平台——当然我应该想到这一点。我现在已经这样做了。这是在 SQL Server 上,“least()”不是现有函数。 @SeanWorle 。 . .我刚刚编辑了答案。这是一个比使用group by
的版本更有效的解决方案。是的,您应该标记数据库。我看到问题时,GMB 已经发表了评论。【参考方案3】:
在这里回答我自己的问题 - 经过大量挖掘后,我认为没有一个好的现有解决方案。所以我最终编写了自己的函数来处理这个问题。
以下是这些函数的代码:
CREATE FUNCTION dbo.maxDate(@date1 DATETIME, @date2 DATETIME) RETURNS DATETIME AS
BEGIN
DECLARE @result DATETIME
IF @date1 > @date2 SET @result = @date1
ELSE SET @result = @date2
RETURN @result
END
go
CREATE FUNCTION dbo.minDate(@date1 DATETIME, @date2 DATETIME) RETURNS DATETIME AS
BEGIN
DECLARE @result DATETIME
IF @date1 < @date2 SET @result = @date1
ELSE SET @result = @date2
RETURN @result
END
go
这样就可以进行类似于我的问题中的第二个建议的查询:
SELECT
MyID,
dbo.minDate(Date1, dbo.minDate(Date2, dbo.minDate(Date3, Date4))),
dbo.maxDate(Date1, dbo.maxDate(Date2, dbo.maxDate(Date3, Date4)))
FROM ...
【讨论】:
【参考方案4】:在 SQL Server 中,least()
和 greatest()
不可用,我建议使用横向连接将列取消透视到行,然后进行聚合以提取最小值和最大值:
select t.myid, x.*
from mytable t
cross apply (
select max(dt) maxdate, min(dt) mindate
from (values (date1), (date2), (date3)) x(dt)
) x
这比union
更有效,因为它只扫描表一次(而不是每个union
成员一次)。
【讨论】:
以上是关于我正在寻找一对将返回日期列表的 MAX 或 MIN 的 SQL 函数 (MS SQL Server)的主要内容,如果未能解决你的问题,请参考以下文章
返回 MIN 和 MAX 值并忽略空值 - 使用前面的非空值填充空值
Access SQL:无法使用 Max() 和 Min() 值更新列表
我可以以某种方式从java中的Collections.Min / Collections.Max中排除或过滤掉一个值吗?