Ошибка обнаружения разрыва между датами в первой сгруппированной записи - PullRequest
2 голосов
/ 03 мая 2019

Перед недавним запросом мне удалось создать запрос, который вычисляет пропуски для каждого журнала пользователя.CTE выводит список каждого пользовательского журнала по его идентификатору с помощью ROW_NUMBER (), затем во втором CTE он сам присоединяется к «RN id + 1», что приводит к «рекурсивному» вычислению даты «INIx - FINx-1», позже ядобавить индикатор для визуальной помощи.Выполнение запроса «как есть» возвращает корректно почти каждую строку, но я заметил, что в некоторых случаях первый последовательный журнал отображается как «NOSEQ» (не последовательный), потому что мой индикатор рассматривает только «1» как условие как последовательное.

CTE RESULT

Где RN = 5, это последовательно, но, поскольку он рассчитывает себя со следующим журналом, он не соответствует требованию.Я не знаю, что я что-то упустил или мне нужно начинать все сначала ... Любая помощь в моей логике запроса приветствуется.(Учтите, что я ограничен синтаксисом SQL Server 2008)

IF NOT EXISTS (
    select * from sysobjects where name='INF_LIC' and xtype='U'
) CREATE TABLE INF_LIC (
    [PER_PRO_ID_HR_INI_FIN] NVARCHAR(57)
);
INSERT INTO INF_LIC VALUES
    (N'201811;P1;2018-11-23 00:00:00.000;2018-11-23 00:00:00.000'),
    (N'201810;P1;2018-10-25 00:00:00.000;2018-10-26 00:00:00.000'),
    (N'201809;P1;2018-09-28 00:00:00.000;2018-09-28 00:00:00.000'),
    (N'201808;P1;2018-08-31 00:00:00.000;2018-09-05 00:00:00.000'),
    (N'201807;P1;2018-07-05 00:00:00.000;2018-07-25 00:00:00.000'),
    (N'201806;P1;2018-06-14 00:00:00.000;2018-07-04 00:00:00.000'),
    (N'201805;P1;2018-05-25 00:00:00.000;2018-06-13 00:00:00.000'),
    (N'201805;P1;2018-05-10 00:00:00.000;2018-05-24 00:00:00.000'),
    (N'201804;P1;2018-04-25 00:00:00.000;2018-05-09 00:00:00.000');

;WITH CTE AS(
    -- LIST EVERY RECORD
    SELECT ID, CAST(INI AS DATETIME) AS INI, CAST(FIN AS DATETIME) AS FIN, 
        RN = ROW_NUMBER()OVER(PARTITION BY ID ORDER BY CAST(FIN AS DATETIME) DESC)
    FROM INF_LIC
    WHERE PER_PRO > 201712
), CTE2 AS(
    -- CALCULATE DATEDIFF
    SELECT T.*, 
        -- DATEDIFF BETWEEN INIn - FINn-1
        DD = CASE WHEN DATEDIFF(DD,T.FIN,T2.INI) IS NULL THEN 0 ELSE DATEDIFF(DD,T2.INI,T.FIN) END
    FROM CTE 
    -- LEFT JOIN ON EQUAL ID's AND RN = RN+1
    LEFT JOIN CTE T2 ON T.RN = T2.RN + 1 AND T.ID = T2.ID AND T.RN <> T2.RN
), CTE3 AS(
    SELECT ID, INI, FIN, RN, ABS(DD) AS DD,
    -- INDICATOR, IF -1 ITS 'SEQ', NULL MARKS THE NEWEST LOG 'FIRSTLOG' ELSE IT'S NOT SEQUENTIAL
    IND = (CASE WHEN DD = -1 THEN 'SEQ'
        WHEN DD = 0 THEN 'FIRSTLOG'
        ELSE 'NOSEQ'
        END)
    FROM CTE2
), CTE4 AS(
    SELECT ID, INI, FIN, RN, DD, IND
    FROM CTE3
    GROUP BY ID, INI, FIN, RN, DD, IND 
)
SELECT * FROM CTE4
ORDER BY ID, RN ASC

1 Ответ

0 голосов
/ 03 мая 2019

Не совсем понятно, почему вы считаете запись 5 последовательной.SQL в вопросе подразумевает, что определение последовательного состоит в том, что ini предыдущей записи находится на расстоянии 1 день от fin этой записи, что является истинным.

Однако это подозрительное определение, учитывая имена этих столбцов,Я подозреваю, что вы хотите определить ind так, чтобы он был последовательным, когда fin этой записи находится на расстоянии 1 день от ini следующей записи.Если это правда, то вы, вероятно, захотите сделать это:

WITH CTE AS(
    -- LIST EVERY RECORD
    SELECT ID, CAST(INI AS DATETIME) AS INI, CAST(FIN AS DATETIME) AS FIN, 
        RN = ROW_NUMBER()OVER(PARTITION BY ID ORDER BY CAST(FIN AS DATETIME) DESC)
    FROM INF_LIC
    WHERE PER_PRO > 201712
), CTE2 AS(
    -- CALCULATE DATEDIFF
    SELECT T.*, 
        -- DATEDIFF BETWEEN INIn - FINn-1
        DD = CASE WHEN DATEDIFF(DD,T2.FIN,T.INI) IS NULL THEN 0 ELSE DATEDIFF(DD,T.INI,T2.FIN) END
    FROM CTE T
    -- LEFT JOIN ON EQUAL ID's AND RN = RN+1
    LEFT JOIN CTE T2 ON T.RN = T2.RN - 1 AND T.ID = T2.ID
), CTE3 AS(
    SELECT ID, INI, FIN, RN, ABS(DD) AS DD,
    -- INDICATOR, IF -1 ITS 'SEQ', NULL MARKS THE NEWEST LOG 'FIRSTLOG' ELSE IT'S NOT SEQUENTIAL
    IND = (CASE WHEN DD in (0, -1) THEN 'SEQ'
        WHEN RN = 1 THEN 'FIRSTLOG'
        ELSE 'NOSEQ'
        END)
    FROM CTE2
), CTE4 AS(
    SELECT ID, INI, FIN, RN, DD, IND
    FROM CTE3
    GROUP BY ID, INI, FIN, RN, DD, IND 
)
SELECT * FROM CTE4
ORDER BY ID, RN ASC

Где соответствующие изменения:

LEFT JOIN CTE T2 ON T.RN = T2.RN - 1 AND T.ID = T2.ID

Это объединение теперь T2.RN минус один: вам нужно вычестьномер строки следующей записи, чтобы получить ее, а не добавить, и:

IND = (CASE WHEN DD in (0, -1) THEN 'SEQ'
        WHEN RN = 1 THEN 'FIRSTLOG'
        ELSE 'NOSEQ'
        END)

Поскольку вы уже нумеруете строку, вы также можете использовать очевидное определение FIRSTLOG.Поскольку этот порядок соединения теперь обратен исходному предположению, DD, равный 0, теперь означает, что это последняя запись, а не первая, поэтому он немного расширяет определение SEQ.

...