获取多个日期范围内缺少的日期

时间:2018-12-21 00:15:14

标签: sql sql-server gaps-and-islands

我有一个表,用于存储客户支持员工在特定位置的时间以及日期。每个单独的日期都是其自己的记录。

我还有第二张表,其中存储了客户要求现场支持的日期范围。

我需要提取给定位置没有任何支持代表的日期列表。我需要的只是位置和日期。我不在乎那个位置的哪个员工或哪个客户请求支持。

因此,在下面的示例数据中,我需要将其作为查询结果:

+--------+------------+
| London | 04/01/2019 |
| London | 07/01/2019 |
| Paris  | 05/01/2019 |
+--------+------------+

表:Employee_Location

+----------+----------+------------+
| Employee | Location |    Date    |
+----------+----------+------------+
|     1111 | London   | 01/01/2019 |
|     1111 | London   | 02/01/2019 |
|     1111 | London   | 03/01/2019 |
|     2222 | Paris    | 01/01/2019 |
|     2222 | Paris    | 02/01/2019 |
|     2222 | Paris    | 03/01/2019 |
|     2222 | Paris    | 04/01/2019 |
|     3333 | London   | 05/01/2019 |
|     3333 | Paris    | 06/01/2019 |
|     3333 | Paris    | 07/01/2019 |
|     4444 | London   | 06/01/2019 |
+----------+----------+------------+

表:Customer_Request

+----------+----------+---------------+------------+
| Customer | Location | Request From  | Request To |
+----------+----------+---------------+------------+
| AAAA     | London   | 01/01/2019    | 06/01/2019 |
| BBBB     | Paris    | 01/01/2019    | 06/01/2019 |
| CCCC     | London   | 05/01/2019    | 07/01/2019 |
+----------+----------+---------------+------------+

这是我当前的代码...

select c.CALENDARDTM 
from CALENDAR c, Employee_Location el 
join Customer_Request cron el.location = cr.location 
where c.CALENDARDTM NOT BETWEEN cr.RequestFrom and cr.RequestTo 
   and c.CALENDARDTM between '2019-01-01' AND '2019-01-07'

1 个答案:

答案 0 :(得分:0)

解决此问题的关键是创建一个记录集,其中包含指定的开始日期和结束日期之间的所有日期。

您可以使用多种方法来执行此操作,在下面的示例中,我使用了递归CTE,对于较大的数据集,您将需要对其进行一些微调。

一旦您拥有所有日期的列表,便可以将其与所有位置的列表结合起来,这样您就可以在所有位置拥有所有日期。

然后,删除与已存在的记录匹配的所有记录,在下面的示例中使用“不存在”,但是您可以使用多种方法来获得所需的结果。

CREATE TABLE #Employee_Location (Employee int, [Location] varchar(100), [date] date)

INSERT INTO #Employee_Location (Employee, [Location], [Date])
    VALUES   (1111,'London','2019-01-01')
            ,(1111,'London','2019-01-02')
            ,(1111,'London','2019-01-03')
            ,(2222,'Paris','2019-01-01')
            ,(2222,'Paris','2019-01-02')
            ,(2222,'Paris','2019-01-03')
            ,(2222 ,'Paris','2019-01-04')
            ,(3333,'London','2019-01-05')
            ,(3333,'Paris','2019-01-06')
            ,(3333,'Paris','2019-01-07')
            ,(4444,'London','2019-01-06')



DECLARE @StartDate  date    = '2019-01-01'
DECLARE @EndDate    date    = '2019-01-07'

;WITH Dates AS (
    SELECT @StartDate as d
    UNION ALL
    SELECT DateAdd(d, 1, d) as d
    FROM    Dates
    WHERE   d < @EndDate
)
,Locations AS (
    SELECT DISTINCT [Location]
    FROM #Employee_Location
)
,AllRecords AS (
    SELECT  d
            ,[Location]
    FROM    Dates
                FULL OUTER JOIN Locations
                    ON      1=1
)
SELECT  *
FROM    AllRecords
WHERE   NOT EXISTS (SELECT 1 
                    FROM    #Employee_Location  e
                    WHERE   e.[date] = Allrecords.d
                        AND e.[Location] = Allrecords.[Location])