T-SQL计算一年中第一个ISO周的第一个星期一,并枚举从到期间的所有周

T-SQL计算一年中第一个ISO周的第一个星期一,并枚举从到期间的所有周,sql,sql-server,date,iso8601,Sql,Sql Server,Date,Iso8601,我想计算给定年份中第一个ISO 8601周的第一天(星期一),然后列举给定年份中所有ISO 8601周,包括它们的数字。我想知道这是否可以做得比我到目前为止做得更好,也许可以使用内置函数datepart(iso_week,getdate())?这是我的密码: DECLARE @y as int = 2011 DECLARE @firstDayOfYear date = CAST(CAST(@y AS varchar(4)) + '-01-01' AS DATE) --thursday befo

我想计算给定年份中第一个ISO 8601周的第一天(星期一),然后列举给定年份中所有ISO 8601周,包括它们的数字。我想知道这是否可以做得比我到目前为止做得更好,也许可以使用内置函数datepart(iso_week,getdate())?这是我的密码:

DECLARE @y as int = 2011

DECLARE @firstDayOfYear date = CAST(CAST(@y AS varchar(4)) + '-01-01' AS DATE)
--thursday before 1st Jan
DECLARE @Thursday date = DATEADD(day,
               3 - (DATEPART(dw, @firstDayOfYear) + @@DATEFIRST - 2) % 7,
               @firstDayOfYear) 
DECLARE @FirstDayOfIsoWeek date = DATEADD(day,
               - (DATEPART(dw, @firstDayOfYear) + @@DATEFIRST - 2) % 7,
               @firstDayOfYear)
if (@Thursday<@firstDayOfYear)
    SELECT @FirstDayOfIsoWeek  = DATEADD(d,7, @FirstDayOfIsoWeek) 

SELECT @FirstDayOfIsoWeek
将@y声明为int=2011
声明@firstDayOfYear日期=CAST(CAST(@y为varchar(4))+'-01-01'为日期)
--1月1日前的星期四
声明@星期四日期=DATEADD(天,
3-(DATEPART(dw,@firstDayOfYear)+@@DATEFIRST-2)%7,
@(每年的第一天)
声明@FirstDayOfIsoWeek date=DATEADD(天,
-(DATEPART(dw,@firstDayOfYear)+@@DATEFIRST-2)%7,
@(每年的第一天)

如果(@星期四除非我误解了你所说的ISO周,否则我认为下面的代码应该适合你

第一部分看起来确实很难看,但执行速度很快。目标是找到一年中第一周的第一天。如果那不是星期一,那么第一天将在前一年,我们希望进入下一周

在此基础上,递归CTE对问题的第二部分进行了简短的处理

DECLARE 
    @year CHAR(4) = 1972,
    @YearDate DATE

SELECT
     DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(YEAR,DATEDIFF(YEAR,0,@year + '-01-01'),0)),0)
    ,DATEADD(WEEK,1 + DATEDIFF(WEEK,0,DATEADD(YEAR,DATEDIFF(YEAR,0,@year + '-01-01'),0)),0)

IF(DATENAME(YEAR,DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(YEAR,DATEDIFF(YEAR,0,@year + '-01-01'),0)),0)) = @year)
BEGIN
SELECT @YearDate = DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(YEAR,DATEDIFF(YEAR,0,@year + '-01-01'),0)),0)
END
ELSE
BEGIN
SELECT @YearDate = DATEADD(WEEK,1 + DATEDIFF(WEEK,0,DATEADD(YEAR,DATEDIFF(YEAR,0,@year + '-01-01'),0)),0)
END

;WITH DateCTE (StartDate, EndDate, YearNum, MnthName, WeekNumber) AS (
    SELECT
         @YearDate
        ,DATEADD(DAY,7,@YearDate)
        ,DATENAME(YEAR,@YearDate)
        ,DATENAME(MONTH,@YearDate)
        ,DATEDIFF(WEEK,DATEADD(WEEK,DATEDIFF(WEEK,0,@YearDate)-1,0),@YearDate)

    UNION ALL

    SELECT
         EndDate
        ,DATEADD(DAY,7,EndDate)
        ,DATENAME(YEAR,EndDate)
        ,DATENAME(MONTH,EndDate)
        ,DATEDIFF(WEEK,DATEADD(WEEK,DATEDIFF(WEEK,0,@YearDate)-1,0),EndDate)
    FROM DateCTE
    WHERE DATENAME(YEAR,EndDate) = @year
)
SELECT
*
FROM DateCTE

我将创建一个值为1到53的表

create table weeknumbers
(
  weeknum int not null
  primary key (weeknum)
)

declare @weeknum int
set @weeknum = 1

while (@weeknum <= 53)
begin
  insert weeknumbers values(@weeknum)
  set @weeknum = @weeknum + 1
end
创建表周数
(
weeknum int不为空
主键(周数)
)
声明@weeknum int
设置@weeknum=1

虽然(@weeknum谢谢,看起来很有希望,但仍然存在严重缺陷。2014年第一个ISO周开始于2013-12-30。您的第一周开始于2014-01-06。而您的输出中的第52周实际上是2015年第一个ISO周。您可以轻松检查:选择DATEPART(ISO_周,“2014-12-29”)我看得出你是对的,我想这就是我不确定你希望它如何工作的部分。要修复它,只需使用IF块中的第一条语句,而不用费心用IF语句检查它。第一条语句返回你要查找的正确2013-12-30日期,如t上面select语句的第一部分所示他说如果。我已经试过了,但它多年来都不起作用。我认为,检查本周的星期四是否在所选年份内很重要。WHERE条件应该是:WHERE DATEPART(year,DATEADD(day,7*N.weeknum+3,@Monday0))=@y,反映星期四。您介意在您的答案中编辑它吗?谢谢,它是这样工作的。您在输出中还指定了两次EndDate。在我的解决方案中实现您的答案时,我将weeknumbers表更改为@weeknumbers表变量。尽管进行了一些编辑,但它为我节省了一些工作,谢谢。请随意编辑。因此rry关于次要问题。也应该提到。拥有数字表通常对其他事情很有用。例如,只需添加我发现的另一个问题:月数不是ISO月数-即2013-12-30…2014-01-05应该是2014年第1个月,而不是12个月。
create table weeknumbers
(
  weeknum int not null
  primary key (weeknum)
)

declare @weeknum int
set @weeknum = 1

while (@weeknum <= 53)
begin
  insert weeknumbers values(@weeknum)
  set @weeknum = @weeknum + 1
end
create isoweeks(@y int) as
begin

DECLARE @firstDayOfYear date = CAST(CAST(@y AS varchar(4)) + '-01-01' AS DATE)
--thursday before 1st Jan
DECLARE @Thursday date = DATEADD(day,
               3 - (DATEPART(dw, @firstDayOfYear) + @@DATEFIRST - 2) % 7,
               @firstDayOfYear) 
DECLARE @FirstDayOfIsoWeek date = DATEADD(day,
               - (DATEPART(dw, @firstDayOfYear) + @@DATEFIRST - 2) % 7,
               @firstDayOfYear)
if (@Thursday<@firstDayOfYear)
    SELECT @FirstDayOfIsoWeek  = DATEADD(d,7, @FirstDayOfIsoWeek)

declare @Monday0 date = DATEADD(d,-7, @FirstDayOfIsoWeek)

-- SELECT @FirstDayOfIsoWeek

select DATEADD(WEEK, N.weeknum, @Monday0) as StartDate
, DATEADD(day, 7*N.weeknum+6, @Monday0) as EndDate
, DATEADD(day, 7*N.weeknum+6, @Monday0) as EndDate
, @y as Year
,   DATEPART(month,  DATEADD(WEEK, N.weeknum, @Monday0)) as Month
,   DATEPART(ISO_WEEK,  DATEADD(WEEK, N.weeknum, @Monday0)) as Month
from dbo.weeknumbers N
where DATEPART(year,  DATEADD(WEEK, N.weeknum, @Monday0)) = @y
order by N.weeknum

end