Я думаю, что вы, вероятно, захотите настоящую таблицу календаря, чтобы вы могли учитывать выходные и праздничные дни. Но это вернет результаты, которые вы ищете. Я сделал это достаточно гибким, чтобы работать в течение нескольких месяцев. Я использую cte в качестве таблицы подсчета, которая делает недолгой работу такого рода вещей. Обратите внимание, что я добавил вторую строку для WorkerID xxxx с несколькими месяцами.
declare @Something table
(
WorkerID char(4)
, StartDate date
, EndDate date
)
insert @Something values
('0001', '20191129', '20191203')
, ('xxxx', '20190929', '20191203')
;
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a cross join E1 b),
InlineTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E2
)
select WorkerID
, StartDate
, EndDate
, WorkDay = case when t.N = 1 --the first month
then datediff(day, StartDate, dateadd(month, datediff(month, 0, StartDate) + 1, 0))
when datepart(month, dateadd(month, t.N - 1, StartDate)) < datepart(month, EndDate) --not the first OR the last month
then datediff(day, dateadd(month, datediff(month, t.N - 1, dateadd(month, t.N - 1, StartDate)), 0), dateadd(month, datediff(month, 0, dateadd(month, t.N - 1, StartDate)) + 1, 0))
else --the last month
datediff(day, dateadd(month, datediff(month, 0, EndDate), 0), EndDate) + 1
end
, FirstDayOfMonth = convert(date, dateadd(month, datediff(month, t.N - 1, dateadd(month, t.N - 1, StartDate)), 0))
from @Something s
join InlineTally t on t.N <= datediff(month, StartDate, EndDate) + 1
order by s.WorkerID
, t.N
Возвращает:
WorkerID | StartDate | EndDate | WorkDay | FirstDayOfMonth
0001 | 2019-11-29 | 2019-12-03 |2 | 2019-11-01
0001 | 2019-11-29 | 2019-12-03 |3 | 2019-12-01
xxxx | 2019-09-29 | 2019-12-03 |2 | 2019-09-01
xxxx | 2019-09-29 | 2019-12-03 |31 | 2019-10-01
xxxx | 2019-09-29 | 2019-12-03 |30 | 2019-11-01
xxxx | 2019-09-29 | 2019-12-03 |3 | 2019-12-01