2015-10-13 2 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' 

У меня есть Interval таблицы, которая имеет все 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 

, который работает в определенной степени, но имеет много NULLS. См. Изображение ниже для того, что я сейчас возвращаю и что в идеале мне нужно.

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  ║║   ║    ║ 
╚══════════════╝╚═══════════╩══════════════╝ 

Теперь результат вы получите прекрасно, но вы хотите реплицировать LoggedOnUser и EventId для не соответствует строкам (I 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

Смежные вопросы