我已经搜索了一遍又一遍,但只是不知道该怎么写。如果有人问过,请原谅我。
我有需要“展平”的日程表数据。看起来像这样:
DATE START END CODE
10/1 0700 1530 WORK -- encompasses the entire shift of the employee
10/1 1015 1030 BREAK
10/1 1200 1230 LUNCH
10/1 1400 1415 BREAK
我需要它看起来像以下内容(基本上删除重叠部分并创建连续的片段):
DATE START END CODE
10/1 0700 1015 WORK
10/1 1015 1030 BREAK
10/1 1030 1200 WORK
10/1 1200 1230 LUNCH
10/1 1230 1400 WORK
10/1 1400 1415 BREAK
10/1 1415 1530 WORK
我似乎找不到任何明智的方法来做到这一点。有什么想法吗?
答案 0 :(得分:4)
这看起来非常复杂,因为我也必须在SQL中进行统计,但是,我建议为此创建一个持久对象。另外,由于您希望时间重叠,因此我必须调整最后SELECT
的值。无论如何,这似乎可行:
CREATE TABLE dbo.YourTable ([Date] date,
[Start] char(4),
[End] char(4),
Code varchar(5));
GO
INSERT INTO dbo.YourTable (Date,
Start,
[End],
Code)
VALUES ('20190110', '0700', '1530', 'WORK'),
('20190110', '1015', '1030', 'BREAK'),
('20190110', '1200', '1230', 'LUNCH'),
('20190110', '1400', '1415', 'BREAK');
GO
--Create a Time Table on the fly
--First some NULL values
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
--Now a Tally
Tally AS(
SELECT TOP (1440) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
FROM N N1, N N2, N N3, N N4),
--And finally some formatting cause
TimeTable AS(
SELECT REPLACE(CONVERT(varchar(5),DATEADD(MINUTE,T.I,'00:00'),108),':','') AS [Time]
FROM Tally T),
--Put into Groups
Grps AS(
SELECT YT1.Date,
TT.Time,
ISNULL(YT2.Code,YT1.Code) AS Code,
ROW_NUMBER() OVER (PARTITION BY YT1.[date] ORDER BY TT.[Time]) -
ROW_NUMBER() OVER (PARTITION BY YT1.[date],ISNULL(YT2.Code,YT1.Code) ORDER BY TT.[Time]) AS Grp,
MIN(YT1.[Start]) OVER (PARTITION BY YT1.[date]) AS DayStart,
MAX(YT1.[End]) OVER (PARTITION BY YT1.[date]) AS DayEnd
FROM dbo.YourTable YT1
JOIN TimeTable TT ON YT1.[Start] <= TT.Time
AND YT1.[End] >= TT.Time
LEFT JOIN dbo.YourTable YT2 ON YT1.Date = YT2.Date
AND YT2.[Start] <= TT.Time
AND YT2.[End] >= TT.Time
AND YT2.Code != 'Work'
WHERE YT1.Code = 'WORK')
SELECT G.[Date],
MIN([Time]) + CASE WHEN G.Code = 'Work' AND MIN(Time) != G.DayStart THEN -1 ELSE 0 END AS StartTime,
MAX([Time]) + CASE WHEN G.Code = 'Work' AND MAX(Time) != G.DayEnd THEN 1 ELSE 0 END AS EndTime,
G.Code
FROM Grps G
GROUP BY G.Date,
G.Code,
G.Grp,
G.DayStart,
G.DayEnd
ORDER BY G.Date,
StartTime;
GO
DROP TABLE dbo.YourTable;
答案 1 :(得分:2)
这里是一种方法,它首先使用UNION作为开始时间和结束时间来构建所有时间的列表。
然后在第二个CTE中使用LEAD从下一条记录计算结束时间。
WITH CTE1 AS
(
SELECT [date], [start], [code]
FROM timeregistration
UNION
SELECT [date], [end], 'WORK'
FROM timeregistration
),
CTE2 AS
(
SELECT [date], [start], [code],
LEAD([start]) OVER (PARTITION BY [date] ORDER BY [start]) AS [end]
FROM CTE1
)
SELECT [date], [start], [end], [code]
FROM CTE2
WHERE [end] IS NOT NULL
ORDER BY [date], [start];
在妊娠here上进行的测试