SQL Server - 基于周数和年份的星期一日期(查看)

时间:2015-07-13 11:00:47

标签: sql sql-server

  1. 我有一个表格,用于指定当前年份(在C#中完成)Years.Year
  2. 我有一个名为Weeks的表,其中包含数字(1-53)Weeks.WeekNumber http://whatweekisit.org/
  3. 现在我要创建一个视图,根据参数Years.YearWeeks.WeekNumber

    列出星期一的每周日期

    下面的代码获取周数,但是请正确计算日期:

    SET DATEFIRST 4     
    DECLARE @d DATETIME
    
    SET @d = GETDATE() 
    --BELOW IS WHAT I WANT TO WORK ALTHOUGH THE SUB QUERY RETURNS MORE THAN ONE VALUE
    --(SELECT Weeks.WeekNumber FROM Weeks)
    
    SELECT
      Weeks.WeekNumber,
      DATEADD(dd, (@@DATEFIRST + 5 + DATEPART(dw, @d)) % 7, @d) Monday
      FROM Weeks
    

    示例数据:

    Week Number       Date
         1        29/12/2014
         2        05/01/2015
         3        12/01/2015
         4        19/01/2015
         5        26/01/2015
        ...           ...
        53        28/12/2015
    

    总结:

    2015年包含53个星期一,因此我尝试生成一个SELECT语句,该语句将指定周数和每周的日期,就像上面的示例数据一样

    感谢下面的帮助,以及各种日历表的建议....我会尝试测试所有:)

7 个答案:

答案 0 :(得分:2)

这不会使用您的查找表,但会生成一年中每个星期一的日期表(仅经过轻微测试):

DECLARE @year INT = DATEPART(YEAR, GETDATE())
DECLARE @firstDate DATE = CONVERT(VARCHAR(12), @year) + '0101'
SET DATEFIRST 1;
WITH    cte
          AS ( SELECT   1 AS WeekNo ,
                        DATEADD(DD, 1 - DATEPART(DW, @firstDate), @firstDate) AS MonDate
               UNION ALL
               SELECT   cte.WeekNo + 1 ,
                        DATEADD(DAY, 7, cte.MonDate) AS MonDate
               FROM     cte
               WHERE    DATEPART(YEAR, DATEADD(DAY, 7, cte.MonDate)) = @year
             )
    SELECT  *
    FROM    cte

它会计算给定年份的第一个星期一,然后只需将7天添加到年底。

答案 1 :(得分:2)

你可以试试这样的事情

DECLARE @startDate DATETIME
DECLARE @endDate DATETIME

SET @startDate = DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP)
SET @endDate = '2016-1-31';

WITH dates(Date) AS 
(
    SELECT @startdate as Date
    UNION ALL
    SELECT DATEADD(d,7,[Date])
    FROM dates 
    WHERE DATE < @enddate
)

SELECT Date
FROM dates
OPTION (MAXRECURSION 0)

答案 2 :(得分:2)

你可以写成:

-- SET DATEFIRST to U.S. English default value of 7.
SET DATEFIRST 7;

SELECT DATEPART( wk, [DateofYear]) as [Week Number],
      [DateofYear] as[MondayDate]
FROM (
 SELECT TOP (365)
 DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY number)-1, '20150101') AS [DateofYear]
 FROM [master].dbo.spt_values
 WHERE [type] = N'P' ORDER BY number
 ) AS T
 WHERE datepart(dw,[DateofYear]) = 2 --Monday
 ORDER BY [DateofYear];

答案 3 :(得分:2)

请尝试这个: -

Declare @StartDate Date = '2015-01-01'

---- here consider Your Week table as AllWeeks
;With AllWeeks As
(
    Select   1 As WeekNo

    Union All

    Select  (WeekNo + 1)
    From    AllWeeks As w
    Where   w.WeekNo < 53
)

Select   w.WeekNo
        ,Dateadd(Day, (2 - Datepart(DW, Dateadd(Week, w.WeekNo, @StartDate))), Dateadd(Week, w.WeekNo, @StartDate)) As Mondays
From    AllWeeks As w
Where   Datepart(Year, Dateadd(Day, (2 - Datepart(DW, Dateadd(Week, w.WeekNo, @StartDate))), Dateadd(Week, w.WeekNo, @StartDate))) = 2015

答案 4 :(得分:2)

正如评论中所提到的,如果您自己构建calendar table,这会更容易,您的查询只会是:

