【问题标题】: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'

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

【问题讨论】:

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


    【解决方案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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-06
          • 1970-01-01
          • 1970-01-01
          • 2022-07-22
          • 1970-01-01
          • 2016-12-30
          • 2020-01-18
          • 2022-01-03
          相关资源
          最近更新 更多