繁体   English   中英

SQL 服务器每年的第一个星期一

[英]First Monday of the Year in SQL Server

如何使用 T-SQL 找到“一年中的第一个星期一”?

这是 ngruson 发布的链接中的示例( http://sqlbump.blogspot.nl/2010/01/first-monday-of-year.html ):

DECLARE @Date datetime
DECLARE @Year int = 2012

SET @Date = DATEADD(YEAR, @Year - 1900, 0)

SELECT DATEADD(DAY, (@@DATEFIRST - DATEPART(WEEKDAY, @Date) + 
    (8 - @@DATEFIRST) * 2) % 7, @Date)

以上返回:

2012-01-02 00:00:00.000
    Here, 
    1) DATEPART function for finding day of week. 
Here 1=sunday,2=monday,..,7=saturday.
    2) first find out is 2(monday) in case when
 condition then get same date,
    3) if is sunday(1) then add 1 day and get next
 day date is for monday,
    4) if is not 2(monday) and greater then 2 then find 
difference between lastday(7) and add 2 days ,
 so we reach to monday date.

    Here are you change year in @year variable. Ex:

        DECLARE @Date datetime
        DECLARE @Year int = 2012

        set @Date= convert(varchar(4),@Year) + '-01-01'
        select @Date,(case when DATEPART(DW,@Date)=2 then @Date
                     when DATEPART(DW,@Date)=1 then DATEADD(day,1,@Date)
                     else DATEADD(day,7-DATEPART(DW,@Date)+2,@Date)
                      end) as MondayDateis

优雅不是;)

    DECLARE @year DATETIME = '01 jan 2012'

    SELECT [Day] 
    FROM
        (
            SELECT @year [Day] UNION ALL
            SELECT DATEADD(DAY, 1, @year) UNION ALL
            SELECT DATEADD(DAY, 2, @year) UNION ALL
            SELECT DATEADD(DAY, 3, @year) UNION ALL
            SELECT DATEADD(DAY, 4, @year) UNION ALL
            SELECT DATEADD(DAY, 5, @year) UNION ALL
            SELECT DATEADD(DAY, 6, @year)
        ) x
    WHERE
        DATENAME(DW, [Day]) = 'Monday'

这是实现这一目标的一个示例:

http://sqlbump.blogspot.nl/2010/01/first-monday-of-year.html

试试这个:

declare @yr int=2020
select case when datepart(weekday,dateadd(year,@yr-1900,0))=1 then dateadd(year,@yr-1900,1)
       else dateadd(dd,8-(datepart(weekday,dateadd(year,@yr-1900,0))),dateadd(year,@yr-1900,1))
end

SQL 小提琴演示

这种方法不使用像 1900 年这样的魔法年份或魔法日期。

DECLARE @first_year_day     DATE,
        @first_year_monday  DATE,
        @year               int = 2017

SET @first_year_day    = CAST('1/1/' + str(@year, 4) AS DATE)
SET @first_year_monday    = DATEADD(day, (9 - DATEPART(dw, @first_year_day)) % 7, @first_year_day)
SELECT @first_year_monday

该代码仅在 SQL Server 首选项中将周配置为从星期日开始时才有效。 这是大多数英语安装的默认设置(在这种情况下,SELECT @@DATEFIRST 将返回 7)

我需要按周对一些数据进行分组并显示每周的第一天(在我的情况下是星期日)。 我使用以下内容来计算一年的第一个星期日,然后您可以使用周数来获取给定日期发生的一周的开始。

DECLARE @firstSundayThisYear DATE,
    @jan1ThisYear DATE,
    @currentYear INT;

SELECT @jan1ThisYear = '01-jan-' + CAST(DATEPART(YEAR, GETDATE()) AS VARCHAR(4)),
    @currentYear = DATEPART(YEAR, GETDATE());

SET @firstSundayThisYear = DATEADD(DAY, -DATEPART(weekday, @jan1ThisYear) + 1, @jan1ThisYear);

PRINT @firstSundayThisYear

注意:@firstSundayThisYear 实际上可能是去年的日期,但是当您乘以周数时,一切都会解决。

我知道这是一个 8 岁的问题,但我想无论如何我都会把帽子扔进戒指

