鉴于从CREATE FUNCTION
documentation适当的ISO一周功能(有一些调整,对所有的坏习惯都在那里,恕我直言):
CREATE FUNCTION dbo.ISOWeek
(
@dt SMALLDATETIME
)
RETURNS TINYINT
AS
BEGIN
DECLARE @ISOweek TINYINT;
SET @ISOweek = DATEPART(WEEK, @dt) + 1
-DATEPART(WEEK, RTRIM(YEAR(@dt)) + '0104');
IF @ISOweek = 0
BEGIN
SET @ISOweek = dbo.ISOweek
(
RTRIM(YEAR(@dt)-1)+'12'+RTRIM(24 + DAY(@dt))
) + 1;
END
IF MONTH(@dt) = 12 AND DAY(@dt) - DATEPART(DAYOFWEEK, @dt) >= 28
BEGIN
SET @ISOweek = 1;
END
RETURN(@ISOweek);
END
GO
我们可以创建一个表是这样的:
CREATE TABLE dbo.ISOWeekCalendar
(
[Date] SMALLDATETIME PRIMARY KEY,
ISOWeekNumber TINYINT,
[Year] INT,
ISOWeek CHAR(8)
);
CREATE UNIQUE INDEX iw ON dbo.ISOWeekCalendar(ISOWeek);
我们可以从年中的任何范围的数据来填充它,这里采用ISO周1-52为2000至29年:
DECLARE @StartDate SMALLDATETIME,
@EndDate SMALLDATETIME;
SELECT @StartDate = '20000102',
@EndDate = '20291229';
INSERT dbo.ISOWeekCalendar([Date])
SELECT TOP (DATEDIFF(DAY, @StartDate, @EndDate)+1) n
= DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY s1.[object_id])-1, @StartDate)
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id];
现在我们可以更新数据。
-- delete all non-Mondays:
SET DATEFIRST 1;
DELETE dbo.ISOWeekCalendar WHERE DATEPART(WEEKDAY, [Date]) <> 1;
-- put the proper ISO week number:
UPDATE dbo.ISOWeekCalendar SET ISOWeekNumber = dbo.ISOWeek([Date]);
-- put the year:
UPDATE dbo.ISOWeekCalendar SET [Year] = DATEPART(YEAR, [Date]);
-- update to the correct year for fringe days:
UPDATE dbo.ISOWeekCalendar SET [Year] = [Year] + 1
WHERE ISOWeekNumber = 1 AND MONTH([Date]) = 12;
-- finally, build the calculated value for YYYY-W##:
UPDATE dbo.ISOWeekCalendar
SET ISOWeek = RTRIM([Year]) + '-W' + RIGHT('0' + RTRIM(ISOWeekNumber), 2);
请注意,以上只需要做一次。现在,我们可以运行一个非常简单的查询给予我们的输入:
SELECT [Date] FROM dbo.ISOWeekCalendar WHERE ISOWeek = '2012-W02';
结果:
Date
-------------------
2012-01-09 00:00:00
我们甚至可以创建一个函数,这是否:
CREATE FUNCTION dbo.ISOWeekDate(@ISOWeek CHAR(8))
RETURNS SMALLDATETIME
WITH SCHEMABINDING
AS
BEGIN
RETURN (SELECT [Date] FROM dbo.ISOWeekCalendar
WHERE ISOWeek = @ISOWeek);
END
GO
而且一个函数去另一种方式:
CREATE FUNCTION dbo.ISOWeekFromDate(@Date SMALLDATETIME)
RETURNS CHAR(8)
WITH SCHEMABINDING
AS
BEGIN
RETURN (SELECT TOP (1) ISOWeek FROM dbo.ISOWeekCalendar
WHERE [Date] <= @Date
ORDER BY [Date] DESC);
END
GO
阙RY:
SELECT dbo.ISOWeekDate('2012-W02'), dbo.ISOWeekFromDate('20120110');
结果:
------------------- --------
2012-01-09 00:00:00 2012-W02
是的,它是一个更小的前期工作比复杂的查询,但我更喜欢易用性和更清晰的查询语义。
能否请你展示一些样品的输入/输出(确保包括在今年的前几个星期为天以及一些两位数周)? ISO 8601星期日期如何存储? – 2012-07-06 20:55:07
每周第一天的价值就足够了。同样,由于没有提供组件,因此要求允许假定第一天。 – kingrichard2005 2012-07-06 21:09:32
“2012-W02”不应该产生“2012-01-08”吗?你能证明哪一条规则使它成为第9名? – 2012-07-06 21:23:04