2015-10-13 87 views
1

重写和重新发布此问题,因为上一个问题很混乱。我很抱歉。在SQL Server 2008中的行之间添加分钟 - 更新

我正在尝试创建一个报告,显示特定事件的持续时间,特别是事件之间的时间。我处理的数据的一个例子是:

> LoggedOnUser|EventDate |EventTime|EventID 
> DWH   |08/10/2015|07:45:00 |4624 
> DWH   |08/10/2015|07:46:00 |4800 
> DWH   |08/10/2015|07:50:00 |4801 
> DWH   |08/10/2015|08:27:00 |4800 
> DWH   |08/10/2015|16:18:00 |4801 
> DWH   |08/10/2015|16:31:00 |4647 

的数据是简单和用于选择上述查询是

SELECT sd.LoggedOnUser 
      , sd.EventDate 
      , CAST(dateadd(mi, datediff(mi, 0, sd.EventTime), 0) 
      AS TIME(7)) AS EventTime 
      , sd.EventID 
FROM dbo.tblStaffLoggedInDetails AS sd 
    WHERE LoggedOnUser = 'DWH' 
    AND EventDate = '08-Oct-2015' 

我有了所有1个分钟的时间间隔的间隔表。所需的输出将是:

> LoggedOnUser|EventDate |EventTime|EventID 
> DWH   |08/10/2015|07:45:00 |4624 
> DWH   |08/10/2015|07:46:00 |4800 
> DWH   |08/10/2015|07:47:00 |4800 
> DWH   |08/10/2015|07:48:00 |4800 
> DWH   |08/10/2015|07:49:00 |4800 
> DWH   |08/10/2015|07:50:00 |4801 
> DWH   |08/10/2015|07:51:00 |4801 
> DWH   |08/10/2015|07:52:00 |4801 
> DWH   |08/10/2015|07:53:00 |4801 
> DWH   |08/10/2015|07:54:00 |4801 

等等...

到目前为止我走到这一步

SELECT ii.IntervalHHMM 
     , dd.LoggedOnUser 
     , dd.EventDate 
     , dd.EventTime 
     , dd.EventID 
FROM (SELECT IntervalHHMM 
       FROM dtLookups.dbo.tblIntervalHHMM AS i) AS ii LEFT OUTER JOIN 
    (SELECT LoggedOnUser 
       , EventDate 
       , CAST(DATEADD(mi, DATEDIFF(mi, 0, EventTime), 0) 
        AS TIME(7)) AS EventTime 
       , EventID 
       , Action 
    FROM dbo.tblStaffLoggedInDetails AS sd 
     WHERE (LoggedOnUser = 'DWH') AND (EventDate = '08-Oct-2015')) 
    AS dd 
    ON ii.IntervalHHMM = dd.EventTime 
GROUP BY dd.LoggedOnUser, dd.EventDate, 
     dd.EventTime, dd.EventID, 
     dd.Action, ii.IntervalHHMM 
ORDER BY ii.IntervalHHMM 

其中一期工程在一定程度上,但有很多的空值。请参阅下面的图片,了解我目前返回的内容以及我需要的理想内容。

Current Result(left) and Desired (Right)

回答

1

的情况是,你做LEFT JOIN

╔══════════════╗╔═══════════╦══════════════╗ 
║ IntervalHHMM ║║ EventTime ║ LoggedOnUser ║ 
╠══════════════╣╠═══════════╬══════════════╣ 
║ 08:52:00  ║║ 08:52:00 ║ DWH   ║ 
║ 08:53:00  ║║ 08:53:00 ║ DWH   ║ 
║ 08:55:00  ║║ 08:55:00 ║ DWH   ║ 
║ 08:56:00  ║║   ║    ║ 
║ 08:57:00  ║║   ║    ║ 
║ 08:58:00  ║║   ║    ║ 
║ 08:59:00  ║║   ║    ║ 
║ 09:00:00  ║║ 09:00:00 ║ DWH   ║ 
║ 09:01:00  ║║   ║    ║ 
╚══════════════╝╚═══════════╩══════════════╝ 

