@ Лукаш Шозда украл мой гром.Мой ответ похож, но не использует переменные (я не предполагаю, хорошо это или плохо .. просто выкрикиваю).
Вы можете создать функцию таблицы календаря (см. Пример ниже), а затем выполнить LEFT ANTI SEMI JOIN
для своей таблицы рабочих дней.Преимуществом этого решения является то, что календарная таблица генерирует 0 IO.
Решение:
WITH r(L,H) AS
(
SELECT CAST(MIN(w.workingdatestart) AS DATE), CAST(MAX(w.workingdateend) AS DATE)
FROM dbo.workingdates AS w
),
cal AS
(
SELECT c.Dt
FROM r
CROSS APPLY dbo.calendar(r.L,r.H) AS c
)
SELECT c.Dt
FROM cal AS c
EXCEPT
SELECT c.Dt
FROM cal AS c
JOIN dbo.workingdates AS w
ON c.Dt BETWEEN w.workingdatestart AND w.workingdateend;
.. и функция:
CREATE FUNCTION dbo.calendar(@startdate DATE, @enddate DATE)
RETURNS TABLE WITH SCHEMABINDING AS RETURN
WITH E1(N) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS x(x)),
iTally(N) AS
(
SELECT 0 UNION ALL
SELECT TOP (DATEDIFF(DAY,@startDate,@endDate)) ROW_NUMBER() OVER (ORDER BY (SELECT 1))
FROM E1 a, E1 b, E1 c
)
SELECT sortKey = i.N, Dt = DATEADD(DAY, i.N, @startDate)
FROM iTally AS i;