我想在给定年份的第一个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
答案 0 :(得分:1)
除非我误解了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 :(得分:1)
我会创建一个值为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
然后这个存储过程应该给你正确的结果
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
不知道这个解决方案是否优于其他发布的解决方案。可能更快或更慢,更容易理解与否。我想这取决于你的偏好。我使用您现有的代码作为存储过程的开头,但您应该调整代码以简化Monday0(前一个ISO年的最后一个星期一)的计算