需要通过临时表中的ID更新存储过程中的行

时间:2012-04-26 20:38:06

标签: sql-server tsql stored-procedures

我正在尝试在描述中断的表中获取行,并通过计算的时间范围将它们分成单独的行,以插入到另一个表中,以描述每个给定范围中的每小时时间段。

以下代码为我们提供了以下输出:

我们从这一行开始(原始数据):

OutageDate        StartTime                 EndTime             Duration
2010-11-10  16:00:00.0000000    17:30:00.0000000    90

在我运行存储过程之后(这是期望的输出!我只需要知道如何将其保存到表中):

OutageDate   StartHour StartMinutes  EndHour EndMinutes    StartTime        EndTime       Duration
2010-11-10  16   0       17       0        16:00:00.0000000     17:30:00.0000000    90
2010-11-10  17  30       18       0        16:00:00.0000000     17:30:00.0000000    90

以下是我需要弄清楚如何在我想要的时间值之间拆分行时保存到表中的代码。我无法控制为什么会发生这种情况,它只需要按照比我更高的人的要求并以这种格式指定:

--First, let's look at the original data in the table...just one row will do

SELECT TOP (1) *
  FROM actualTable
  ORDER BY OutageDate ASC

--Begin sproc logic
declare @OutageDate date
declare @StartTime time(7)
declare @EndTime time(7)
declare @StartHour bigint
declare @EndHour int
declare @StartMinute int
declare @EndMinute int
declare @Duration int

declare @Temp_StartTime time
declare @Temp_EndTime time
declare @temp_StartHour int
declare @temp_EndHour int
declare @temp_StartMinute int
declare @temp_EndMinute int


SELECT TOP(1) @OutageDate = OutageDate, @StartTime = StartTime, @EndTime = EndTime, @Duration = Duration FROM actualTable


SET @Temp_StartTime=@StartTime
SET @Temp_EndTime=@EndTime
SET @temp_StartHour=DATEPART(HOUR, @StartTime)
SET @temp_EndHour=DATEPART(HOUR, @EndTime)
SET @temp_StartMinute=DATEPART(MI, @StartTime)
SET @temp_EndMinute=DATEPART(MI, @EndTime)

PRINT @temp_StartHour
PRINT @temp_EndHour
PRINT @temp_StartMinute
PRINT @StartTime
PRINT @EndTime

if(@temp_EndMinute>0)
    BEGIN
        SET @temp_EndHour=@temp_EndHour+1
    END

--this declares the temp table 

DECLARE @Temp_Table TABLE
(
OutageDate date,
StartHour int,
StartMinute int,
EndHour int,
EndMinute int,
StartTime time,
EndTime time,
Duration int
)

--Here's the loop that inserts the rows

While((@temp_EndHour-@temp_StartHour>1))
    BEGIN
       INSERT INTO @Temp_Table
       SELECT 
            @OutageDate AS OutageDate,  
           (DATEPART(HOUR, @Temp_StartTime)) AS StartHour,
           (DATEPART(MINUTE, @Temp_StartTime)) AS StartMinute, 
            @temp_StartHour+1 AS EndHour, 
            0 AS EndMinute,
            @StartTime as StartTime, 
            @EndTime as EndTime,
           @Duration AS Duration


--DATEADD returns a specified date with the specified number interval (signed integer) added to a specified datepart of that date.

        SET @temp_StartHour=@temp_StartHour+1
        SET @Temp_StartTime=DATEADD(HOUR,1,@Temp_StartTime)

--Let's make sure we account for the minutes in the first and last hours if any

        if(DATEPART(MI, @Temp_StartTime)!=0)
            BEGIN
                SET @Temp_StartTime=DATEADD(MI,-@Temp_StartMinute,@Temp_StartTime)
            END
    END

--Ok, if we're at the last row insertion, we still need the minutes the outage finished at...those go into StartMinutes

    WHile((@temp_EndHour-@temp_StartHour=1))
    BEGIN
       INSERT INTO @Temp_Table
       SELECT 
       @OutageDate AS OutageDate, 
       (DATEPART(HOUR, @Temp_StartTime)) AS StartHour, 
       @temp_EndMinute AS StartMinute, 
       @temp_StartHour+1 AS EndHour, 
      0 AS EndMinute, 
      @StartTime as StartTime, 
       @EndTime as EndTime,
       @Duration AS Duration

--DATEADD returns a specified date with the specified number interval (signed integer) added to a specified datepart of that date.

        SET @temp_StartHour=@temp_StartHour+1
        SET @Temp_StartTime=DATEADD(HOUR,1,@Temp_StartTime)

--Let's make sure we account for the minutes in the first and last hours if any

        if(DATEPART(MI, @Temp_StartTime)!=0)
            BEGIN
                SET @Temp_StartTime=DATEADD(MI,-@temp_StartMinute,@Temp_StartTime)
            END
    END

--Need to add logic that drops and recreates the table from the temp table so we don't have to employ a cursor

