2015-10-13 89 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