不同字段中最大日期的SQL Server函数

时间:2014-02-20 11:14:12

标签: sql sql-server

我在数据库中有多个相关表,每个表都可以单独更新并拥有自己的LastUpdated Date字段。在其中一个表中,有多个LastUpdated字段,每个字段指示该记录的更新源。我们通常将这些多个表作为带有连接的单个项进行查询,因此我想知道每条记录中所有连接中最近的LastUpdated记录是什么。我知道这可以通过许多子查询来实现,但我想知道是否存在Coalesce函数的某些内容,您可以将许多字段传递给它并返回第一个非null值。

所以它会读起来像:

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,如果这有帮助的话。

2 个答案:

答案 0 :(得分:2)

在2008年以上,您可以使用CROSS APPLY为每个日期创建一行,然后选择最大值:

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

答案 1 :(得分:0)

 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