现在你得到的结果是完全没有问题的,但要复制LoggedOnUserEventId非匹配的行(我assusme到最后知道价值)。在SQL Server 2008你没有访问窗口函数FIRST_VALUE/LAST_VALUE/LAG/LEAD但你可以用CROSS APPLY

WITH cte AS 
(
SELECT ii.IntervalHHMM 
     , LoggedOnUser 
     , dd.EventDate 
     , dd.EventTime 
     , dd.EventID 
FROM (SELECT IntervalHHMM    -- you can use simple #tblIntervalHHMM AS ii 
     FROM #tblIntervalHHMM AS i) AS ii 
LEFT OUTER JOIN 
     (SELECT LoggedOnUser 
       ,EventDate 
       ,CAST(DATEADD(mi, DATEDIFF(mi, 0, EventTime), 0) 
       AS TIME(7)) AS EventTime 
       ,EventID 
     FROM #tblStaffLoggedInDetails AS sd 
     WHERE (LoggedOnUser = 'DWH') 
       AND (EventDate = '2015-10-08')) AS dd 
ON ii.IntervalHHMM = dd.EventTime 
GROUP BY 
    dd.LoggedOnUser, 
    dd.EventDate, 
    dd.EventTime, 
    dd.EventID, 
    ii.IntervalHHMM 
) 
SELECT 
    IntervalHHMM 
    ,l.LoggedOnUser 
    ,EventDate 
    ,EventTime 
    ,l2.EventID 
FROM cte c 
CROSS APPLY (SELECT TOP 1 LoggedOnUser 
      FROM cte b 
      WHERE b.IntervalHHMM <= c.IntervalHHMM 
       AND b.LoggedOnUser IS NOT NULL 
       ORDER BY IntervalHHMM DESC) AS l 
CROSS APPLY (SELECT TOP 1 EventId 
      FROM cte b 
      WHERE b.IntervalHHMM <= c.IntervalHHMM 
       AND b.EventId IS NOT NULL 
       ORDER BY IntervalHHMM DESC) AS l2 
ORDER BY IntervalHHMM; 

LiveDemo

输出:

╔══════════════╦══════════════╦═════════════════════╦═══════════╦═════════╗ 
║ IntervalHHMM ║ LoggedOnUser ║  EventDate  ║ EventTime ║ EventID ║ 
╠══════════════╬══════════════╬═════════════════════╬═══════════╬═════════╣ 
║ 07:45:00  ║ DWH   ║ 2015-10-08 00:00:00 ║ 07:45:00 ║ 4624 ║ 
║ 07:46:00  ║ DWH   ║ 2015-10-08 00:00:00 ║ 07:46:00 ║ 4800 ║ 
║ 07:47:00  ║ DWH   ║      ║   ║ 4800 ║ 
║ 07:48:00  ║ DWH   ║      ║   ║ 4800 ║ 
║ 07:49:00  ║ DWH   ║      ║   ║ 4800 ║ 
║ 07:50:00  ║ DWH   ║ 2015-10-08 00:00:00 ║ 07:50:00 ║ 4801 ║ 
║ 07:51:00  ║ DWH   ║      ║   ║ 4801 ║ 
╚══════════════╩══════════════╩═════════════════════╩═══════════╩═════════╝ 

我发现干净的解决方案是使用LAST_VALUE但在那里是一个捕获。 SQL标准定义了IGNORE NULLS子句,但SQL Server尚不支持。

SELECT 
    IntervalHHMM 
    ,LAST_VALUE(LoggedOnUser IGNORE NULLS) 
      OVER(ORDER BY IntervalHHMM ROWS UNBOUNDED PRECEDING) AS LoggedOnUser 
    ,EventDate 
    ,EventTime 
    ,LAST_VALUE(EventID IGNORE NULLS) 
     OVER(ORDER BY IntervalHHMM ROWS UNBOUNDED PRECEDING) AS EventID 
FROM cte c 
ORDER BY IntervalHHMM; 

SqlFiddleDemo_using_Oracle