У нас есть таблица 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
Неудача в том, чтобы иметь только один вложенный запрос, заключалась в невозможности получить одинаковый номер 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;
Объяснение запроса:
-
CTE
Priors
:- Мы выбираем необходимые значения из таблицы
Transmission_Status
и используем функциюLAG()
, чтобы получить предыдущее значениеNEW_VALUE
для каждой строки. LAG(new_value)
позволяет нам получить значениеNEW_VALUE
из предыдущей строки в пределах одной группы, определенной поkey_value
иfield
, упорядоченной поdate_modified
.
- Мы выбираем необходимые значения из таблицы
-
CTE
numberedChanges
:- Здесь мы отбираем только те строки, где текущее значение
NEW_VALUE
отличается от предыдущего значения (prior_value
), или гдеprior_value
являетсяNULL
(то есть для первой записи). - Для каждой такой записи мы назначаем номер в порядке убывания даты изменения при помощи
ROW_NUMBER()
.
- Здесь мы отбираем только те строки, где текущее значение
- Финальный выбор:
- Мы выбираем только первую (самую свежую) запись из отфильтрованных результатов, которая соответствует последнему изменению значения.
Итог:
Этот запрос вернет последнюю дату изменения статуса передачи, когда произошел переход от одного значения NEW_VALUE
к другому. В данном случае, если вы выполните приведенный запрос, вы получите Date_Modified = 5/15/2024
, что соответствует вашему ожидаемому результату.