请查看以下查询:
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
我们的想法是在同一天内生成包含起始值和结束值的行。
提前致谢。
答案 0 :(得分: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
答案 1 :(得分: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