SELECT * FROM @Temp_Table

BEGIN
SELECT * INTO newTable FROM @Temp_Table
END

如果您在SMS中运行此直线,您将获得最基本的逻辑:

declare @StartTime time
declare @EndTime time
declare @Temp_StartTime time

declare @temp_StartHour int
declare @temp_EndHour int
declare @temp_StartMinute int
declare @temp_EndMinute int

SET @StartTime='2:30:00'
SET @EndTime='4:01:00'
SET @Temp_StartTime=@StartTime

SET @temp_StartHour=DATEPART(HOUR, @StartTime)
SET @temp_EndHour=DATEPART(HOUR, @EndTime)
SET @temp_StartMinute=DATEPART(MI, @StartTime)
SET @temp_EndMinute=DATEPART(MI, @EndTime)

if(@temp_EndMinute>0)
    BEGIN
        SET @temp_EndHour=@temp_EndHour+1
    END

DECLARE @Temp_Table TABLE
(
  StartHour int,
  StartMinute int,
  EndHour int,
  EndMinute int,
  StartTime time,
  EndTime time
)

WHile((@temp_EndHour-@temp_StartHour>=1))
    BEGIN
        INSERT INTO @Temp_Table
        SELECT (DATEPART(HOUR, @Temp_StartTime)) AS StartHour,(DATEPART(MINUTE, @Temp_StartTime)) AS StartMinute,
        @temp_StartHour+1 AS EndHour, 
        0 AS EndMinute, @StartTime as StartTime, @EndTime as EndTime

        SET @temp_StartHour=@temp_StartHour+1
        SET @Temp_StartTime=DATEADD(HOUR,1,@Temp_StartTime)

        if(DATEPART(MI, @Temp_StartTime)!=0)
            BEGIN
                SET @Temp_StartTime=DATEADD(MI,-@temp_StartMinute,@Temp_StartTime)
            END
    END

SELECT * FROM @Temp_Table 

1 个答案:

答案 0 :(得分:1)

首先,一些设置:

USE tempdb;
GO

CREATE TABLE dbo.Outages
(
    OutageDate DATE,
    StartTime TIME(7),
    EndTime TIME(7),
    Duration INT
);

INSERT dbo.Outages SELECT '20101110', '16:00', '17:30', 90;
/*
-- I also tested these cases, and *think* it still produces what you expect:
INSERT dbo.Outages SELECT '20101111', '13:00', '14:02', 62;
INSERT dbo.Outages SELECT '20101112', '17:00', '18:00', 60;
INSERT dbo.Outages SELECT '20101113', '16:05', '16:25', 20;
INSERT dbo.Outages SELECT '20101114', '16:59', '18:01', 62;
INSERT dbo.Outages SELECT '20101115', '22:15', '01:30', 165;
*/

现在,查询:

;WITH n(n) AS 
(
  SELECT TOP 24 ROW_NUMBER() OVER (ORDER BY [object_id])
  FROM sys.objects
),
x AS
(
  SELECT 
    o.OutageDate, StartHour = (DATEPART(HOUR, StartTime) + n.n - 1) % 24,
    StartTime, EndTime, Duration,
    rn = ROW_NUMBER() OVER (PARTITION BY o.OutageDate, o.StartTime ORDER BY n.n)
  FROM n INNER JOIN dbo.Outages AS o
  ON n.n <= CEILING(DATEDIFF(MINUTE, CONVERT(DATETIME, StartTime), 
    DATEADD(DAY, CASE WHEN EndTime < StartTime THEN 1 ELSE 0 END, 
    CONVERT(DATETIME, EndTime)))/60.0)
 ),
 mx AS (SELECT OutageDate, StartTime, minrn = MIN(rn), maxrn = MAX(rn) 
   FROM x GROUP BY OutageDate, StartTime)

 -- insert into some other table
 SELECT 
    x.OutageDate, 
    x.StartHour, 
    StartMinutes = CASE 
      WHEN x.rn = mx.minrn THEN DATEPART(MINUTE, x.StartTime) ELSE 0 END,
    EndHour = x.StartHour + 1, 
    EndMinutes = CASE
      WHEN x.rn = mx.maxrn THEN DATEPART(MINUTE, x.EndTime) ELSE 0 END,
    x.StartTime, 
    x.EndTime,
    x.Duration
 FROM x INNER JOIN mx 
 ON x.OutageDate = mx.OutageDate
 AND x.StartTime = mx.StartTime
 ORDER BY x.OutageDate, x.rn;
GO

如果您对为各种方案提供正确的行感到高兴,那么请替换

-- insert into some other table

使用实际插入,例如

INSERT dbo.OtherTable(col1, col2, ...)

如果您尝试从此输出创建一个全新的表格,请替换

FROM x INNER JOIN mx

使用INTO子句,例如

INTO dbo.MyNewTable FROM x INNER JOIN mx

别忘了清理:

DROP TABLE dbo.Outages;