鑑於從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