为什么这会返回4而不是6?
SET DATEFIRST 1
SELECT DATEDIFF(WEEK, CAST('2017-01-01' AS DATE), CAST('2017-01-31' AS DATE))
作为日期部分的星期是否只计算monday - sunday
(整周)的几周?如何获得所有周 - 包括那些没有seven days
的人?在上述情况下,答案应为6
。
答案 0 :(得分:4)
DATEDIFF
计算过渡,而非句点(例如,查看DATEDIFF(year,'20161231','20170101')
)。它还将星期日视为一周的第一天。那么,我们如何补偿这些功能呢?首先,我们改变日期,以便星期一是新的星期日,第二,我们加1以补偿Fence-Post错误:
declare @Samples table (
StartAt date not null,
EndAt date not null,
SampleName varchar(93) not null
)
insert into @Samples (StartAt,EndAt,SampleName) values
('20170101','20170131','Question - 6'),
('20170102','20170129','Exactly 4'),
('20170102','20170125','3 and a bit, round to 4'),
('20170101','20170129','4 and 1 day, round to 5')
--DATEDIFF counts *transitions*, and always considers Sunday the first day of the week
--We subtract a day from each date so that we're effectively treating Monday as the first day of the week
--We also add one because DATEDIFF counts transitions but we want periods (FencePost/FencePanel)
select *,
DATEDIFF(WEEK, DATEADD(day,-1,StartAt), DATEADD(day,-1,EndAt)) +1
as NumWeeks
from @Samples
结果:
StartAt EndAt SampleName NumWeeks
---------- ---------- -------------------------- -----------
2017-01-01 2017-01-31 Question - 6 6
2017-01-02 2017-01-29 Exactly 4 4
2017-01-02 2017-01-25 3 and a bit, round to 4 4
2017-01-01 2017-01-29 4 and 1 day, round to 5 5
如果这与您想要的不匹配,也许您可以采用并调整我的@Samples
表来显示您期望的结果。
答案 1 :(得分:2)
你问的是,一个范围涵盖的周数,而不是两个日期之间的周数。
在计算周转换时, DATEDIFF
总是使用星期日。
这不是一个错误,它可以确保函数是确定性的,并且对于每个查询都返回相同的值,无论DATEFIRST
设置如何。来自documentation
指定SET DATEFIRST对DATEDIFF没有影响。 DATEDIFF总是使用星期日作为一周的第一天,以确保功能是确定性的。
一种解决方案是计算开始日期和结束日期的周数之间的差异,第一天是星期一。 1
被添加到差异中以考虑第一周:
SET DATEFIRST 1;
select 1 +datepart(WEEK,'20170131') - datepart(WEEK,'20170101')
这是一个脆弱的计算,但如果DATEFIRST
发生变化或其中一个日期是在另一年,则会中断。
您可以使用ISO Weeks摆脱SET DATEFIRST
:
select 1 +datepart(ISO_WEEK,'20170131') - datepart(ISO_WEEK,'20170101')
但2017-01-01
会失败,因为星期日被计算为上一年的第52周。
更好的解决方案是使用包含日期和不同周数的Calendar表计算不同的周数,以涵盖多个业务要求,例如正常和ISO周数,或基于的业务日历一个4-4-5日历。
在这种情况下,您可以只计算不同的周数:
SELECT COUNT(DISTINCT Calendar.IsoWeek )
from Calendar
where date between '20170101' and '20170131'
如果表格没有ISO周列,您可以使用DATEPART
:
select count (distinct datepart(ISO_WEEK,date) )
from Calendar
where date between '20170101' and '20170131'