Ключом к решению этой проблемы является создание набора записей, который содержит все даты между назначенными датами начала и окончания.
Существует множество методов, которые можно использовать для этого, в приведенном ниже примере IВы использовали рекурсивный CTE, для больших наборов данных вам нужно будет немного его настроить.
После того, как у вас есть список всех дат, вы объединяете его со списком всех местоположений, поэтому у вас есть все даты на всехlocation.?
Затем вы удаляете все записи, которые соответствуют уже существующим записям, в примере ниже используется «Not Exists», но вы можете использовать различные подходы, чтобы получить желаемый результат.
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])