1

ISO 8601 形式で指定された曜日 (つまり、YYYY-W##) の日を特定しようとしています。私の最終目標は、ISO 8601 Week Date を ISO 8601 Calendar Date に変換することです。私は TSQL でこれを行う必要があります (私は SQL Server 2005 で作業しています)。これを可能にする SQL Server 05 に既に組み込まれているものがあるかどうかはわかりませんが、別の言語または一般的な擬似コードで

アップデート:

私の質問の構造がわかりにくい場合は申し訳ありません。基本的に、ISO8601カレンダー日付に変換しようとしているISO8601週の日付があります。

例 (ウィキペディアから)

ISO 8601 週の日付: 2012-W02 (YYYY-W##)

に変換...

ISO 8601 カレンダー日付: 2012-01-09 (YYYY-MM-DD)

私の週の日付の例では日のコンポーネントが指定されていないため、週の最初の曜日を想定できます。

4

2 に答える 2

2

次の解決策を試してください。

declare 
    @date varchar(10)
    ,@convertedDate datetime
    ,@wk int
    ,@yr int

set @date = '2012-W02';

set @yr = parsename(replace(@date, '-W', '.'), 2)
set @wk = parsename(replace(@date, '-W', '.'), 1)

set @convertedDate = convert(varchar(10), dateadd(week, @wk, dateadd (year, @yr-1900, 0)) - 5 - datepart(dw, dateadd (week, @wk, dateadd (year, @yr-1900, 0))), 121)

select 
    'Year' = @yr
    ,'Week' = @wk
    ,'Date' = @convertedDate

出力:

-----------------------------------------
| Year | Week |         Date            |
-----------------------------------------
| 2012 |   2  | 2012-01-09 00:00:00.000 |
-----------------------------------------
于 2012-07-06T21:25:46.193 に答える
0

CREATE FUNCTIONドキュメントから適切な ISO 週関数が与えられた場合(そこにあるすべての悪い習慣にいくつかの調整を加えて、IMHO):

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);

これには、2000 ~ 2029 年の ISO 週 1 ~ 52 を使用して、任意の範囲のデータを入力できます。

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

クエリ:

SELECT dbo.ISOWeekDate('2012-W02'), dbo.ISOWeekFromDate('20120110');

結果:

-------------------    --------
2012-01-09 00:00:00    2012-W02

はい、複雑なクエリよりも前もっての作業が少し増えますが、私は使いやすさとより明確なクエリ セマンティクスを好みます。

于 2012-07-06T20:46:07.830 に答える