【问题标题】:How to SELECT records using MIN and MAX when multiple records exist?存在多条记录时如何使用 MIN 和 MAX 选择记录?
【发布时间】:2014-06-05 20:11:50
【问题描述】:

我有两个 SQL Server 表。第一个表是客户表,包含客户编号、姓名等。第二个表包含客户的服务日期。客户可以有多个服务日期。以下是服务日期表的示例:

custnmbr     DateIn       DateOut
------------------------------------    
78001       1991-02-10    2001-12-07
78001       2002-08-03    2003-06-17  
78001       2006-11-22    NULL   

我想选择最早的 DateIn 和最近的 DateOut。在上面的示例中,我希望将 DateIn 返回为 1991-02-10,并且由于客户当前处于活动状态,因此我希望将 DateOut 返回为 NULL。

这是我尝试过的,但没有运气

SELECT  
    SM.Custnmbr, 
    CONVERT (VARCHAR(10), MAX(LH.DateIn), 101) AS DateIn, 
    CONVERT (VARCHAR(10), MAX(LH.DateOut), 101) AS DateOut, 
FROM    
    dbo.toCustomer SM
LEFT OUTER JOIN 
    dbo.toLocCustHist LH ON SM.CustomerId = LH.CustomerId
GROUP BY    
    SM.CustNmbr, SM.CustName, LH.LocationId

当我运行查询时,DateIn 是正确的 1991-02-10,但 DateOut 是 2003-06-17,这是错误的。

【问题讨论】:

    标签: sql sql-server sql-server-2008


    【解决方案1】:

    NULL 值不在聚合函数中考虑,因此您需要将 NULL 设置为其他值,并且您的 GROUP BY 语句中不应包含额外的元素:

    SELECT  
        SM.Custnmbr, 
        CONVERT (VARCHAR(10), MAX(LH.DateIn), 101) AS DateIn, 
        CONVERT (VARCHAR(10), MAX(ISNULL(LH.DateOut,'2099-01-01'), 101) AS DateOut, 
    FROM    
        dbo.toCustomer SM
    LEFT OUTER JOIN 
        dbo.toLocCustHist LH ON SM.CustomerId = LH.CustomerId
    GROUP BY    
        SM.CustNmbr
    

    【讨论】:

    • group by 中的额外元素可能是相关的,具体取决于整个查询的样子。例如,如果几个人在多个地点工作,并且他们在每个地点使用不同的机器会怎样。也许我们想要与每个位置相关的数据,但我们并不关心位置本身。将客户名称包含在 group by 中是合适的,但不要包含在 select 中。
    • @Jenn 我不确定在什么情况下多次显示相同的Custnmbr 以及无法相互区分的相关MAX() 日期会有所帮助,但可能会有一个案例。
    • 这种情况很少见,我认为我的示例不能完全涵盖它。我见过用作摘要的存储过程,他们使用了这个技巧。例如,也许我正在撤回一份摘要,该摘要通知 IT 部门过去一年中维修过的机器数量以及解决问题所花费的平均时间。在这种情况下,group by 中很可能有一些列不在 select 中。
    【解决方案2】:
    WITH TEMP AS
    (
    SELECT  SM.Custnmbr AS Custnmbr, 
    CONVERT (VARCHAR(10), MIN(LH.DateIn), 101) AS DateIn, 
    CONVERT (VARCHAR(10), MAX(ISNULL(LH.DateOut,'9999-12-12')), 101) AS DateOut, 
    FROM    dbo.toCustomer SM
    LEFT OUTER JOIN dbo.toLocCustHist LH ON SM.CustomerId = LH.CustomerId
    GROUP BY    SM.CustNmbr, SM.CustName, LH.LocationId
    )
    SELECT Custnmbr,DateIn,
    CASE WHEN DateOut='9999-12-12' THEN NULL
    ELSE DateOut
    END
    FROM TEMP;
    

    【讨论】:

      【解决方案3】:

      SQL 不认为 N​​ULL 日期大于 2003-06-17。您需要将 NULL 替换为遥远的未来占位符日期,以便 MAX() 选择它。

      SELECT  SM.Custnmbr, 
      CONVERT (VARCHAR(10), MAX(LH.DateIn), 101) AS DateIn, 
      CONVERT (VARCHAR(10), MAX(ISNULL(LH.DateOut,'99991231'), 101) AS DateOut, 
      FROM    dbo.toCustomer SM
      LEFT OUTER JOIN dbo.toLocCustHist LH ON SM.CustomerId = LH.CustomerId
      GROUP BY    SM.CustNmbr, SM.CustName, LH.LocationId
      

      如果您想显示当前日期(即GETDATE())而不是 9999-12-31,您可以使用 CASE 语句。

      【讨论】:

        猜你喜欢
        • 2015-09-03
        • 2014-10-16
        • 1970-01-01
        • 1970-01-01
        • 2017-03-02
        • 1970-01-01
        • 2023-03-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多