DATEPART:当不能使用 SET DATEFIRST 时指定一周的第一天

DATEPART: specifying first day of week when SET DATEFIRST cannot be used

我正在 ReportServer(动态列表类型)中创建一些报告,其中之一是从 SQL 服务器检索过去一周事件的信息。

在 SSMS 中,这很简单,我通过

获得了所需的信息(按时间)
... WHERE DATEPART(week, event_date) = DATEPART(week, DATEADD(d, -5, GETDATE()))

前面有一个

SET DATEFIRST 1;

声明以便将星期一设置为一周的第一天。

不幸的是,ReportServer 不接受 SET DATEFIRST 语句作为查询的一部分,因此在将其删除后,返回的数据范围是星期日到星期六,而不是星期一到星期日。我无法对数据库(或服务器)进行全局更改。

我该如何解决这个问题?

您可以使用 @@DATEFIRST 来尝试一下。这是一个系统变量,您无需在 inline/ad-hoc 查询中进行任何声明或设置即可使用:

--这是星期天

DECLARE @OneSunday DATE='20190929';

--你的说法return在不同的文化中是不同的

SET LANGUAGE ENGLISH;
SELECT DATEPART(week, @OneSunday); --<-- returns 40
SELECT @@DATEFIRST;                --<-- returns 7  

SET LANGUAGE GERMAN;
SELECT DATEPART(week, @OneSunday); --<-- returns 39
SELECT @@DATEFIRST;                --<-- returns 1

如您所见,系统变量@@DATEFIRST反映了当天的索引,这是由文化设置的。您可以将它用于一些校正算法。

SET LANGUAGE ENGLISH;
SELECT DATEPART(week, DATEADD(DAY,(@@DATEFIRST % 7),@OneSunday));

SET LANGUAGE GERMAN;
SELECT DATEPART(week, DATEADD(DAY,(@@DATEFIRST % 7),@OneSunday));

现在都是return40.

我使用 % 7 得到一个 0,其中 @@DATEFIRST return 是 7

计算所需的一周第一天,然后在 where 子句中使用周日期范围,例如

declare @FirstDayOfWeek date, @Now date = getdate();

select @FirstDayOfWeek = dateadd(day, -1*(case when datepart(weekday, @Now) > 1 then datepart(weekday, @Now)-2 else 6 end), @Now);

select *
from dbo.MyTable
where event_date >= @FirstDayOfWeek and event_date < dateadd(week, 1, @FirstDayOfWeek);

当然您也可以将计算嵌入到查询中,例如

select *
from dbo.MyTable
cross join (
  select dateadd(day, -1*(case when datepart(weekday, getdate()) > 1 then datepart(weekday, getdate())-2 else 6 end), getdate()) FirstDayOfWeek
) D
where event_date >= D.FirstDayOfWeek and event_date < dateadd(week, 1, D.FirstDayOfWeek);

注意:您可以将日期计算复制到 where 子句中并避免使用 join,但我不喜欢重复计算。

因为您想要以 Monday 开始的一周,所以您使用 Monday 的参考日期,例如 1900-01-01 并计算一周的开始和结束日期

begin_of_week = dateadd(day, datediff(day, '1900-01-01', [date]) / 7 * 7, '1900-01-01')

并获取周末日期,

end_of_week = dateadd(day, datediff(day, '1900-01-01', [date]) / 7 * 7 + 7, '1989-12-31')

所以把它放到你的查询中(我假设你的 event_date 可能包含时间部分,因此,上面的条件是 less than <

WHERE event_date >= dateadd(day, datediff(day, '1900-01-01', getdate()) / 7 * 7, '1900-01-01')
AND   event_date <  dateadd(day, datediff(day, '1900-01-01', getdate()) / 7 * 7 + 7, '1900-01-01')