DECLARE @Year INT = 2015;
SELECT  Date, ISOWeek
FROM    CalendarTable
WHERE   DayNumberOfWeek = 1
AND     ISOYear = @Year;

我会假设这不是你的选择。第一步是获得一年中的第一天,这很简单:

SELECT CAST(CAST(@Year AS VARCHAR(4)) + '0101' AS DATE)

然后你可以得到本周的星期一:

SELECT DATEADD(WEEK, DATEDIFF(WEEK, 0, YearStart), 0)

然后你从1到53的一组数字来添加你的周数:

SELECT  TOP(53) ROW_NUMBER() OVER(ORDER BY object_id)
FROM sys.all_objects

最后,如果今年的第一天是在今年的第一周或去年的最后一周,你需要确定。如果是后者,那么您需要在周开始计算中添加一周。结合以上内容,你得到:

DECLARE @Year INT = 2016;
SELECT  n.Weeknumber,
        StartOfWeek = DATEADD(WEEK, DATEDIFF(WEEK, 0, d.YearStart) + n.WeekNumber + n.Factor, 0)
FROM    (SELECT CAST(CAST(@Year AS VARCHAR(4)) + '0101' AS DATE)) AS d (YearStart)
        CROSS APPLY
        (   SELECT  TOP(53) ROW_NUMBER() OVER(ORDER BY object_id),
                    CASE WHEN DATEPART(ISO_WEEK, d.YearStart) = 1 THEN -1 ELSE 0 END
            FROM sys.all_objects
        ) AS n (Weeknumber, Factor)
WHERE   DATEPART(ISO_WEEK, DATEADD(WEEK, DATEDIFF(WEEK, 0, YearStart) + n.WeekNumber + n.Factor, 0)) = n.WeekNumber;

最后的where子句将删除上周,以确保在52周内您不会包含下一年的第一周。

修改

刚刚意识到你已经有了53个数字的表格,所以你不需要自己生成:

DECLARE @Year INT = 2016;

SELECT  w.Weeknumber,
        StartOfWeek = DATEADD(WEEK, DATEDIFF(WEEK, 0, d.YearStart) + w.WeekNumber + f.Factor, 0)
FROM    (SELECT CAST(CAST(@Year AS VARCHAR(4)) + '0101' AS DATE)) AS d (YearStart)
        CROSS JOIN Weeks AS w
        CROSS APPLY (SELECT CASE WHEN DATEPART(ISO_WEEK, YearStart) = 1 THEN -1 ELSE 0 END) f (Factor)
WHERE   DATEPART(ISO_WEEK, DATEADD(WEEK, DATEDIFF(WEEK, 0, d.YearStart) + w.WeekNumber + f.Factor, 0)) = w.WeekNumber;

答案 5 :(得分:2)

检查一下:

;WITH Recur AS
(
    SELECT CAST('1/1/' + CAST(YEAR(GETDATE()) AS VARCHAR) AS DATETIME) AS RecurDate
    UNION ALL
    SELECT DATEADD(DAY, 1, RecurDate)
    FROM Recur
    WHERE YEAR(RecurDate) = YEAR(GETDATE())
)
SELECT
    CONVERT(VARCHAR, RecurDate, 103) AS [Date]
FROM
    Recur
WHERE DATENAME(WEEKDAY,RecurDate) = 'Monday'
OPTION (MAXRECURSION 0)

答案 6 :(得分:1)

也许是这样的?

DECLARE @year INT=2015;

WITH ThreeHundredSixtySixNumbers AS
(
    SELECT TOP 366 ROW_NUMBER() OVER(ORDER BY object_id) As nmbr
    FROM sys.objects --any large table with at least 366 rows
)
,FirstDayOfYear AS
(
    SELECT CAST(CONVERT(VARCHAR(4),@year) + '/1/1'  AS DATE) AS FirstDay
)
,MondayOnly AS
(
    SELECT nmbr AS DayIndex
    FROM ThreeHundredSixtySixNumbers
    WHERE ((nmbr - DATEPART(WEEKDAY,(SELECT FirstDay FROM FirstDayOfYear)))%7) = 0
)
SELECT ROW_NUMBER() OVER(ORDER BY DayIndex) AS WeekNumber
      ,DATEADD(DAY,DayIndex,(SELECT FirstDay FROM FirstDayOfYear))
FROM MondayOnly