下面的第一个片段创建了一个测试表,以证明后面的代码不会遇到任何 RBAR 问题。 解决方案实际上是填充第二个片段结果中的“FirstMondayOfYear”列的相当短的公式。 其他一切只是为了添加到演示中。 不需要单独的 SET,不需要 CASE 语句,也不需要对 DATEFIRST 的引用。

--===== Create a test table that contains random dates and times from 1900-01-01 up to and not
     -- including 2100-01-01.
   DROP TABLE IF EXISTS #MyHead
;
 SELECT TOP 100000
        SomeDateTime = RAND(CHECKSUM(NEWID()))*DATEDIFF(dd,'1900','2100')+CONVERT(DATETIME,'1900') --Inherently DATETIME
--        SomeDateTime = CONVERT(DATETIME2(7),RAND(CHECKSUM(NEWID()))*DATEDIFF(dd,'1900','2100')+CONVERT(DATETIME,'1900')) --DATETIME2()
--        SomeDateTime = CONVERT(DATE,ABS(CHECKSUM(NEWID())%DATEDIFF(dd,'1900','2100'))+CONVERT(DATETIME,'1900')) --DATE
   INTO #MyHead
   FROM      sys.all_columns ac1
  CROSS JOIN sys.all_columns ac2
;
--===== Return the first Monday for the year of each given date (and the original date) as well
     -- as a weekday name and day check for the date created by the formula.  The FirstMondayOfYear
     -- should (obviously) always be a Monday and it should always be a day of 7 or less.
   WITH cteFindMonday AS
(
 SELECT  SomeDateTime
        ,FirstMondayOfYear  = DATEADD(dd,(DATEDIFF(dd,'1753',DATENAME(yy,SomeDateTime))+6)/7*7,'1753')
   FROM #MyHead
)
 SELECT  SomeDateTime
        ,FirstMondayOfYear
        ,DoW     = DATENAME(dw,FirstMondayOfYear)
        ,IsValid =  IIF(    DATENAME(dw,FirstMondayOfYear) = 'Monday'
                        AND DATEPART(dd,FirstMondayOfYear) <= 7 
                    ,1,0)
   FROM cteFindMonday
  ORDER BY SomeDateTime
;

我不知道为什么这里的答案非常简单,真的:

    // You can try any year
    DECLARE @YEAR INT = 2021
    // First you get the first day of the year
    DECLARE @FIRST_DAY_OF_YEAR DATE = CAST(@YEAR AS VARCHAR(4)) + '-01-01'
    // Then you get its weekday
    DECLARE @FIRST_DAY_OF_YEAR_WEEKDAY INT = DATEPART(WEEKDAY,@FIRST_DAY_OF_YEAR)
    // Then it's just a CASE matter, where you must see if the actual first day of the year is itself a monday or a sunday. If it's a monday we just return the first day, if it's a sunday we just add 1, if it's anything else beyond that we just have to substract the weekday from 9 (which is essentialy the second monday of the year). And we add the result to whichever day of the week is our first day of the year and we always get our first monday
    DECLARE @FIRST_MONDAY_OF_YEAR DATE =
    CASE
        WHEN @FIRST_DAY_OF_YEAR_WEEKDAY = 2 THEN @FIRST_DAY_OF_YEAR
        WHEN @FIRST_DAY_OF_YEAR_WEEKDAY = 1 THEN DATEADD(DAY, 1, @FIRST_DAY_OF_YEAR)
        ELSE DATEADD(DAY, 9 - @FIRST_DAY_OF_YEAR_WEEKDAY, @FIRST_DAY_OF_YEAR)
    END

    SELECT @FIRST_MONDAY_OF_YEAR
-- for specific date
DECLARE @date DATETIME = '20220909'
SELECT CAST(DATEADD(WEEK, - (DATEPART(DAYOFYEAR, @date) / 7) + 1, @date - (DATEPART(WEEKDAY, @date) - 2)) AS DATE);
-- for current date
SELECT CAST(DATEADD(WEEK, - (DATEPART(DAYOFYEAR, GETDATE()) / 7) + 1, GETDATE() - (DATEPART(WEEKDAY, GETDATE()) - 2)) AS DATE);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM