这看起来像很多代码,但我认为它逐步完成并解释了它如何满足计算范围内天数的要求,包括省略下一年的天数(以防有人忘记先过滤它,示例用法也处理):
CREATE FUNCTION dbo.ReturnDateRangeByMonth
(
@start date, @end date
)
RETURNS TABLE WITH SCHEMABINDING
AS
RETURN
(
WITH d(d) AS -- recursive to get all the days in the range
(
SELECT @start UNION ALL SELECT DATEADD(DAY, 1, d) FROM d
-- except the last day
WHERE d < DATEADD(DAY,-1,@end)
-- and except any days from the next year
AND d < DATEFROMPARTS(YEAR(@start)+1, 1, 1)
-- on < 2012 use AND YEAR(d) = YEAR(@start)
),
m(m) AS -- grab all 12 months to pivot on
(
SELECT 1 UNION ALL SELECT m + 1 FROM m WHERE m < 12
)
SELECT m.m, c = COALESCE(COUNT(d.d),0) FROM m
LEFT OUTER JOIN d ON m.m = MONTH(d.d) GROUP BY m.m
);
Run Code Online (Sandbox Code Playgroud)
示例用法:
DECLARE @vaca TABLE (OOW date, RTW date);
INSERT @vaca(OOW,RTW) VALUES('20191222','20200107'),('20190326','20190528'),
('20190328','20190522'),('20190612','20190617'),('20190404','20190418');
;WITH v AS
(
SELECT OOW, RTW FROM @vaca WHERE OOW >= '20190101' AND OOW < '20200101'
)
SELECT * FROM v CROSS APPLY dbo.ReturnDateRangeByMonth(v.OOW, v.RTW) AS f
PIVOT (MAX(c) FOR m IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])) AS p
OPTION (MAXRECURSION 366);
Run Code Online (Sandbox Code Playgroud)
结果:
可能最容易生成开始和停止之间的日期:
with t (d) as (
select cast('2017-02-10' as date)
union all
select dateadd(day, 1, d) from t where d < '2017-03-15'
)
select month(d), count(1) from t group by month(d);
Run Code Online (Sandbox Code Playgroud)
我认为在应用程序层进行旋转更好,但如果您坚持,您可以这样做:
with t (d) as (
select cast('2017-02-10' as date)
union all
select dateadd(day, 1, d) from t where d < '2017-03-15'
)
select count(case when month(d) = 1 then 1 end)
, count(case when month(d) = 2 then 1 end)
, count(case when month(d) = 3 then 1 end)
...
from t;
Run Code Online (Sandbox Code Playgroud)
编辑:在编辑后的帖子中似乎有几个间隔。您可以考虑为日期范围创建一个函数。例子:
CREATE FUNCTION date_range(@start date, @stop date)
RETURNS TABLE AS
RETURN
with t (d) as (
select cast(@start as date)
union all
select dateadd(day, 1, d) from t where d < @stop
)
select d from t;
with t (x,y) as (
select '2017-02-10', '2017-03-15'
union all
select '2017-05-01', '2017-06-21'
)
select month(dr.d), count(1)
from t
cross apply date_range(t.x, t.y) dr
group by month(dr.d);
Run Code Online (Sandbox Code Playgroud)
如果要在每个间隔内计数:
with t (x,y) as (
select '2017-02-10', '2017-03-15'
union all
select '2017-05-01', '2017-06-21'
)
select t.x, t.y, month(dr.d) as month, count(1) as cnt
from t
cross apply date_range(t.x, t.y) dr
group by t.x, t.y, month(dr.d);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
489 次 |
| 最近记录: |