如何使用 T-SQL 找到“一年中的第一个星期一”?
9 回答
这是 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 Fiddle 演示
这种方法不使用像 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 实际上可能是去年的日期,但是当您乘以周数时,一切都会解决。
我不确切知道为什么这里的答案很简单,真的很详细:
// 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
我知道这是一个 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
;