sql-server - 在 SQL Server 中获取一周的第一天

标签 sql-server tsql sql-server-2008 date

我尝试按周对记录进行分组,将聚合日期存储为一周的第一天。但是,我用于四舍五入日期的标准技术似乎无法在几周内正常工作(尽管它可以在天、月、年、季度和我应用的任何其他时间范围内正常工作)。

这是 SQL:

select "start_of_week" = dateadd(week, datediff(week, 0, getdate()), 0);

这将返回 2011-08-22 00:00:00.000,这是星期一,而不是星期日。选择 @@datefirst 返回 7,这是星期日的代码,因此据我所知,服务器设置正确。

我可以通过将上面的代码更改为以下内容来轻松绕过这个问题:

select "start_of_week" = dateadd(week, datediff(week, 0, getdate()), -1);

但事实上我必须破例,这让我有点不安。另外,如果这是一个重复的问题,我们深表歉意。我发现了一些相关的问题,但没有一个专门解决这方面的问题。

最佳答案

回答为什么你得到星期一而不是星期日:

您要在日期 0 上添加周数。日期 0 是多少? 1900 年 1 月 1 日。 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 设置(或者您的代码正在为具有不同设置的用户运行),则这不会中断 - 前提是无论当前设置如何,您仍然想要星期日。如果您想要 jive 这两个答案,那么您应该使用一个确实依赖于 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 成为高端最快的。也许我会进行一些更彻底的测试并在博客中介绍它...如果你们不反对我在其他地方发布您的函数。

关于sql-server - 在 SQL Server 中获取一周的第一天,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7168874/

相关文章:

sql-server - XML 服务器 XML 性能优化

sql-server - 如何确保嵌套事务彼此独立提交?

tsql - 运行插入语句 x 次

sql - 根据列值重复行 N 次

sql-server - 与简单的 IF EXISTS 相比,MERGE 的优势是什么?

c# - 在SQL Server 2012中使用Entity Framework 5时出错

mysql - 为什么当前的数据库查询优化技术不支持计算列的优化?

sql-server - SQL Server - 将无效值转换为 int

sql - T-SQL。如何在没有光标的情况下将 Item[i] 和 Item[i-1] 选择到同一行

sql - 连接和重复行