需要两个日期之间的周数列表

时间:2015-11-30 15:07:44

标签: sql sql-server date

我需要一个结果集,包括两个日期之间的周,年和所有周的开始日期。我需要它来匹配其他搜索结果到周。由于报告将持续一年多,我需要它来匹配日历。

我们在欧洲,所以星期几在星期一开始。 我通过JDBC连接使用SQL Server。我不能使用压延表。

我遇到过各种各样的解决方案,但没有一个能满足我的需求。这是我需要的那种列表,但不知何故结果不正确。我找不到我的错误:

selenium

我用过--SET DATEFIRST 1;确保星期一星期几开始。

结果如下:

WITH mycte AS
(
 SELECT DATEADD(ww, DATEDIFF(ww,0,CAST('2010-12-01' AS DATETIME)), 0) DateValue
 UNION ALL
 SELECT  DateValue + 7
 FROM    mycte   
 WHERE   DateValue + 7 < '2016-12-31'
)

SELECT  DATEPART(wk, DateValue) as week, DATEPART(year, DateValue) as year, DateValue
FROM    mycte
OPTION (MAXRECURSION 0);

问题很明显。 2010年还没有53周,第1周也没了。 这也适用于其他年份。只有2015年有53周。

(注意:在iso周(欧洲),2010年仅有52周,请参阅wiki:https://en.wikipedia.org/wiki/ISO_week_date

  

在400年周期中接下来的71年(当前增加2000年)   年)有53周(闰年,2月29日,强调),   未列出的年份有52周:004,009,015,020,026,032,037,   043,048,054,060,065,071,076,082,088,093,099,105,111,116,   122,128,133,139,144,150,156,161,167,172,178,184,189,   195,201,207,212,218,224,229,235,240,246,252,257,263,268,   274,280,285,291,296,303,308,314,320,325,331,336,342,348,   353,359,364,370,376,381,387,392,398。

但日期是正确的。 2012-12-27是星期一,2011-01-03也是如此。 但在欧洲,我们总是有一个完整的第1周(所以星期一总是有一周的第1周)

任何关于第1周的问题或为什么有这么多年的53(这是错误的)?

3 个答案:

答案 0 :(得分:1)

DATEPART中使用iso_week

  

ISO 8601包括ISO周日期系统,一个编号系统   周。每周与周四发生的年份相关联。   例如,2004年第1周(2004W01)从2003年12月29日星期一开始   到2004年1月4日星期日。一年中最高的一周数可能是   52或53.这种编号方式通常用于欧洲   国家/地区,但在其他地方很少见。

WITH mycte AS
(
 SELECT DATEADD(ww, DATEDIFF(ww,0,CAST('2010-12-01' AS DATETIME)), 0) DateValue
 UNION ALL
 SELECT  DateValue + 7
 FROM    mycte   
 WHERE   DateValue + 7 < '2016-12-31'
)  
SELECT DATEPART(iso_week, DateValue) as week, DATEPART(year, DateValue) as year,
       DateValue
FROM    mycte
OPTION (MAXRECURSION 0);

LiveDemo

您还可以考虑使用tally table更改递归CTE。

答案 1 :(得分:1)

您在2010年看到53周的原因仅仅是因为, 2010年。

让我们仔细看看那一周的周数是如何分解的:

Declare @FromDate   Date = '2010-01-01',
        @ToDate     Date = '2011-01-03'

;With Date (Date) As
(
    Select  @FromDate Union All
    Select  DateAdd(Day, 1, Date)
    From    Date
    Where   Date < @ToDate
)
Select  Date, DatePart(Week, Date) WeekNo, DateName(WeekDay, Date) WeekDay
From    Date
Option  (MaxRecursion 0)

SQL Fiddle

以下是今年年初的结果:

Date       WeekNo      WeekDay
---------- ----------- ------------------------------
2010-01-01 1           Friday
2010-01-02 1           Saturday
2010-01-03 2           Sunday
2010-01-04 2           Monday
2010-01-05 2           Tuesday
2010-01-06 2           Wednesday
2010-01-07 2           Thursday
2010-01-08 2           Friday
2010-01-09 2           Saturday
2010-01-10 3           Sunday

由于这一年从一周的中间开始,Week 1只有两天。这导致一年有53个星期。

现在,为了回答你为什么没有看到2011年Week 1价值的问题,让我们来看看那一年如何结束:

Date       WeekNo      WeekDay
---------- ----------- ------------------------------
2010-12-26 53          Sunday
2010-12-27 53          Monday
2010-12-28 53          Tuesday
2010-12-29 53          Wednesday
2010-12-30 53          Thursday
2010-12-31 53          Friday
2011-01-01 1           Saturday
2011-01-02 2           Sunday
2011-01-03 2           Monday

您以7天为单位选择日期。您在2010年提取的最后一个日期是2010-12-27,这是在第53周准确显示的。但是明年的开始时间是在本周的星期六,在2011年的星期六Week 1 ,第二天开始Week 2

由于您没有在星期一2011-01-03之前选择新的日期,因此它会有效地跳过2011年第一周的日期,并以Week 2开头。

答案 2 :(得分:0)

SQL Server正在使用与Outlook匹配的标准周数(而53个声音奇怪,它是有效的)。

当然,您可以随时创建自己的自定义周数。您需要做的就是选择一个星期一开始并计算您要分配的星期数。然后,您的CTE可以增加其自己的周数,每当年度变化时重置为1。但即便如此,这将在第53周返回(2012年12月31日是星期一,使其成为当年的第53周,即使本周剩余的时间是在2013年)。

值得一提;您的周数不太可能与其他系统/流程相匹配。这可能会导致你的问题进一步发展。

SET DATEFIRST 1;

WITH [Week] AS
    (
            SELECT
                CAST('2010-11-29' AS DATE)      AS [Date],
                48                              AS WeekNumber

        UNION ALL

            SELECT
                DATEADD(DAY, 7, [Date]) AS [Date],
                CASE
                    -- Reset the week number count when the year changes.
                    WHEN YEAR([Date]) <> YEAR(DATEADD(DAY, 7, [Date])) THEN 1
                    ELSE WeekNumber + 1             
                END AS WeekNumber
            FROM
                [Week]
            WHERE
                [Date] < GETDATE()
    )
SELECT
    *
FROM
    [Week]
OPTION
    (MAXRECURSION 0)
;