如何选择最大日期早于某个值的行

Posted

技术标签:

【中文标题】如何选择最大日期早于某个值的行【英文标题】:How to select rows with max date older then some value 【发布时间】:2020-05-12 18:59:49 【问题描述】:

我有 Microsoft SQL Server 2008 和一个包含如下数据的表:

id | file_date [datatime] | file_path [varchar(255)]
____________________________________________________
1  |  01-01-1999          |   C:\f1.txt
2  |  01-01-2020          |   C:\f2.txt
3  |  05-05-1999          |   C:\f3.txt
4  |  05-05-2020          |   C:\f3.txt
5  |  05-05-1999          |   C:\f4.txt
6  |  06-05-1999          |   C:\f4.txt

我需要选择所有 file_paths,其中 file_date 是旧的,并且没有其他具有此 file_path 的行具有较新的 file_date强>存在

例如,如果我必须获取日期早于 2019 年的行,我的结果应该是这样的:

file_path
C:\f1.txt
C:\f4.txt

我有一个解决方案:

SELECT rslt.file_path
FROM mytable rslt
GROUP BY rslt.file_path
HAVING MAX(rslt.file_date) < '2019-01-01'

问题是这个脚本需要大约 2 分钟才能返回一个表中的大约 62k 行,其中我有 4460 万行,而简单的脚本来获取所有早于日期的行(见下文)需要 2-3秒

SELECT * FROM mytable WHERE file_date < '2019-01-01'

那么,有什么办法可以优化我的解决方案吗?

【问题讨论】:

【参考方案1】:

这需要多长时间?

SELECT t.file_path
FROM mytable t
WHERE NOT EXISTS (SELECT 1
                  FROM mytable t2
                  WHERE t2.file_path = t.file_path AND t2.file_date >= '2019-01-01'
                 );

您希望在(file_path, file_date) 上建立索引以获得最佳性能。

【讨论】:

【参考方案2】:

您能否否定第二个更快的查询并执行NOT IN

     SELECT rslt.file_path
     FROM mytable rslt
     WHERE rslt.file_path NOT IN
         (SELECT rslt2.file_path
          FROM mytable rslt2
          WHERE rslt2.file_path IS NOT NULL
          AND rslt2.file_date >= '2019-01-01')
     GROUP BY rslt.file_path;

NOT IN 似乎会在选择拉回空值时变得有点古怪,所以我也在内部查询的 where 中放了一个 IS NOT NULL,但你可能没有必要这样做。

【讨论】:

【参考方案3】:
DECLARE @TargetDate     date    =   '01-01-2019'
DECLARE     @PathList   TABLE   (id int, file_date datetime, file_path varchar(255))
INSERT INTO @PathList   VALUES
            (1, '01-01-1999', 'C:\f1.txt')
        ,   (2, '01-01-2020', 'C:\f2.txt')
        ,   (3, '05-05-1999', 'C:\f3.txt')
        ,   (4, '05-05-2020', 'C:\f3.txt')
        ,   (5, '05-05-1999', 'C:\f4.txt')
        ,   (6, '06-05-1999', 'C:\f4.txt')
;

SELECT  DISTINCT
        PL.file_path
FROM            @PathList   PL                                        
    LEFT JOIN   @PathList   PH  ON  PH.file_path =  PL.file_path    
                                AND PH.file_date >= @TargetDate 
WHERE   
            PL.file_date    <   @TargetDate 
        AND PH.id           IS  NULL

【讨论】:

JOIN 的诀窍是:排除那些路径相同但日期较新的路径。【参考方案4】:

检查一下

SELECT rslt.file_path, MAX(rslt.file_date) as Max_file_date
into #t
FROM mytable rslt
GROUP BY rslt.file_path

Select file_path 
From #t 
Where Max_file_date < '2019-01-01'

或者试试

SELECT rslt.file_path
into #t
FROM mytable rslt
WHERE file_date < '2019-01-01'
GROUP BY rslt.file_path

【讨论】:

以上是关于如何选择最大日期早于某个值的行的主要内容,如果未能解决你的问题,请参考以下文章

如何从计数中选择具有最大产生值的行

如何选择特定日期是不是早于 X 年? - 快速 SQL

POSTGRES:如何仅在另一个值不存在时选择具有某个值的行,在这种情况下选择另一个值?

如何选择具有最大值的行的所有列

如何根据创建标识符和最大日期的两列选择行

带有手动输入和动态最小日期的 jQuery UI 日期选择器