【问题标题】:SQL Server Function for Maximum Date in Different Fields不同字段中最大日期的 SQL Server 函数
【发布时间】:2014-02-20 11:14:12
【问题描述】:

我在数据库中有多个相关表,每个表都可以单独更新,并有自己的 LastUpdated Date 字段。在这些表之一中,有多个 LastUpdated 字段,每个字段都指示该记录是从哪个源更新的。我们通常将这些多个表作为带有连接的单个项目进行查询,因此我想知道每条记录的最新 LastUpdated 记录在所有连接中是什么。我知道这可以通过许多子查询来实现,但我想知道是否有一些类似于 Coalesce 函数的东西可以传递许多字段并返回第一个非空值。

所以它会读成这样:

SELECT a.a_id, 
       a.name, 
       b.b_id, 
       b.detail, 
       c.c_id, 
       c.otherfield, 
       Maxdate(a.lastupdated, a.lastupdatedfromweb, b.lastupdated, 
       c.lastupdated) AS 
       LastUpdatedDate 
FROM   a 
       INNER JOIN b 
               ON a.a_id = b.a_id 
       INNER JOIN c 
               ON b.b_id = c.b_id 

有什么想法吗?这可以写成自定义函数还是存在于盒子中?如果有帮助,我正在开发 SQL Server 2005 和 2008。

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    在 2008+ 年,您可以使用 CROSS APPLY 为您的每个日期创建一行,然后选择 Max:

    SELECT 
     a.a_Id,
     a.Name,
     b.b_Id,
     b.Detail,
     c.c_Id,
     c.OtherField,
     ld.LastUpdatedDate
    FROM 
     a INNER JOIN b ON a.a_Id = b.a_Id 
       INNER JOIN c ON b.b_Id = c.b_Id
       CROSS APPLY
       (    SELECT  LastUpdatedDate = MAX(LastUpdatedDate)
            FROM    (VALUES
                        (a.LastUpdated), 
                        (a.LastUpdatedFromWeb), 
                        (b.LastUpdated), 
                        (c.LastUpdated)
                    ) d (LastUpdatedDate)
        ) ld
    

    您也可以将其作为关联子查询执行,但在优化期间 SQL Server 会将关联子查询重写为 OUTER APPLY,因此我更愿意只是跳出一步并自己编写 APPLY,因为我在 SQL 时发现了一些不寻常的行为解构相关子查询并将其重写为 APPLY。这方面的更多细节是described in this answer

    对于 2005 年,我认为您需要使用稍微不同的方法,因为它不支持表值构造函数:

    SELECT 
     a.a_Id,
     a.Name,
     b.b_Id,
     b.Detail,
     c.c_Id,
     c.OtherField,
     ld.LastUpdatedDate,
     (  SELECT  MAX(CASE Number 
                        WHEN 1 THEN a.LastUpdated
                        WHEN 2 THEN a.LastUpdatedFromWeb
                        WHEN 3 THEN b.LastUpdated
                        WHEN 4 THEN c.LastUpdated
                    END)
        FROM    (SELECT TOP 4 Number = ROW_NUMBER() OVER(ORDER BY object_id) 
                FROM sys.all_objects) n
    ) AS LastUpdated
    FROM 
     a INNER JOIN b ON a.a_Id = b.a_Id 
       INNER JOIN c ON b.b_Id = c.b_Id;
    

    或者:

    SELECT 
     a.a_Id,
     a.Name,
     b.b_Id,
     b.Detail,
     c.c_Id,
     c.OtherField,
     ld.LastUpdatedDate,
     (  SELECT  MAX(LastUpdated)
        FROM    (   SELECT a.LastUpdated UNION ALL
                    SELECT a.LastUpdatedFromWeb UNION ALL
                    SELECT b.LastUpdated UNION ALL
                    SELECT c.LastUpdated
                ) d
    ) AS LastUpdated
    FROM 
     a INNER JOIN b ON a.a_Id = b.a_Id 
       INNER JOIN c ON b.b_Id = c.b_Id;
    

    很遗憾,我不再安装任何 2005 实例,因此我无法对此进行测试。

    编辑

    刚刚意识到你也想要字段的来源,还记得2005确实支持使用APPLY,所以对于2008+:

    SELECT 
     a.a_Id,
     a.Name,
     b.b_Id,
     b.Detail,
     c.c_Id,
     c.OtherField,
     ld.LastUpdatedDate,
     ld.FieldName
    FROM 
     a INNER JOIN b ON a.a_Id = b.a_Id 
       INNER JOIN c ON b.b_Id = c.b_Id
       CROSS APPLY
       (    SELECT  TOP 1 LastUpdatedDate, FieldName
            FROM    (VALUES
                        (a.LastUpdated, 'a.LastUpdated'), 
                        (a.LastUpdatedFromWeb, 'a.LastUpdatedFromWeb'), 
                        (b.LastUpdated, 'b.LastUpdated'), 
                        (c.LastUpdated, 'c.LastUpdated')
                    ) d (LastUpdatedDate, FieldName)
            ORDER BY LastUpdated DESC
        ) ld
    

    2005 年:

    SELECT 
     a.a_Id,
     a.Name,
     b.b_Id,
     b.Detail,
     c.c_Id,
     c.OtherField,
     ld.LastUpdatedDate,
     ld.FieldName
    FROM 
     a INNER JOIN b ON a.a_Id = b.a_Id 
       INNER JOIN c ON b.b_Id = c.b_Id
       CROSS APPLY
       (    SELECT  TOP 1 LastUpdatedDate = LastUpdated, FieldName
            FROM    (
                        SELECT a.LastUpdated, FieldName = 'a.LastUpdated' UNION ALL
                        SELECT a.LastUpdatedFromWeb, 'a.LastUpdatedFromWeb' UNION ALL
                        SELECT b.LastUpdated, 'b.LastUpdated' UNION ALL
                        SELECT c.LastUpdated, 'c.LastUpdated'
                    ) d
            ORDER BY LastUpdated DESC
        ) ld
    

    【讨论】:

    • 在阅读之前,我实际上只是在此处尝试了您的最终建议(略有不同),它确实有效。我希望有一个速记的方法,但我想这会完成这项工作。感谢您的努力。
    【解决方案2】:
     SELECT 
     a.a_Id,
     a.Name,
     b.b_Id,
     b.Detail,
     c.c_Id,
     c.OtherField,
     MAX(SELECT a.LastUpdated, a.LastUpdatedFromWeb, b.LastUpdated, c.LastUpdated FROM a INNER JOIN b ON a.a_Id = b.a_Id INNER JOIN c ON b.b_Id = c.b_Id) AS LastUpdatedDate
    FROM 
     a INNER JOIN b ON a.a_Id = b.a_Id 
       INNER JOIN c ON b.b_Id = c.b_Id
    

    【讨论】:

    • 什么是aabbcc?为什么你认为 SQL Server 有一个 MAXDATE 函数(它没有)?
    • 这个答案我也有点困惑。
    猜你喜欢
    • 2012-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-12
    • 2010-10-07
    • 1970-01-01
    相关资源
    最近更新 更多