我有一张开始时间和持续时间的表格,其中一些持续时间超过了下一个开始时间。我希望以更正下一个开始时间的方式选择数据-
编辑,但时间不会减少!
我正在SQL Server 2016上运行此查询。我已经尝试使用LEAD和LAG,但无法使其正常工作。
原始表格是
| BeginTime | Duration |
------------------------
| 6:00 | 75 |
| 7:00 | 45 |
| 7:45 | 60 |
| 9:00 | 90 |
| 11:00 | 60 |
| 11:30 | 30 |
------------------------
输出应为
| BeginTime | Duration |
------------------------
| 6:00 | 75 |
| 7:15 | 45 |
| 8:00 | 60 |
| 9:00 | 90 |
| 11:00 | 60 |
| 12:00 | 30 |
------------------------
答案 0 :(得分:2)
您可以尝试使用一些聚合函数
LAG
窗口功能与DATEADD
SUM
窗口函数以累积Duration
个值。然后,唯一带有total
列值的时间就是来自子查询。
与MIN(BeginTime)
女巫的最终加法时间是指开始时间。
查询1 :
SELECT (CASE WHEN rn = 1 THEN BeginTime
ELSE DATEADD(MINUTE,LAG(total) OVER(ORDER BY BeginTime),MIN(BeginTime) OVER(ORDER BY BeginTime)) END) BeginTime
,Duration
FROM (
SELECT *,
SUM(Duration) OVER(ORDER BY BeginTime) total,
ROW_NUMBER() OVER(ORDER BY BeginTime) rn,
LAG(BeginTime) OVER(ORDER BY BeginTime) privous
FROM T
) t1
Results :
| BeginTime | Duration |
|------------------|----------|
| 06:00:00.0000000 | 75 |
| 07:15:00.0000000 | 45 |
| 08:00:00.0000000 | 60 |
| 09:00:00.0000000 | 90 |
答案 1 :(得分:1)
--Sample
SELECT CAST('6:00' as TIME) as BeginTime, 75 as Duration
INTO #Temp --drop table #Temp
UNION ALL
SELECT '7:00',45
UNION ALL
SELECT '7:15',45
UNION ALL
SELECT '7:45',60
UNION ALL
SELECT '8:00',60
UNION ALL
SELECT '9:00',90
--Query starts from here
DECLARE @MinTime TIME
SELECT @MinTime = MIN(BeginTime) FROM #Temp
DECLARE @MaxTime TIME
SELECT @MaxTime = MAX(BeginTime) FROM #Temp
;
WITH A(BeginTime, Duration)
AS
(
SELECT BeginTime, Duration FROM #Temp where BeginTime = @MinTime
UNION ALL
SELECT DATEADD(mi,A.Duration,A.BeginTime),B.Duration
FROM A
INNER JOIN #Temp as B
ON B.BeginTime = DATEADD(mi,A.Duration,A.BeginTime)
WHERE DATEADD(mi,A.Duration,A.BeginTime) < = @MaxTime
)
SELECT * FROM A
编辑答案:
在这种情况下,所有其他BeginTime
都是无用的,您需要总结的是Duration
与第一个BeginTime
的总数:
SELECT CAST('6:00' as TIME) as BeginTime, 75 as Duration, 1 as [Count]
INTO #Temp --drop table #Temp
UNION ALL
SELECT '7:00',45, 2
UNION ALL
SELECT '8:00',60, 3
UNION ALL
SELECT '9:00',90,4
UNION ALL
SELECT '10:00',60,5
UNION ALL
SELECT '11:00',30,6
DECLARE @MinTime Time
SELECT @MinTime = MIN(BeginTime) FROM #Temp
SELECT BeginTime,Duration FROM #Temp WHERE BeginTime = @MinTime
UNION ALL
SELECT DATEADD(MI,SUM(B.Duration), @MinTime) as BeginTime,
A.Duration
FROM #Temp as A
INNER JOIN #Temp as B
ON B.[Count] < A.[Count]
WHERE A.BeginTime != @MinTime
GROUP BY A.Duration, A.[Count]
ORDER BY BeginTime
答案 2 :(得分:0)
我的一个朋友能够解决问题-这是解决方案:
--DROP TABLE #a;
CREATE TABLE #a
(
BeginTime DATETIME,
Duration INT,
BeginTimeNew DATETIME
);
INSERT INTO #a
(
BeginTime,
Duration
)
VALUES
('20190828 8:00:00', 75),
('20190828 9:00:00', 30),
('20190828 10:00:00', 45),
('20190828 11:00:00', 90),
('20190828 12:00:00', 75),
('20190828 13:00:00', 15),
('20190828 14:00:00', 75),
('20190828 15:00:00', 60);
SELECT *
FROM #a
ORDER BY BeginTime,
Duration
;
WITH rownumber
AS (SELECT r = ROW_NUMBER() OVER (ORDER BY BeginTime, Duration),
BeginTime,
Duration
FROM #a),
cte
AS (SELECT r,
OrigBeginTime = BeginTime,
Duration,
LV = 1,
BeginTime,
EndTime = DATEADD(minute, Duration, BeginTime)
FROM rownumber
WHERE r = 1
UNION ALL
SELECT a.r,
a.BeginTime,
a.Duration,
b.LV + 1,
BeginTime = IIF(b.EndTime >= a.BeginTime, b.EndTime, a.BeginTime),
EndTime = DATEADD(minute, a.Duration, IIF(b.EndTime >= a.BeginTime, b.EndTime, a.BeginTime))
FROM rownumber a
INNER JOIN cte b
ON a.r = b.r + 1)
UPDATE a
SET BeginTimeNew = b.BeginTime
FROM #a a
INNER JOIN cte b
ON a.BeginTime = b.OrigBeginTime
AND a.Duration = b.Duration
OPTION (MAXRECURSION 0);
SELECT *
FROM #a
ORDER BY BeginTime,
Duration