Получить дату последнего изменения на основе изменения значения столбца в SQL

Вопросы и ответы

У нас есть таблица Transmission_Status:

Key_Value FIELD NEW_VALUE DATE_MODIFIED
45 Статус передачи Завершено 11/07/2024
45 Статус передачи Завершено 15/05/2024
45 Статус передачи Неактивно 13/02/2022
45 Статус передачи Неактивно 13/02/2022
45 Статус передачи Активно 24/01/2022
45 Статус передачи Активно 20/12/2021
45 Статус передачи Активно 20/12/2021

Нам нужна дата последнего изменения, когда изменяется столбец NEW_VALUE (в данном случае, изменился с Неактивно на Завершено).

Текущий запрос:

select 
    key_value, field, new_value, date_modified
from
    (select 
         key_value, field, new_value, date_modified,
         rank() over (partition by key_value order by date_modified desc) rnk
     from 
         transmission_status
     where 
         key_value = 45 
         and Field = 'Статус передачи'
) x
where 
    rnk = 1

Текущий результат = Date_Modified = 11/07/2024

Ожидаемый результат = Date_Modified = 15/05/2024 (2-я строка)

Как я могу исправить это, чтобы получить ожидаемый результат?

Нам нужна дата последнего изменения всякий раз, когда изменяется столбец NEW_VALUE

Мне потребовалось некоторое время, чтобы понять это, сопоставляя только запрос на 2-ю строку вместо строк 2 и 4. Но я думаю, что теперь я понял, и более точное формулирование задачи выглядит так:

Нам нужна самая ранняя дата изменения из финального/конечного статуса NEW_VALUE.

Во-первых, если вы хотите узнать, когда значение меняется от одной строки к следующей, вместо rank() я бы предпочел использовать lead() или lag(), чтобы посмотреть на соседнюю строку.

Затем нам нужно узнать первую запись в каждом изменении. К сожалению, я не смог сделать это без еще одного уровня вложенности. Но мне удалось придумать следующее:

WITH Priors AS (
    select key_value, field, new_value, date_modified
        ,lag(new_value) over (partition by key_value, field order by date_modified) prior_value

    from Transmission_Status
    where key_value = 45 and Field ='Статус передачи'
), numberedChanges AS (
    select key_value, field, new_value, date_modified
      ,row_number() over (order by date_modified desc) rn
    from Priors
    where new_value <> prior_value
)
SELECT Key_Value, FIELD, New_Value, Date_Modified
FROM numberedChanges
WHERE rn = 1

https://dbfiddle.uk/8EuFC4Xc

Неудача в том, чтобы иметь только один вложенный запрос, заключалась в невозможности получить одинаковый номер rank() для каждого набора записей New_Value в рамках дальнейшей разбивки по key_value/field на основе минимальной даты. Если бы я мог найти способ сделать это, я мог бы также добавить row_number() в эту разбивку и искать строки (строку), где и rank, и номер равны 1.

Но то, что у меня есть, работает так, как есть.

Ответ

Для решения задачи получения последней даты изменения столбца DATE_MODIFIED при изменении значения в столбце NEW_VALUE, мы можем воспользоваться функцией LAG() для определения изменений значений.

В данной ситуации, мы будем использовать два уровня CTE (Common Table Expressions) для нахождения нужной информации. Сначала мы создадим временную таблицу с предыдущими значениями NEW_VALUE, а затем отфильтруем записи, соответствующие последнему изменению.

Вот готовый SQL-запрос:

WITH Priors AS (
    SELECT 
        key_value, 
        field, 
        new_value, 
        date_modified,
        LAG(new_value) OVER (PARTITION BY key_value, field ORDER BY date_modified) AS prior_value
    FROM 
        Transmission_Status
    WHERE 
        key_value = 45 
        AND field = 'Transmission Status'
),
numberedChanges AS (
    SELECT 
        key_value, 
        field, 
        new_value, 
        date_modified,
        ROW_NUMBER() OVER (ORDER BY date_modified DESC) AS rn
    FROM 
        Priors
    WHERE 
        new_value <> prior_value OR prior_value IS NULL
)
SELECT 
    key_value, 
    field, 
    new_value, 
    date_modified
FROM 
    numberedChanges
WHERE 
    rn = 1;

Объяснение запроса:

  1. CTE Priors:

    • Мы выбираем необходимые значения из таблицы Transmission_Status и используем функцию LAG(), чтобы получить предыдущее значение NEW_VALUE для каждой строки.
    • LAG(new_value) позволяет нам получить значение NEW_VALUE из предыдущей строки в пределах одной группы, определенной по key_value и field, упорядоченной по date_modified.
  2. CTE numberedChanges:

    • Здесь мы отбираем только те строки, где текущее значение NEW_VALUE отличается от предыдущего значения (prior_value), или где prior_value является NULL (то есть для первой записи).
    • Для каждой такой записи мы назначаем номер в порядке убывания даты изменения при помощи ROW_NUMBER().
  3. Финальный выбор:
    • Мы выбираем только первую (самую свежую) запись из отфильтрованных результатов, которая соответствует последнему изменению значения.

Итог:

Этот запрос вернет последнюю дату изменения статуса передачи, когда произошел переход от одного значения NEW_VALUE к другому. В данном случае, если вы выполните приведенный запрос, вы получите Date_Modified = 5/15/2024, что соответствует вашему ожидаемому результату.

Оцените материал
Добавить комментарий

Капча загружается...