![](/img/trans.png)
[英]T-SQL How to get Week Number (ISO) of First Week from all Quarters from GetDate()?
[英]T-SQL calculate the first monday of the first ISO week in a year and enumerate all weeks as from-to periods
我想计算给定年份中第一个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
我也正在寻找一种方法,以枚举从第一个星期一开始的所有ISO周为周期表,其中包含StartDate,EndDate,Year,Month,ISOWeekNo列。 如果有人知道快速干净的解决方案,请提供帮助。
我进行了很少的编辑,因此可以根据需要进行工作-以Outlook日历方式枚举一年中的几周:
CREATE FUNCTION [dbo].[FGetISOWeeks](@y int)
RETURNS
@ISOWeeks TABLE (StartDate Date NOT NULL, EndDate Date NOT NULL, YearNo int not null, MonthNo int not null, WeekNo int not null)
AS
BEGIN
DECLARE @weeknumbers as TABLE ( weeknum int not null primary key (weeknum)) -- helper table of week numbers
declare @weeknum int = 1
while (@weeknum <= 53)
begin
insert @weeknumbers values(@weeknum)
set @weeknum = @weeknum + 1
end
DECLARE @firstDayOfYear date = CAST(CAST(@y AS varchar(4)) + '-01-01' AS DATE)
DECLARE @Thursday date = DATEADD(day,3 - (DATEPART(dw, @firstDayOfYear) + @@DATEFIRST - 2) % 7,@firstDayOfYear) --thursday before 1st Jan
DECLARE @FirstDayOfIsoWeek date = DATEADD(day, - (DATEPART(dw, @firstDayOfYear) + @@DATEFIRST - 2) % 7, @firstDayOfYear)
if (@Thursday<@firstDayOfYear) SELECT @FirstDayOfIsoWeek = DATEADD(d,7, @FirstDayOfIsoWeek) -- calculate first day of iso year
declare @Monday0 date = DATEADD(d,-7, @FirstDayOfIsoWeek)
INSERT INTO @ISOWeeks
select DATEADD(WEEK, N.weeknum, @Monday0) as StartDate
,DATEADD(day, 7*N.weeknum+6, @Monday0) as EndDate, @y as YearNo
,DATEPART(month, DATEADD(DAY, 7*N.weeknum+3, @Monday0)) as MonthNo
,DATEPART(ISO_WEEK, DATEADD(WEEK, N.weeknum, @Monday0)) as WeekNo
from @weeknumbers N
where DATEPART(year, DATEADD(day, 7*N.weeknum+3, @Monday0)) = @y
order by N.weeknum
RETURN
END
除非我误解了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
然后,此存储的proc应该会给您正确的结果
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
不知道这种解决方案是否比其他发布的解决方案更好。 也许更快或更慢,更容易理解与否。 我想这取决于您的偏好。 我使用您现有的代码作为存储过程的开头,但是您应该调整代码以简化星期一0(上一ISO年的最后一个星期一)的计算。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.