我有两个参数:
@startDate date = N'2022-01-17'
@endDate date = N'2022-02-28'
以及一个包含数据(与参数无关(的表格
jobnr | startdate | duedate |
---|---|---|
nr324 | 2022-01-09 | 2022-01-19 |
nr326 | 2022-04-09 | 202年5月13日 |
您的月份CTE是正确的,但您需要小心结束条件,例如2022-01-31至2022-02-01。从那里,您可以CROSS JOIN
带有工作数据的日历,以计算工作、月份和整个范围之间的重叠日期数。
SQL Server没有LEAST((或GREATEST((函数来操作离散值,因此需要另一种方法。对于两个值,可以使用一个简单的CASE语句,但对于比较3个或更多的值,该逻辑会变得越来越复杂。保持事情相对简单的一个技巧是使用对使用VALUES语法定义的一组数据进行操作的MIN((和MAX((聚合函数。
从那里,你可以计算天数,小心避免负值范围。
最终结果是:
;WITH Months (Date) AS (
SELECT DATEADD(DAY, 1 - DAY(@startdate), @startdate) -- First-of-month
UNION ALL
SELECT DATEADD(month, 1, Date)
from months
where DATEADD(month, 1, Date) <= @enddate -- Inclusive
)
SELECT
JobNr = D.jobnr,
Month = DATENAME(month, M.Date),
[How Many Days] = CASE
WHEN R.RangeStart <= R.RangeEnd
THEN 1 + DATEDIFF(DAY, R.RangeStart, R.RangeEnd)
ELSE 0
END
FROM Months M
CROSS JOIN @Data D
OUTER APPLY(
SELECT RangeStart = MAX(StartDate), RangeEnd = MIN(EndDate)
FROM (
VALUES
(@startDate, @endDate),
(M.Date, EOMONTH(m.Date)),
(D.startdate, D.duedate)
) A(StartDate, EndDate)
) R
ORDER BY D.jobnr, M.Date
结束日期(@endDate和duedate(假定为包含所有日期。上述逻辑也适用于跨越多年的范围,您可能希望将YEAR(M.Date)
添加到结果中。
请参阅此数据库<gt;小提琴演示。
declare @a table (
jobnr VARCHAR(6) NOT NULL
,startdate DATE NOT NULL
,duedate DATE NOT NULL
);
INSERT INTO @a(jobnr,startdate,duedate) VALUES
('nr324','2022-01-09','2022-01-19'),
('nr326','2022-04-09','2022-05-13');
使用join
、union
和format
,如下
DECLARE @startDate DATE = N'2022-01-17' --yourvariable
DECLARE @endDate DATE = N'2022-02-28' -- yourvariable
SELECT a.month1,
Count(b.month1) AS 'How many days'
FROM (SELECT Format(@startDate, 'MMMM') month1---month as name
UNION
SELECT Format(@endDate, 'MMMM') month1) a
LEFT JOIN (SELECT jobnr,
startdate,
Format(startdate, 'MMMM') month1
FROM @a --your table
UNION
SELECT jobnr,
duedate,
Format(duedate, 'MMMM') month1
FROM @a) b
ON a.month1 = b.month1
GROUP BY b.month1,
a.month1