【问题标题】:choose minimum date from a record out of multiple columns从多列的记录中选择最小日期
【发布时间】:2021-02-24 19:34:03
【问题描述】:

您好,我有以下表格结构:

Person    Date1             Date2............Daten
------    -----             -----            -----
1         2001-01-01        2002-01-01
2         2003-01-01        2000-01-01

我想选择 Date1 和 Date(n) 之间的最小日期(在我的情况下为 20 个日期)。例如,它会为 Person1 选择 Date1,为 Person2 选择 Date2。

显然,如果我只有 1 个日期列,我可以只使用 min(Date),但在这种情况下我无法正确理解我的逻辑。

非常感谢。

【问题讨论】:

  • 日期字段代表什么?
  • LEAST(MIN(date1) , MIN(date2) )
  • 我能想到两种解决方案,但没有一种是真正令人愉快的,而且都会有与之相关的维护问题。用例是什么,日期代表什么?如果日期在语义上是等效的,那么它们应该表示为行而不是列...

标签: sql db2


【解决方案1】:
SELECT person AS the_person
  , LEAST(date1 ,date2, date3, date4, date5, ..., dateN ) AS the_date
FROM the_table ;

Least() 应该忽略 NULL(如果存在)。 (以上适用于 Postgres)

UPDATE(感谢@WarrenT)显然DB2 没有LEAST(),但它确实有MIN()(有多个参数)。

SELECT person AS the_person
  , MIN(date1 ,date2, date3, date4, date5, ..., dateN ) AS the_date
FROM the_table ;

【讨论】:

  • 优秀——至少不会忽略空值——至少没有任何额外的参数。
  • 取决于平台。 least() 是非标准的,但却是一个常见的扩展。 Postgresql 忽略 NULL。如果没有:可能还有其他变体可用(显然使用不同的名称),否则您需要在日期中添加一堆 COALESCE (date1, -infinity )s。
  • 啊,我明白了。我正在使用 DB2,所以这是有道理的。只是出于兴趣,我可以使用什么函数来挑选列中某个日期以上的任何字段?即如果 3 个日期中只有 2 个大于 2000-01-01,那么我只带回这两个字段。
  • 如果我理解正确,那至少需要一个三元运算符/函数。我不知道它是否存在;这将是非常不标准的。否则,你将不得不自己编写一个丑陋的 CASE ... WHEN ... 构造。
  • 取决于 DB2 平台。 least() 目前在 DB2 for z/OS 和 DB2 for i 上不可用。使用min()。它做同样的事情。它们是同义词,但min() 是可移植的。也少打字;-)
【解决方案2】:

没有评论真正糟糕的架构(它违反了正常形式的规则 - 我认为它被称为没有重复组),
我知道的唯一方法是使用 case 语句

 Select case 
       When Date1 < Date2 And Date1 < date3 and date1 < date4 and ... Then date1
       When Date2 < Date1 And Date2 < date3 and date2 < date4 and ... Then date2
       When Date3 < Date1 And Date3 < date2 and date3 < date4 and ... Then date3
       When Date4 < Date1 And Date4 < date2 and date4 < date3 and ... Then date4
       ...
       End as MinDate
 From table        

【讨论】:

  • 在我看到 widplasser 的回答之前,这也是我能想到的唯一方法。
【解决方案3】:

SQL: 使用此函数获取最多四个日期之间的最小日期,如果您想找到两列的最小值,只需为 date3 和 date4 传递 null。

--Use this function to get least date 
--SELECT dbo.GetLeastDate('2021-01-19 01:09:28.997', '2021-01-19 01:07:28.997', '2021-01-19 00:02:28.997', '2021-01-19 02:05:28.997') as theDate  
--SELECT dbo.GetLeastDate('2021-01-19 01:09:28.997', '2021-01-19 01:07:28.997', '2021-01-19 02:05:28.997', null) as theDate  
--SELECT dbo.GetLeastDate('2021-01-19 01:09:28.997', '2021-01-19 01:07:28.997', null, null) as theDate  
--SELECT dbo.GetLeastDate('2021-01-19 01:09:28.997', null, null, null) as theDate  
CREATE OR ALTER FUNCTION [dbo].[GetLeastDate]
(
    @d1 datetime,
    @d2 datetime,
    @d3 datetime,
    @d4 datetime
)
RETURNS datetime
AS
BEGIN
    DECLARE @least datetime

    IF @d1 is null
       and @d2 is null
       and @d3 is null
        RETURN null

    Set @d1 = Isnull(@d1, getDate())
    Set @d2 = Isnull(@d2, getDate())
    Set @d3 = Isnull(@d3, getDate())
    Set @d4 = Isnull(@d4, getDate())
    
    IF @d1 < @d2 and @d1 < @d3 and @d1 < @d4
        SET @least = @d1
    ELSE IF @d2 < @d1 and @d2 < @d3 and @d2 < @d4
        SET @least = @d2
    ELSE IF @d3 < @d1 and @d3 < @d2 and @d3 < @d4
        SET @least = @d3
    ELSE
        SET @least = @d4

    RETURN @least
END

【讨论】:

  • 仅当任何非空输入参数在过去时,建议的解决方案才会返回正确答案。否则返回当前日期(如果所有非空输入值都在未来)。这不是OP所要求的。您能否更新您的答案或(至少)记录特殊情况?
猜你喜欢
  • 1970-01-01
  • 2011-07-18
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多