0

次のクエリを見てください。

SELECT ID, START, END FROM TABLEA

結果は次のとおりです。

ID       START                      END
1        2012-06-07 19:32:00        2012-06-08 06:00:00
2        2012-06-08 06:00:00        NULL

しかし、私は本当に次のような結果が欲しいです:

START                      END
2012-06-07 19:32:00        2012-06-07 23:59:59
2012-06-08 00:00:00        NULL

IDは関係ありません。

そして、この例を見てください:

 ID       START                      END
    1        2012-06-06 19:32:00        2012-06-08 06:00:00
    2        2012-06-08 06:00:00        NULL

それは違いない:

        START                      END
        2012-06-06 19:32:00        2012-06-06 23:59:59
        2012-06-07 00:00:00        2012-06-07 23:59:59
        2012-06-08 00:00:00        NULL

アイデアは、同じ日の開始値と終了値を持つ行を生成することです。

前もって感謝します。

4

2 に答える 2

1

次のソリューションは、必要なすべてを SQL で実行します。重複する連続したタイムスパン (完全に重複するタイムスパンを含む) をマージし、カレンダー テーブルを使用して日付ごとに複数日のタイムスパンを分割します。

declare @TimeSheetEntries table 
    ( 
    ID int identity not null primary key, 
    [Start] datetime not null, 
    [End] datetime null 
    ); 

declare @CalendarTable table
(
    CalDate datetime
)

DECLARE @CurDate datetime = '2000-01-01 00:00:00';

WHILE @CurDate <= '2020-12-31'
BEGIN
    INSERT INTO @CalendarTable
    SELECT @CurDate;

    SELECT @CurDate = DATEADD(day,1,@CurDate);
END

insert into @TimeSheetEntries 
    ( 
    [Start], 
    [End] 
    ) 
select 
    '2012-06-06 19:32:00', 
    '2012-06-08 06:00:00' 
union all select 
    '2012-06-08 06:00:00', 
    NULL
union all select 
    '2012-06-08 02:00:00', 
    '2012-06-08 03:00:00' 
union all select 
    '2012-01-01 14:09:00', 
    '2012-01-01 17:30:00'
union all select
    '2012-01-01 18:30:00', 
    '2012-01-01 19:30:00';

WITH ClockData AS
(
    SELECT ID, [Start], [End] AS EffectiveEnd, [Start] AS LastStart, 1 AS NumTimespans
    FROM @TimeSheetEntries ts
    WHERE NOT EXISTS 
    (
        SELECT tsWhere.ID FROM @TimeSheetEntries tsWhere 
        WHERE
            tsWhere.ID <> ts.ID -- don't match yourself!
            AND tsWhere.[Start] < ts.[Start]
            AND
            (
                -- Three types of things we don't want our outer SELECT to return
                -- 1) Completed timespans with another appointment's end date sitting inside;
                -- 2) Incomplete timespans (NULL ClockedOut) with another appointment's end date after ClockedIn
                -- 3) Any timespan wholly inside another one
                (ts.[End] IS NULL AND tsWhere.[End] >= ts.[Start]) OR
                (ts.[End] IS NOT NULL AND tsWhere.[End] BETWEEN ts.[Start] AND ts.[End]) OR
                (tswhere.[End] > ts.[End])
            )
    )

    UNION ALL

    SELECT cd.ID, cd.[Start], ts.[End] AS EffectiveClockout, ts.Start AS LastStart, cd.NumTimespans + 1 AS NumTimespans
    FROM @TimeSheetEntries ts
    INNER JOIN ClockData cd
            ON ts.[Start] BETWEEN cd.[Start] AND cd.EffectiveEnd AND ts.ID <> cd.ID 
                AND (ts.[End] IS NULL OR ts.[End] > cd.EffectiveEnd)
),
MergedTimespans AS
(
    SELECT [ID], [Start], [EffectiveEnd], [LastStart]
    FROM ClockData cd
    WHERE NumTimespans = (SELECT MAX(NumTimespans) FROM ClockData WHERE ID = cd.ID)
)
SELECT 
    CASE 
        WHEN mt.Start > cal.CalDate 
            THEN mt.Start 
        ELSE cal.CalDate 
    END AS [Start],
    CASE 
        WHEN (mt.EffectiveEnd IS NOT NULL AND mt.EffectiveEnd >= DATEADD(day,1,cal.CalDate)) OR (mt.EffectiveEnd IS NULL AND cal.CalDate < CAST(mt.LastStart AS date)) THEN DATEADD(second, -1,DATEADD(day,1,cal.CalDate))
        ELSE mt.EffectiveEnd
    END AS [End]
FROM MergedTimespans mt
    INNER JOIN @CalendarTable cal
        ON (mt.EffectiveEnd IS NULL AND cal.CalDate BETWEEN CAST(mt.Start AS date) AND mt.LastStart) -- Handle NULL end dates
         OR (mt.EffectiveEnd IS NOT NULL AND cal.CalDate BETWEEN CAST(mt.Start AS date) AND mt.EffectiveEnd)
ORDER BY Start
于 2012-06-08T16:39:22.880 に答える
0
 with       cte
      AS ( SELECT   MIN(START) AS MinStart ,
                    MAX(START) AS MaxStart
           FROM     TableA
           UNION ALL
           SELECT   DATEADD(DAY, 1, MinStart) ,
                    MaxStart
           FROM     cte
           WHERE    DATEADD(DAY, 1, MinStart) BETWEEN MinStart AND MaxStart
         )
SELECT  MinStart AS START ,
        DATEADD(millisecond, -3, FLOOR(CAST(MinStart AS FLOAT)) + 1) AS [End]
FROM    cte
于 2012-06-08T15:36:57.990 に答える