回答为什么是星期一而不是星期日:
您要向日期 0 添加周数。日期 0 是什么? 1900-01-01。 1900 年 1 月 1 日是哪一天?周一。所以在你的代码中你说的是,自 1900 年 1 月 1 日星期一以来已经过去了多少周?我们称之为[n]。好的,现在将 [n] 周添加到 1900 年 1 月 1 日星期一。您应该不会对这最终成为星期一感到惊讶。 DATEADD 不知道您想增加周数,但直到您到达周日,它只是增加 7 天,然后再增加 7 天,......就像 DATEDIFF 只识别已跨越的边界。例如,它们都返回 1,尽管有些人抱怨应该内置一些合理的逻辑来向上或向下舍入:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
回答如何获得星期天:
如果您想要星期天,请选择一个不是星期一而是星期日的基准日期。例如:
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
如果您更改 DATEFIRST 设置(或者您的代码正在为具有不同设置的用户运行),这不会中断 - 前提是无论当前设置如何,您仍然想要星期天。如果您希望这两个答案能够解决问题,那么您应该使用 确实 依赖于 DATEFIRST 设置的函数,例如
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
因此,如果您将DATEFIRST 设置更改为星期一、星期二,那么您的行为将会改变。根据您想要的行为,您可以使用以下功能之一:
CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO
...或...
CREATE FUNCTION dbo.StartOfWeek2 -- always the DATEFIRST weekday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, @d), @d));
END
GO
现在,您有很多选择,但哪一个表现最好?如果会有任何重大差异,我会感到惊讶,但我收集了迄今为止提供的所有答案,并通过两组测试对它们进行了测试——一组便宜,一组昂贵。我测量了客户端统计数据,因为我没有看到 I/O 或内存在此处的性能中发挥作用(尽管这些可能会根据函数的使用方式发挥作用)。在我的测试中,结果是:
“便宜”赋值查询:
Function - client processing time / wait time on server replies / total exec time
Gandarez - 330/2029/2359 - 0:23.6
me datefirst - 329/2123/2452 - 0:24.5
me Sunday - 357/2158/2515 - 0:25.2
trailmax - 364/2160/2524 - 0:25.2
Curt - 424/2202/2626 - 0:26.3
“昂贵的”分配查询:
Function - client processing time / wait time on server replies / total exec time
Curt - 1003/134158/135054 - 2:15
Gandarez - 957/142919/143876 - 2:24
me Sunday - 932/166817/165885 - 2:47
me datefirst - 939/171698/172637 - 2:53
trailmax - 958/173174/174132 - 2:54
如果需要,我可以转达我的测试细节 - 在这里停下来,因为这已经变得相当冗长了。考虑到计算和内联代码的数量,看到 Curt 在高端领域中速度最快,我有点惊讶。也许我会进行一些更彻底的测试并写博客……如果你们不反对我在其他地方发布你们的函数。