我需要将每行复制的次数与StartTime
和EndTime
之间的小时数相同。
示例数据:
TimeKey HourKey SensorKey IdleTimeMinute StartTime EndTime
20121017 8 45 110 2012.10.17 08:31 2012.10.17 10:21
20121017 10 45 25 2012.10.17 10:26 2012.10.17 10:51
20121017 12 45 5 2012.10.17 12:21 2012.10.17 12:26
20121017 12 45 60 2012.10.17 12:41 2012.10.17 13:41
20121017 13 45 55 2012.10.17 13:51 2012.10.17 14:46
20121017 15 45 5 2012.10.17 15:11 2012.10.17 15:16
20121017 15 45 35 2012.10.17 15:46 2012.10.17 16:21
20121017 18 45 5 2012.10.17 18:51 2012.10.17 18:56
解释
例如,第一行跨越小时8,9和10.在三个输出行的每一行中,IdleTimeMinute
必须是该小时内的分钟持续时间。
预期结果:
TimeKey HourKey SensorKey IdleTimeMinute StartTime EndTime
20121017 8 45 29 2012.10.17 08:31 2012.10.17 10:21
20121017 9 45 60 2012.10.17 08:31 2012.10.17 10:21
20121017 10 45 21 2012.10.17 08:31 2012.10.17 10:21
20121017 10 45 25 2012.10.17 10:26 2012.10.17 10:51
20121017 12 45 5 2012.10.17 12:21 2012.10.17 12:26
20121017 12 45 19 2012.10.17 12:41 2012.10.17 13:41
20121017 13 45 41 2012.10.17 12:41 2012.10.17 13:41
20121017 13 45 9 2012.10.17 13:51 2012.10.17 14:46
20121017 14 45 46 2012.10.17 13:51 2012.10.17 14:46
20121017 15 45 5 2012.10.17 15:11 2012.10.17 15:16
20121017 15 45 14 2012.10.17 15:46 2012.10.17 16:21
20121017 16 45 21 2012.10.17 15:46 2012.10.17 16:21
20121017 18 45 5 2012.10.17 18:51 2012.10.17 18:56
较小的示例
前两行中较小的例子:
TimeKey HourKey SensorKey IdleTimeMinute StartTime EndTime
20121017 8 45 110 2012.10.17 08:31 2012.10.17 10:21
20121017 10 45 25 2012.10.17 10:26 2012.10.17 10:51
对于第一行,我们有时间8:31 - 10:21
所以8小时29分钟,9小时60分钟,10小时21分钟。
预期的小结果:
TimeKey HourKey SensorKey IdleTimeMinute StartTime EndTime
20121017 8 45 29 2012.10.17 08:31 2012.10.17 10:21
20121017 9 45 60 2012.10.17 08:31 2012.10.17 10:21
20121017 10 45 21 2012.10.17 08:31 2012.10.17 10:21
20121017 10 45 25 2012.10.17 10:26 2012.10.17 10:51
答案 0 :(得分:0)
这有点乱,但基于你可以做的SQL小提琴
CREATE TABLE #Temp (RowNumber INT Identity(1,1),[TimeKey] int, [HourKey] int,
[SensorKey] int, [IdleTimeMinute] int, [StartTime] datetime, [EndTime] datetime)
INSERT INTO #Temp
SELECT *
FROM Table1
DECLARE @i INT = 1
DECLARE @StartTime DATETIME, @EndTime DATETIME
DECLARE @Total INT = (SELECT COUNT(*) FROM #Temp)
DECLARE @x INT = 1
DECLARE @TotalHours INT = 0
WHILE @i <= @Total + 1
BEGIN
SET @StartTime = (SELECT StartTime FROM #temp WHERE RowNumber = @i)
SET @EndTime = (SELECT EndTime FROM #temp WHERE RowNumber = @i)
SET @x = 1
SET @TotalHours = (SELECT DATEDIFF(Hour,@StartTime,@EndTime))
WHILE @x <= @TotalHours
BEGIN
INSERT INTO Table2 SELECT * FROM #Temp WHERE RowNumber = @i
SET @x = @x + 1
END
SET @i = @i + 1
END
SELECT * FROM Table2
假设您有第二个具有此布局的表
CREATE TABLE Table2
(RowNumber INT, [TimeKey] int, [HourKey] int, [SensorKey] int, [IdleTimeMinute] int, [StartTime] datetime, [EndTime] datetime)
;
答案 1 :(得分:0)
你可以试试这个。生成序列的限制。如果您的IdleTimeMinute
出乎意料,那么您必须使用CTE中的OPTION (MAXRECURSION n)
。查询可以从SQL Server 2005+运行。对于旧版本,您必须使用自己的序列生成机制。
;WITH Times
AS
(
SELECT 1 Id
UNION ALL
SELECT Id + 1
FROM Times
WHERE Id < 100
)
SELECT
R.* ,
CASE WHEN (IDLETIMEMINUTE - 60 * (T.Id - 1)) / 60 > 0
THEN 60
ELSE (IDLETIMEMINUTE % 60)
END IDLETIMEMINUTE_New
FROM Table1 R
JOIN Times T
ON T.Id <= CEILING(R.[IdleTimeMinute]/60.0)
<强> SQL FIDDLE DEMO 强>
答案 2 :(得分:0)
WITH q(n) AS
(
SELECT 0
UNION ALL
SELECT n + 1
FROM q
WHERE n <23
)
select TimeKey,
q.n as HourKey,
SensorKey,
(select min(V) from
(select ETime-q.n*60 as V
union all
select ((q.n+1)*60)-sTime as V
union all
select 60 as V
) x
) as IdleTimeMinute,
StartTime,
EndTime
from q
join
(
select *,
DATEPART(HOUR, starttime)*60
+DATEPART(MINUTE, starttime) sTime,
DATEPART(HOUR, Endtime)*60
+DATEPART(MINUTE, Endtime) eTime
from
table1
) t1
on q.n*60 between (t1.sTime/60)*60 and t1.eTime
order by TimeKEy,SensorKey,HourKey,StartTime
答案 3 :(得分:0)
你走了。这将处理时间跨度超过午夜或持续数天的情况。它应该表现得很好。
DECLARE @MaxHour int = IsNull((SELECT Max(DateDiff(hour, StartTime, EndTime)) + 1 FROM dbo.Table1), 0);
WITH L0 AS (SELECT 1 N UNION ALL SELECT 1),
L1 AS (SELECT 1 N FROM L0, L0 B),
L2 AS (SELECT 1 N FROM L1, L1 B),
L3 AS (SELECT 1 N FROM L2, L2 B),
L4 AS (SELECT 1 N FROM L3, L3 B),
L5 AS (SELECT 1 N FROM L4, L4 B),
Nums AS (SELECT Num = Row_Number() OVER (ORDER BY (SELECT 1)) FROM L5)
SELECT
TimeKey = Convert(int, Convert(char(8), S.HourStartTime, 112)),
HourKey = DatePart(hour, S.HourStartTime),
T.SensorKey,
IdleTimeMinute = DateDiff(minute, S.HourStartTime, E.HourEndTime),
T.StartTime,
T.EndTime,
S.HourStartTime,
E.HourEndTime
FROM
dbo.Table1 T
CROSS APPLY (
SELECT AnchorHour = DateAdd(hour, DateDiff(hour, 0, T.StartTime) + N.Num - 1, 0)
FROM Nums N
WHERE
DateDiff(hour, T.StartTime, T.EndTime) + 1 >= N.Num
AND N.Num <= @MaxHour
) D
CROSS APPLY (
SELECT HourStartTime = Max(StartTime)
FROM (VALUES (D.AnchorHour), (T.StartTime)) S (StartTime)
) S
CROSS APPLY (
SELECT HourEndTime = Min(EndTime)
FROM (VALUES (DateAdd(hour, 1, D.AnchorHour)), (T.EndTime)) E (EndTime)
) E
ORDER BY
TimeKey,
StartTime,
HourKey;
我包含所选小时的新时间跨度。如果您希望该时间跨度在下一个小时的:59
而不是:00
结束,则在第三个CROSS APPLY
更改DateAdd(hour, 1, D.AnchorHour)
到DateAdd(minute, 59, D.AnchorHour)
并添加{{ 1}}到+ 1
子句中DateDiff(minute, S.HourStartTime, E.HourEndTime)
的末尾。
在我看来:
注意:我声明@MaxHour变量的原因是我正在使用的动态数字表CTE想要一个常量。嗯,这不完全准确,但它的长短是没有常量它可以选择一个执行计划,不会限制快速查询所需的行中的行。我选择了SELECT
来计算它,但实际上我现在看到这可能会更快,如果你有一个IdleTimeMinute索引肯定会更快:
DateDiff
由于可以跨越两个不同小时的最小时间范围是2分钟(比如说11:59到12:00),所以我们必须增加118分钟,以确保至少有2个小时。