Я предложил решение добавить недостающие строки в таблицу - как для отсутствующих in
строк, так и для отсутствующих out
строк.
Единственное, что я сделал, отличается от того, что вы просилисостоит в том, что отсутствующие строки завершают 8-часовой рабочий день со своей исходной строкой.
Обратите внимание, что это может использоваться только с одним пользователем каждый раз.
Так вот как:
Во-первых, я создал общее табличное выражение, содержащее все строки таблицы, принадлежащие конкретному пользователю.В этом cte я использовал lag
и lead
для получения следующего события, предыдущего события и времени следующего события, а также столбца row_number.
Затем я использовал объединение всех трехзапросы на основе этого cte - один для исходных строк, один для новых строк с событием in
и один для новых строк с событиями out
.
Сценарий основан на ваших данных примера, и вы можетесм. онлайн-демонстрацию на rextester.
DECLARE @User nvarchar(6) = N'Jibran';
WITH CTE AS
(
SELECT [User],
[Event],
[Time],
ROW_NUMBER() OVER(ORDER BY [Time]) + 0.0 As rn,
LAG([Event]) OVER(ORDER BY [Time]) As PrevEvent,
LEAD([Event]) OVER(ORDER BY [Time]) As NextEvent,
LEAD([Time]) OVER(ORDER BY [Time]) As NextEventTime
FROM TimeLog
WHERE [User] = @User
)
SELECT [User],
'OUT' As [Event],
DATEADD(HOUR, 8, [Time]) As [Time],
rn + 0.5 As rn
FROM CTE
WHERE NextEvent = [Event]
AND [Event] = 'IN'
UNION ALL
SELECT [User],
'IN' As [Event],
DATEADD(HOUR, -8, [NextEventTime]) As [Time],
rn - 0.3 As rn
FROM CTE
WHERE PrevEvent = [Event]
AND [Event] = 'OUT'
UNION ALL
SELECT [User],
[Event],
[Time],
rn
FROM CTE
ORDER BY rn
Результаты:
User Event Time rn
Jibran IN 15.04.2015 00:31:00 1,0
Jibran OUT 15.04.2015 08:31:00 1,5
Jibran IN 16.04.2015 20:10:00 2,0
Jibran OUT 17.04.2015 04:10:00 2,5
Jibran IN 17.04.2015 10:32:00 3,0
Jibran OUT 17.04.2015 18:32:00 3,5
Jibran IN 21.04.2015 14:59:00 4,0
Jibran OUT 22.04.2015 01:01:00 5,0
Jibran IN 22.04.2015 10:46:00 6,0
Jibran OUT 23.04.2015 00:58:00 7,0
Jibran IN 23.04.2015 14:50:00 8,0
Jibran OUT 24.04.2015 01:37:00 9,0
Jibran IN 26.04.2015 16:57:00 9,7
Jibran OUT 25.04.2015 01:01:00 10,0
Jibran IN 29.04.2015 07:03:00 10,7
Jibran OUT 27.04.2015 00:57:00 11,0
Jibran IN 29.04.2015 15:03:00 12,0
Jibran OUT 01.05.2015 00:44:00 13,0
Jibran IN 02.05.2015 07:08:00 13,7
Jibran OUT 02.05.2015 01:19:00 14,0
Jibran IN 02.05.2015 15:08:00 15,0
Jibran OUT 03.05.2015 01:08:00 16,0
Jibran IN 03.05.2015 15:06:00 17,0
Jibran OUT 04.05.2015 01:01:00 18,0
Jibran IN 04.05.2015 15:11:00 19,0
Jibran OUT 05.05.2015 01:08:00 20,0
Side Примечание: Вы можете указать, какая строка была добавлена какой частью объединения, всеЗапрос основан на рН.
Обновление
После нашего разговора в комментариях к вопросу - Чтобы получить входы и выходы в разных столбцах, я обернул запрос объединения всех в другой cte и поставил еще один cte навершина этого, чтобы получить номер строки bigint.Тогда это был просто вопрос условной агрегации с твист-спариванием четных и нечетных номеров строк в группы с использованием перекрестного применения.
Вот полный сценарий - и, конечно, онлайн-демонстрация :
DECLARE @User nvarchar(6) = N'Jibran';
WITH CTE AS
(
SELECT [User],
[Event],
[Time],
ROW_NUMBER() OVER(ORDER BY [Time]) + 0.0 As rn,
LAG([Event]) OVER(ORDER BY [Time]) As PrevEvent,
LEAD([Event]) OVER(ORDER BY [Time]) As NextEvent,
LEAD([Time]) OVER(ORDER BY [Time]) As NextEventTime
FROM TimeLog
WHERE [User] = @User
), CTERows AS
(
-- Added out rows
SELECT [User],
'OUT' As [Event],
DATEADD(HOUR, 8, [Time]) As [Time],
rn + 0.5 As rn
FROM CTE
WHERE NextEvent = [Event]
AND [Event] = 'IN'
UNION ALL
-- Added in rows
SELECT [User],
'IN' As [Event],
DATEADD(HOUR, -8, [NextEventTime]) As [Time],
rn - 0.3 As rn
FROM CTE
WHERE PrevEvent = [Event]
AND [Event] = 'OUT'
UNION ALL
-- Existing rows
SELECT [User],
[Event],
[Time],
rn
FROM CTE
), CTEIntNumberedRows AS
(
SELECT [User],
[Event],
[Time],
ROW_NUMBER() OVER (ORDER BY rn) As rn
FROM CteRows
)
SELECT [User],
MAX(CASE WHEN [Event] = 'IN' THEN [Time] END) As 'IN',
MAX(CASE WHEN [Event] = 'OUT' THEN [Time] END) As 'OUT',
Pairs
FROM CTEIntNumberedRows
CROSS APPLY
(
SELECT CASE WHEN rn % 2 = 0 THEN rn-1 ELSE rn END As Pairs
) x
GROUP BY [User], Pairs
ORDER BY Pairs