Этот ответ будет зависеть от использования таблицы чисел для генерации диапазона дат. Это может быть статически сгенерированная таблица чисел или CTE, однако из-за пределов рекурсии у CTE есть ограничения на число строк, которые вы можете сгенерировать.
Проверьте эти ссылки для получения информации о том, как построить таблицу чисел :
Stati c Таблица номеров
Последовательность номеров CTE
--SETUP FOR DEMO
DECLARE @tableX TABLE
(
Date DATETIME
,[Location] VARCHAR(1)
,DayOfWeekNumber INT
,DayofWeekName VARCHAR(10)
)
DECLARE @tableY TABLE
(
Date DATETIME
,[Location] VARCHAR(1)
,DayOfWeekNumber INT
,DayofWeekName VARCHAR(10)
)
INSERT INTO @tableX
VALUES
(43920,'X',DATEPART(DW,43920),DATENAME(DW,43920)),
(43921,'X',DATEPART(DW,43921),DATENAME(DW,43921)),
(43922,'X',DATEPART(DW,43922),DATENAME(DW,43922)),
(43923,'X',DATEPART(DW,43923),DATENAME(DW,43923)),
(43924,'X',DATEPART(DW,43924),DATENAME(DW,43924)),
--(43925,'X',DATEPART(DW,43925),DATENAME(DW,43925)),
--(43926,'X',DATEPART(DW,43926),DATENAME(DW,43926)),
(43927,'X',DATEPART(DW,43927),DATENAME(DW,43927)),
(43928,'X',DATEPART(DW,43928),DATENAME(DW,43928)),
(43929,'X',DATEPART(DW,43929),DATENAME(DW,43929)),
(43930,'X',DATEPART(DW,43930),DATENAME(DW,43930)),
(43931,'X',DATEPART(DW,43931),DATENAME(DW,43931)),
(43932,'X',DATEPART(DW,43932),DATENAME(DW,43932)),
(43933,'X',DATEPART(DW,43933),DATENAME(DW,43933)),
(43934,'X',DATEPART(DW,43934),DATENAME(DW,43934))
INSERT INTO @tableY
VALUES
(43920,'Y',DATEPART(DW,43920),DATENAME(DW,43920)),
(43921,'Y',DATEPART(DW,43921),DATENAME(DW,43921)),
(43922,'Y',DATEPART(DW,43922),DATENAME(DW,43922)),
(43923,'Y',DATEPART(DW,43923),DATENAME(DW,43923)),
(43924,'Y',DATEPART(DW,43924),DATENAME(DW,43924)),
--(43925,'Y',DATEPART(DW,43925),DATENAME(DW,43925)),
--(43926,'Y',DATEPART(DW,43926),DATENAME(DW,43926)),
--(43927,'Y',DATEPART(DW,43927),DATENAME(DW,43927)),
(43928,'Y',DATEPART(DW,43928),DATENAME(DW,43928)),
(43929,'Y',DATEPART(DW,43929),DATENAME(DW,43929)),
(43930,'Y',DATEPART(DW,43930),DATENAME(DW,43930)),
(43931,'Y',DATEPART(DW,43931),DATENAME(DW,43931)),
(43932,'Y',DATEPART(DW,43932),DATENAME(DW,43932)),
(43933,'Y',DATEPART(DW,43933),DATENAME(DW,43933)),
(43934,'Y',DATEPART(DW,43934),DATENAME(DW,43934))
--END SETUP FOR DEMO
--DECLARE YOUR RANGE
DECLARE @rangeStart DATETIME
DECLARE @rangeEnd DATETIME
DECLARE @dataSet TABLE
(
Date DATETIME
,[Location] VARCHAR(1)
,DayOfWeekNumber INT
,DayofWeekName VARCHAR(10)
)
--SIMPLE UNION ALL OF THE LOCATION TABLES IN QUESTION
--IF LOCATION CODE IS NOT ALREADY PART OF THE TABLE, YOU CAN DEFINE IT AS AN ADDITIONAL COLUMN IN YOUR STATEMENT
INSERT INTO @dataSet
select * from @tableX
UNION ALL
SELECT * from @tableY
SELECT @rangeStart = MIN(DATE) FROM @dataSet
SELECT @rangeEnd = MAX(Date) FROM @dataSet
--DEFINE YOUR BUSINESS DAYS FOR EACH LOCATION
DECLARE @locationsBusinessDays TABLE
(
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY
,LocationCode NVARCHAR(10)
,BusinessDay INT
)
--INSERT A RECORD FOR EACH LOCATION AND BUSINESS DAY FOR SAID LOCATION.
--THIS COULD BE A STATIC FACT TABLE IS YOU PREFER.
INSERT INTO @locationsBusinessDays
(
LocationCode
,BusinessDay
)
VALUES
('X', 2)
,('X', 3)
,('X', 4)
,('X', 5)
,('X', 6)
,('Y', 2)
,('Y', 3)
,('Y', 4)
,('Y', 5)
,('Y', 6)
,('Y', 7)
--USE THE NUMBERS TABLE TO GENERATE A LIST OF DATES, ONE FOR EACH LOCATION, WITHIN THE DEFINED RANGE
;with reportRange
as
(
select
CAST(Num as DATETIME) as DateStamp
,loc.LocationCode
,DATEPART(DW, n.num) As DayOfWeekNumber
,DATENAME(DW, n.Num) AS DayOfWeekName
FROM Numbers n
CROSS APPLY (SELECT DISTINCT LocationCode From @locationsBusinessDays) loc
WHERE n.Num >= @rangeStart ANd n.Num <= @rangeEnd
),
/*BRING ALL THE DATA BACK,
JOINING AGAINST YOUR BUSINESS DAYS FACT TABLE
AND YOUR MERGED DATASET
ANYTHING WITH A MISSING DATE BECAUSE OF THE LEFT JOIN ON THE MERGED DATASET
AS WELL AS BEING CONSIDERED A VALID BUSINESS DAY GET MARKED AS MISSING
*/
calcMissing
AS
(
SELECT r.*
,CASE WHEN b.Date IS NULL AND lbd.BusinessDay IS NOT NULL THEN 1 ELSE 0 END AS Missing
FROM reportRange r
left join @dataSet b on r.DateStamp = b.Date and r.LocationCode = b.Location
left join @locationsBusinessDays lbd on lbd.LocationCode = r.LocationCode AND r.DayOfWeekNumber = lbd.BusinessDay
)
--GROUP AS NECESSARY AND SUM THE MISSING DAYS
SELECT
MONTH(DateStamp) AS [Month]
,YEAR(DateStamp) AS [Year]
,LocationCode
,SUM(Missing) as MissingDays
FROM calcMissing
GROUP BY
MONTH(DateStamp)
,YEAR(DateStamp)
,LocationCode