仅计算MS Access中的连续日期

时间:2014-06-17 08:58:36

标签: sql ms-access

我试图查询计算某些客户的连续逾期天数。我还有一个识别客户的主键。

样本表

Date (d.m.y)     Name 
01.01.2014       Alex
02.01.2014       Alex
03.01.2014       Alex
01.01.2014       Bianca
02.01.2014       Bianca
08.07.2014       Alex
09.07.2014       Alex
10.07.2014       Alex
11.07.2014       Alex

如何区分名称,只计算制作SELECT COUNT()的连续日期?

Desired Result
Name     Overdue Day Count   Date
Alex          3              01.01.2014  <== The date is the first overdue date
Bianca        2              01.01.2014
Alex          4              08.07.2014

2 个答案:

答案 0 :(得分:3)

这是一个gaps and islands problem(特别是岛屿) - 不幸的是我认为访问中唯一支持的解决方案效率非常低:

SELECT  Name, 
        COUNT(*) AS Days,
        MIN(Date) AS FirstDate, 
        MAX(Date) AS LastDate
FROM    (   SELECT  Name,
                    Date,
                    (   SELECT  MIN(B.Date)
                        FROM    T AS B
                        WHERE   B.Date >= A.Date
                        AND     B.Name = A.Name
                        AND     NOT EXISTS
                                (   SELECT  1
                                    FROM    T AS C
                                    WHERE   C.Name = B.Name
                                    AND     C.Date = B.Date + 1
                                )
                    ) AS grp
            FROM    T AS A
        ) AS D
GROUP BY Name, grp;

上面链接的文章中有完整的解释,但用于创建列grp的子查询找到每个特定岛的末尾,然后此值可用于对外部查询进行分组。

答案 1 :(得分:2)

使用[NOT] EXISTS的查询可能会很慢,因此这里的解决方案可能运行得更快。

我们首先创建一个查询,按名称

查找每个连续日期组的开始日期
SELECT t1.Date, t1.Name
FROM 
    T AS t1 
    LEFT JOIN 
    T AS t2 
        ON t1.Name=t2.Name 
            AND t1.Date=DateDiff("d",-1,t2.Date)
WHERE t2.Date IS NULL

它给了我们

Date        Name  
----------  ------
2014-01-01  Alex  
2014-01-01  Bianca
2014-07-08  Alex  

我们可以使用不等连接

将该查询链接回主表
SELECT t3.Date, t3.Name
FROM
    T AS t3
    INNER JOIN
    (
        SELECT t1.Date, t1.Name
        FROM 
            T AS t1 
            LEFT JOIN 
            T AS t2 
                ON t1.Name=t2.Name 
                    AND t1.Date=DateDiff("d",-1,t2.Date)
        WHERE t2.Date IS NULL
    ) AS StartDates
        ON t3.Name=StartDates.Name AND t3.Date>=StartDates.Date

生成以下内容,为每个连续的组重复行

Date        Name  
----------  ------
2014-01-01  Alex  
2014-01-02  Alex  
2014-01-03  Alex  
2014-01-01  Bianca
2014-01-02  Bianca
2014-07-08  Alex  
2014-07-08  Alex  
2014-07-09  Alex  
2014-07-09  Alex  
2014-07-10  Alex  
2014-07-10  Alex  
2014-07-11  Alex  
2014-07-11  Alex  

因此,如果我们将其调整为聚合查询,我们可以为原始表中的每一行分配一个组号

SELECT t3.Date, t3.Name, COUNT(*) AS GroupNo
FROM
    T AS t3
    INNER JOIN
    (
        SELECT t1.Date, t1.Name
        FROM 
            T AS t1 
            LEFT JOIN 
            T AS t2 
                ON t1.Name=t2.Name 
                    AND t1.Date=DateDiff("d",-1,t2.Date)
        WHERE t2.Date IS NULL
    ) AS StartDates
        ON t3.Name=StartDates.Name AND t3.Date>=StartDates.Date
GROUP BY t3.Date, t3.Name

导致

Date        Name    GroupNo
----------  ------  -------
2014-01-01  Alex          1
2014-01-02  Alex          1
2014-01-03  Alex          1
2014-01-01  Bianca        1
2014-01-02  Bianca        1
2014-07-08  Alex          2
2014-07-09  Alex          2
2014-07-10  Alex          2
2014-07-11  Alex          2

最后,我们可以将整个事物包装在另一个聚合查询中

SELECT 
    Grouped.Name, 
    COUNT(*) AS DaysOverdue,
    MIN(Grouped.Date) AS OverdueSince
FROM
    (
        SELECT t3.Date, t3.Name, COUNT(*) AS GroupNo
        FROM
            T AS t3
            INNER JOIN
            (
                SELECT t1.Date, t1.Name
                FROM 
                    T AS t1 
                    LEFT JOIN 
                    T AS t2 
                        ON t1.Name=t2.Name 
                            AND t1.Date=DateDiff("d",-1,t2.Date)
                WHERE t2.Date IS NULL
            ) AS StartDates
                ON t3.Name=StartDates.Name AND t3.Date>=StartDates.Date
        GROUP BY t3.Date, t3.Name
    ) AS Grouped
GROUP BY Grouped.Name, Grouped.GroupNo
ORDER BY 3, 1

产生最终结果

Name    DaysOverdue  OverdueSince
------  -----------  ------------
Alex              3  2014-01-01  
Bianca            2  2014-01-01  
Alex              4  2014-07-08