#sql #oracle
Вопрос:
Сценарий:
Таблица «HIST»
избавлять | ценность | HIST_DATE |
---|---|---|
1 | В111 | 2019-01-01 |
1 | V112 | 2020-02-11 |
1 | V112 | 2020-03-08 |
1 | V113 | 2020-04-11 |
1 | V114 | 2021-03-15 |
2 | V211 | 2020-04-11 |
2 | V211 | 2021-03-16 |
3 | V311 | 2019-05-01 |
3 | V312 | 2020-01-01 |
ОЖИДАЕМЫЙ РЕЗУЛЬТАТ:
избавлять | ЗНАЧЕНИЕ, РАВНОЕ | VALUE_NEW |
---|---|---|
1 | V113 | V114 |
Я хочу отобразить разницу между строками в столбце «ЗНАЧЕНИЕ», группируемом по RID, где HIST_DATE находится между «2020-03-31» и «2021-04-01».
Затем перенесите различные значения в столбцы «VALUE_OLD» И «VALUE_NEW».
Примечание : Предполагая, что между этими датами может быть только 2 разных значения
Oracle SQL
Комментарии:
1. Пожалуйста, объясните логику. Что случилось с остальными значениями в таблице?
2. Я только хочу знать разницу в значениях между 2 контрольными точками времени. В остальном разница не нужна
Ответ №1:
Другой вариант-использовать функции аналитики ОТСТАВАНИЯ/ЛИДОВ :
- ЗАДЕРЖКА возвращает значение из предыдущей строки таблицы.
- ЛИД возвращает значение из следующей строки таблицы.
select rid
, LAG(hist_date) OVER(partition by rid order by hist_date ) as HIST_DATE_OLD
, hist_date as HIST_DATE
, LAG(value) OVER(partition by rid order by hist_date ) as VALUE_OLD
, value as VALUE_NEW
from hist
select rid
, lead(hist_date) OVER(partition by rid order by hist_date desc) as HIST_DATE_OLD
, hist_date as HIST_DATE
, lead(value) OVER(partition by rid order by hist_date desc) as VALUE_OLD
, value as VALUE_NEW
from hist
order by rid, hist_date
Затем вы можете отфильтровать и отформатировать в соответствии с вашими потребностями
select rid, VALUE_OLD, VALUE_NEW from (
select rid
, TO_CHAR(lead(hist_date) OVER(partition by rid order by hist_date desc), 'YYYY-MM-DD') as HIST_DATE_OLD
, TO_CHAR(hist_date , 'YYYY-MM-DD') as HIST_DATE
, lead(value) OVER(partition by rid order by hist_date desc) as VALUE_OLD
, value as VALUE_NEW
from hist
where HIST_DATE between '2020-03-31' and '2021-04-01'
and rid = 1
order by rid, hist_date
)
where HIST_DATE_OLD IS NOT NULL
RID VALUE_OLD VALUE_NEW
--- --------- ---------
1 V113 V114
select * from (
select rid
, TO_CHAR(lead(hist_date) OVER(partition by rid order by hist_date desc), 'YYYY-MM-DD') as HIST_DATE_OLD
, TO_CHAR(hist_date , 'YYYY-MM-DD') as HIST_DATE
, lead(value) OVER(partition by rid order by hist_date desc) as VALUE_OLD
, value as VALUE_NEW
from hist
order by rid, hist_date
)
where HIST_DATE between '2020-03-31' and '2021-04-01'
and rid = 1
RID HIST_DATE_OLD HIST_DATE VALUE_OLD VALUE_NEW
--- ------------- ---------- --------- ---------
1 2020-03-08 2020-04-11 V112 V113
1 2020-04-11 2021-03-15 V113 V114
позаботьтесь о фильтре внутри и снаружи основного ВЫБОРА
- снаружи вы выполняете фильтрацию после выполнения операции ЗАДЕРЖКИ/ОПЕРЕЖЕНИЯ (выше)
- внутри вы выполняете фильтрацию перед выполнением операции ЗАДЕРЖКИ/ОПЕРЕЖЕНИЯ (ниже).
RID HIST_DATE_OLD HIST_DATE VALUE_OLD VALUE_NEW
--- ------------- ---------- --------- ---------
1 2020-04-11 V113
1 2020-04-11 2021-03-15 V113 V114
Ответ №2:
Предполагая, что между этими датами может быть только 2 разных значения
select distinct RID,
first_value(VALUE) over(order by HIST_DATE) VALUE_OLD,
first_value(VALUE) over(order by HIST_DATE desc) VALUE_NEW
from HIST
where HIST_DATE between date '2020-03-31' and date '2021-04-01'
Ответ №3:
Вам придется:
- Найдите последнюю дату hist_date для каждого rid (новые значения)
- Найдите последнюю дату истории для каждого rid (oldvals), которая предшествует самой последней (newvals)
- Прочитайте таблицу hist, чтобы найти новые значения для каждого rid
- Прочитайте таблицу hist, чтобы найти предыдущие значения для каждого rid
Вы всегда показываете два последних значения каждого rid, независимо от того, есть ли другие более старые значения.
SELECT
n.rid,
o.value AS value_old,
n.value AS value_new
FROM
(
SELECT
rid,
MAX(hist_date) AS DATE
FROM
hist
GROUP BY
rid
)
newvals,
(
SELECT
hist.rid,
MAX(hist_date) AS DATE
FROM
hist,
(
SELECT
rid,
MAX(hist_date) AS DATE
FROM
hist
GROUP BY
rid
)
newvals
WHERE
hist.rid=newvals.rid
AND hist.hist_date<newvals.date
GROUP BY
hist.rid
)
oldvals,
hist n,
hist o
WHERE
n.rid=o.rid
and n.rid=newvals.rid
and n.rid=oldvals.rid
AND n.hist_date=newvals.date
AND o.hist_date=oldvals.date