给定周数,返回 T-SQL 中一周的第一天

Posted

技术标签:

【中文标题】给定周数,返回 T-SQL 中一周的第一天【英文标题】:Given a Week Number, Return the First Day of the Week in T-SQL 【发布时间】:2016-07-27 14:30:07 【问题描述】:

这会给我一个基于日期的星期数:

SELECT DATEPART(wk, '7/27/2016') AS [Week]

例如,返回 31。

现在,我需要做的是找到该周的第一天,并以短日期格式返回。例如:

Given Week: 31
Return First Day of Week: July 24

或者

Given Week: 52
Return First Day of Week: Dec 25

我相信一周的默认第一天是星期日,这就是我需要的日期。

我在这里看到了几篇接近的帖子,但没有一个能让我一路走好。

谢谢!

【问题讨论】:

如何定义一周的“第一”天?有些使用星期日,有些使用星期一。 好问题。我的意思是要说明这一点。我认为默认是星期日,这就是我想要的。 可能重复:***.com/questions/7168874/… @jpw,我看到了那个。但是这个问题,就像我所看到的一样,假设你从约会开始。我需要以数字 (31) 开头并返回一个日期。 那么您真正需要的是一年中给定一周中的星期日日期(“first”在这种情况下太容易使用了),对吧? 【参考方案1】:

我帮助从内到外阅读此内容。我添加了编号的 cmets 来提供帮助。

declare @weekNum int;set @weeknum = 52;
select 
-- 3.  Add number of weeks
dateadd(wk, @weekNum, 
    --2.  first day of week 0 for that year (may belong to previous year)
    dateadd(ww, datediff(wk, 0, 
        --1.  First date of the year (week 0)
        dateadd(YEAR, datediff(year,0, getDate()),0)
     ),-1) -- -1 here because 1900-01-01 (date 0) was a Monday, and adding weeks to a Monday results in a Monday.
)

我们可以将第二步和第三步结合起来,因为它们都增加了周数:

declare @weekNum int;set @weeknum = 52;
select 
    --2.  first day of week 0 for that year (may belong to previous year) + number of weeks
    dateadd(ww, @weekNum + datediff(wk, 0, 
        --1.  First date of the year (week 0)
        dateadd(YEAR, datediff(year,0, getDate()),0)
     ),-1) -- -1 here because 1900-01-01 (day 0) was a Monday. Adding weeks to a Monday results in a Monday

另外,我认为您在第 31 周的示例提前了一周。您可以像这样查看全年的完整集:

with weeks as 
(
    select top 52 row_number() over (order by  object_id) as wk  from sys.objects
)
select wk,
    --2.  first day of week 0 for that year (may belong to previous year) + number of weeks
    dateadd(ww, wk + datediff(wk, 0, 
        --1.  First date of the year (week 0)
        dateadd(YEAR, datediff(year,0, getDate()),0)
     ),-1) -- -1 here because 1900-01-01 (day 0) was a Monday. Adding weeks to a Monday results in a Monday
from weeks

【讨论】:

好吧,这里有些奇怪。 SELECT DATEPART(wk, '7/27/2016') 返回 31。但是,如果我将 31 放回您的查询中,我会得到 2016 年 7 月 31 日。给定一个日期,该日期所在一周的第一天不能晚于该日期。 问题是一年的第一天不是星期天。你想怎么解释呢?你想展示去年的一天吗?第 1 周的结果应该是 2016-01-03 还是 2015-12-27?如果您对此进行更改,它将一切向前移动,包括第 52 周(您要允许第 53 周吗?)。 我明白你的意思。我们现在拥有的是从 1 月 3 日开始的第 1 周,忽略了 1 月 1 日和 1 月 2 日。我需要包括这些日期。所以,我们最好从 2015 年 12 月 27 日开始第 1 周。 很容易将 -1 添加到第 num 周,但请记住,这现在将更改您问题中第 52 周的结果,在年底时会出现部分第 53 周。我还想在周日开始的一年内对此进行测试。如果 1 月 1 日是星期天,您可能还需要一份案例声明以不进行调整。 从技术上讲,在闰年,如果一年从星期六开始,你可以有 54 周(假设星期天是你一周的第一天。)这是一个极端的情况,但几年前它让我很痛苦.【参考方案2】:

看看我的计算。我们的想法是从今年的 1 月 1 日开始算术。

declare @year int=2016, @wk int=31
--A) Single chain calculations
select case datepart(weekday,cast(concat(@year,'-01-01') as date))
            when 1 then dateadd(wk,@wk-1,cast(concat(@year,'-01-01') as date))
            else dateadd(wk,@wk-1,
                  dateadd(day, 1/*8 if you want "first full week"*/ - datepart(weekday, cast(concat(@year,'-01-01') as date)),
                          cast(concat(@year,'-01-01') as date))) end

--B) the same in a better readable form    
;with tmp as (
select  cast(concat(@year,'-01-01') as date) jan01
)
select case datepart(weekday,jan01)
            when 1 then dateadd(wk, @wk-1, jan01)
            else dateadd(wk, @wk-1, dateadd(day, 1 - datepart(weekday, jan01), jan01)) end frstDay
from tmp

【讨论】:

'concat' 不是可识别的内置函数名。 concat 是在 SQL Server 2012 中引入的。对于早期版本,您可以使用 cast(@year as varchar)+'-01-01'。 CTE 也于 2008 年首次出现。【参考方案3】:

这是一个使用 DATEDIFF 和 DATEADD 的示例(第 3 行是获取所需值的一行代码)。这可能类似于接受的答案。

我发帖是因为这是我在为自己记录时在函数中使用的分解。

--1. Get the number of Weeks since Monday, January 1, 1900
select DATEDIFF(wk, 0, '01/01/2016') -- 6052 Weeks

--2: Take the value since 1900 + Number of Weeks - 8 Days get you to Sunday.
select DATEADD(wk, 6052 + (31), -8);

--3. Put it all together..
select DATEADD(wk, DATEDIFF(wk, 0, '1/1/2016' ) + (31), -8); --=2016-07-24

【讨论】:

以上是关于给定周数,返回 T-SQL 中一周的第一天的主要内容,如果未能解决你的问题,请参考以下文章

获取PHP中给定周数的第一周

详细讲解Oracle数据库的“周数计算”

如何将星期天设置为excel对周计算的第一天。

亚马逊 - Redshift:给定日期的周数错误

Bigquery 自定义一周的第一天(默认为星期一)

需要星期日作为一周的第一天