Обработка пропущенных значений входа / выхода в SQL Datetime - PullRequest
0 голосов
/ 15 октября 2018

Мой запрос Sql:

CREATE TABLE TimeLog (
    [User] NVARCHAR(6),
    [Event] NVARCHAR(3),
    [Time] DATETIME
);
INSERT INTO TimeLog VALUES
(N'Jibran',N'IN','2015-04-15 00:31:00'),
(N'Jibran',N'IN','2015-04-16 20:10:00'),
(N'Jibran',N'IN','2015-04-21 14:59:00'),
(N'Jibran',N'OUT','2015-04-22 01:01:00'),
(N'Jibran',N'IN','2015-04-22 10:46:00'),
(N'Jibran',N'OUT','2015-04-23 00:58:00'),
(N'Jibran',N'IN','2015-04-23 14:50:00'),
(N'Jibran',N'OUT','2015-04-24 01:37:00'),
(N'Jibran',N'OUT','2015-04-25 01:01:00'),
(N'Jibran',N'OUT','2015-04-27 00:57:00'),
(N'Jibran',N'IN','2015-04-17 10:32:00'),
(N'Jibran',N'IN','2015-04-29 15:03:00'),
(N'Jibran',N'OUT','2015-05-01 00:44:00'),
(N'Jibran',N'OUT','2015-05-02 01:19:00'),
(N'Jibran',N'IN','2015-05-02 15:08:00'),
(N'Jibran',N'OUT','2015-05-03 01:08:00'),
(N'Jibran',N'IN','2015-05-03 15:06:00'),
(N'Jibran',N'OUT','2015-05-04 01:01:00'),
(N'Jibran',N'IN','2015-05-04 15:11:00'),
(N'Jibran',N'OUT','2015-05-05 01:08:00');

SELECT TOP (30) UserName, EventName, EventTime
From AttendanceEvents
Where UserName = 'Jibran'

Результат:

enter image description here

Есть ли способ справиться с отсутствующими значениями длякаждое значение IN, которое не имеет значения даты и времени OUT?

Я читал статью: https://www.red -gate.com / simple-talk / sql / t-sql-программирования /Вычисление разрывов между перекрывающимися временными интервалами в sql /

Но не смог понять это на полпути.

Как получить Среднее из Datetime, чтобы использовать его для пропущенных значений?

Ожидаемый вывод будет иметь значения OUT для каждого IN.

Спасибо.

1 Ответ

0 голосов
/ 15 октября 2018

Я предложил решение добавить недостающие строки в таблицу - как для отсутствующих 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...