始终返回上周一至周日的数据

时间:2011-08-22 21:14:18

标签: tsql

如何编写始终从上周一到上周日返回数据的sql语句?任何指导都表示赞赏。

感谢。

4 个答案:

答案 0 :(得分:13)

t-clausen.dk's answer确实有效,但可能不清楚为什么它(无论是对您还是对您而言的开发人员都有效)。由于增加的清晰度有时会以简洁和性能为代价,我想解释一下为什么它可以用来防止你更喜欢使用那种较短的语法。

SELECT t.*  
FROM <table> t CROSS JOIN 
(SELECT DATEDIFF(day, 0, getdate() - DATEDIFF(day, 0, getdate()) %7) lastmonday) a 
WHERE t.yourdate >= a.lastmonday - 7 and yourdate < a.lastmonday 

SQL Server如何在内部存储datetime

SQL Server将datetime存储为两个4字节整数;前四个字节表示自19/1年1月1日以来(或者在1/1/1900之前,对于负数)的天数,后四个字节表示自午夜以来的毫秒数。

datetimeintdecimal

一起使用

因为datetime存储为两个4字节整数,所以很容易在T-SQL中的数字和日期数据类型之间移动。例如,SELECT GETDATE() + 1返回的内容与SELECT DATEADD(day, 1, GETDATE())相同,CAST(40777.44281 AS datetime)2011-08-24 10:37:38.783相同。

1/1/1900

由于datetime的第一个整数部分,如上所述,自191年1月1日以来的天数(也称为SQL Server Epoch),CAST(0 as datetime)根据定义相当于 1900-01-01 00:00:00

DATEDIFF(day,0,GETDATE())

这里的事情开始变得既棘手又有趣。首先,我们已经确定,当0被视为日期时,它与1/1/1900相同,因此DATEDIFF(day, '1/1/1900', GETDATE())DATEDIFF(day, 0, GETDATE())相同 - 两者都将返回自19/1/19以来的当前天数。但是,等一下:当前的天数恰好是datetime的前四个字节所代表的!在一个语句中,我们做了两件事:1)我们删除了GETDATE()返回的“时间”部分,我们得到了一个整数值,我们可以用它来计算查找最近的星期日和上周一稍微容易一点。

星期一的Modulo 7

DATEDIFF(day, 0, GETDATE()) % 7利用了DATEPART(day, 0)(有可能过分强调该点,与DATEPART(day, '1/1/1900')相同)返回2(星期一)这一事实。 1 因此,DATEDIFF(day, 0, GETDATE()) % 7将始终生成当前日期的星期一天数。

1 除非您使用DATEFIRST更改了默认行为。

最近一个星期一

这对于它自己的标题来说几乎是微不足道的,但是在这一点上我们可以将迄今为止所有的东西放在一起:

  • GETDATE() - DATEDIFF(day, 0, GETDATE()) %7为您提供最新的星期一
  • DATEDIFF(day, 0, GETDATE() - DATEDIFF(day, 0, GETDATE()) %7)为您提供最新的星期一作为整个日期,没有时间部分。

但是海报想要从周一到周日的一切......

而不是使用BETWEEN运算符(包括在内),将发布的答案排除在最后一天之外,这样就无需进行任何转换或计算以获得正确的日期范围:

  • t.yourdate >= a.lastmonday - 7返回自第二个最近一个星期一午夜以来(或包括)午夜的记录
  • t.yourdate < a.lastmonday返回最近一个星期一午夜之前(但不包括)日期的记录。

我非常支持编写易于理解的代码,无论是对于您还是一年后跟随您的开发人员(可能也是您)。我相信我之前发布的答案对于新手T-SQL程序员来说应该是可以理解的。但是,t-clausen.dk的答案很简洁,表现良好,可能会在生产代码中遇到,所以我想给出一些解释,以帮助未来的访问者理解它的工作原理。

答案 1 :(得分:4)

我意识到我的代码太复杂了,所以我改变了我的答案。 getdate()之后的减号修正了这个以返回星期日的最后一个星期一而不是星期一的星期一(明天如果今天是星期天)。

