0

StartTime我需要复制每一行的次数与和之间的小时数一样多EndTime

示例数据:

SQLFIDDLE示例

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
4

4 回答 4

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)
;
于 2013-01-30T13:37:33.527 回答
0

你可以试试这个。生成序列的限制。如果你IdleTimeMinute出乎意料的好,你必须OPTION (MAXRECURSION n)从 CTE 使用。查询可以从 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 小提琴演示

于 2013-01-30T14:02:44.100 回答
0

SQLFiddle

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
于 2013-01-31T05:43:34.733 回答
0

干得好。这甚至可以处理时间跨度超过午夜或超过很多天的情况。它应该表现得非常好。

请参阅SqlFiddle

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的末尾。DateDiff(minute, S.HourStartTime, E.HourEndTime)SELECT

在我看来:

  • 使用 CTE 逐步增加一个人的最大差异并不是最佳的。一旦达到最大 Num,我使用的 CTE 就会退出,最高可达 4294967296。
  • 不计算新 TimeKey 的解决方案是脆弱的,因为它依赖于一个未说明的假设,即不能跨越午夜。
  • 依赖于您将表更改为具有无间隙单调递增 ID 的解决方案不太可能适合您的实际数据。

注意:我声明 @MaxHour 变量的原因是我正在使用的动态数字表 CTE 需要一个常量。嗯,这并不完全准确,但总而言之,如果没有常量,它可以选择一个执行计划,该计划不会限制获得快速查询所需的行。我选择DateDiff计算这个,但事实上我现在看到这可能会更快,如果你在 IdleTimeMinute 上有一个索引肯定会更快:

DECLARE @MaxHour int = IsNull((SELECT (Max(IdleTimeMinute) + 118) / 60 FROM dbo.Table1), 0);

由于可以跨越两个不同小时的最小时间范围是 2 分钟(比如 11:59 到 12:00),因此我们必须添加 118 分钟以确保至少有 2 小时。

于 2013-01-31T06:43:20.087 回答