SELECT t.* 
FROM <table> t CROSS JOIN
(SELECT DATEDIFF(week, 0, getdate() - 1) * 7 lastmonday) a
WHERE t.yourdate >= a.lastmonday - 7 and yourdate < a.lastmonday

旧代码

SELECT t.* 
FROM <table> t CROSS JOIN
(SELECT DATEDIFF(day, 0, getdate() - DATEDIFF(day, 0, getdate()) %7) lastmonday) a
WHERE t.yourdate >= a.lastmonday - 7 and yourdate < a.lastmonday

答案 2 :(得分:3)

你没有指定哪种SQL方言,所以我会回答T-SQL,这是我最熟悉的,你使用了tsql标签。

在T-SQL中,使用DATEPART函数查找星期几。当您知道当周的当天时,您可以获得最近一个星期日和星期一之前的日期。

在存储过程中,在我看来,它更容易 - 更易读,更易于维护 - 计算最近星期日和前一个星期一的值,并将值存储在变量中。然后,这些变量可以在程序的后期计算中使用。

CREATE PROCEDURE SomeProcedure
AS
  DECLARE @CurrentDayOfWeek int, @LastSunday date, @LastMonday date
  SET @CurrentWeekday = DATEPART(weekday, GETDATE())
  -- Count backwards from today to get to the most recent Sunday.
  -- (@CurrentWeekday % 7) - 1 will give the number of days since Sunday; 
  -- -1 negates for subtraction.
  SET @LastSunday = DATEADD(day,  -1 * (( @CurrentWeekday % 7) - 1), GETDATE())
  -- Preceding Monday is obviously six days before last Sunday.
  SET @LastMonday = DATEADD(day, -6, @LastSunday)

  SELECT ReportColumn1, ReportColumn2
  FROM ReportTable
  WHERE DateColumn BETWEEN @LastMonday AND @LastSunday

如果你需要能够在SELECT语句或视图中进行计算,那么现在我们已经完成了这些步骤,虽然查询本身有点麻烦,但这很简单:

  SELECT ReportColumn1, ReportColumn2
  FROM ReportTable
  WHERE DateColumn 
  BETWEEN 
  (
      -- Last Monday is six days before...
      DATEADD(day, -6, 
         -- ... last Sunday.
         DATEADD(day,  -1 * (( DATEPART(weekday, GETDATE()) % 7) - 1), GETDATE())
      )
  )
  AND
  (
      -- Last Sunday has to be calculated again each time it is used inline.
      DATEADD(day,  -1 * (( DATEPART(weekday, GETDATE()) % 7) - 1), GETDATE())
  )

我添加的括号不是必需的,但仅用于帮助您了解如何构建WHERE子句。

最后,请注意这些使用SQL 2008 date数据类型;对于datetime数据类型,您可能需要执行自己的转换/截断来比较整个日期而不是日期加时间值。

答案 3 :(得分:1)

@ t-clausen.dk答案中的短代码不适用于星期日,也不是我在Google上找到的第一个结果。要测试它们,请尝试。

DECLARE @date as DATETIME;
SET @date = '2014-11-23 10:00:00'; -- Sunday at 10a

SELECT DATEADD(wk, DATEDIFF(wk,0,@date), 0) -- 2014-11-24 00:00:00
SELECT CAST(DATEDIFF(week, 0, @date)*7 as datetime) -- 2014-11-24 00:00:00
SELECT CAST(DATEDIFF(day, 0, CAST(@date as DATETIME) - DATEDIFF(day, 0,@date) %7) as DATETIME) --2014-11-17 00:00:00
SELECT DATEADD(wk, DATEDIFF(wk,0,@date-1), 0) --2014-11-17 00:00:00

因此,您应该使用原始答案或修改过的短代码中的长代码。

SELECT t.* 
FROM <table> t CROSS JOIN
(SELECT DATEDIFF(week, 0, getdate() - 1) * 7 lastmonday) a
WHERE t.yourdate >= a.lastmonday - 7 and yourdate < a.lastmonday