Oracle SQL — создать оператор выбора, который будет извлекать каждую конечную дату месяца, но сравнивать значения через день или два после окончания месяца

#sql #oracle

#sql #Oracle

Вопрос:

Допустим, у меня есть таблица клиентов.

 customer_name ||   date  ||  amount
-----------------------------------
A               31-OCT-20    100
A               01-NOV-20    100
A               02-NOV-20    200
B               31-OCT-20    300
B               01-NOV-20    325
B               02-NOV-20    350
  

Мне нужно создать оператор выбора, который будет извлекать каждую конечную дату месяца и сравнивать значения для сумм, соответствующих дню или двум после. Если сумма за день или два отличается от даты окончания этого месяца, отобразите недавно измененную сумму.

Пример 1. Извлеките клиента A для 31 октября-20, сравните с 01 НОЯБРЯ-20 и 02 НОЯБРЯ-20, выведите 200 для суммы.

Пример 2. Извлеките клиента B для 31 октября-20, сравните с 01 НОЯБРЯ-20 и 02 НОЯБРЯ-20, выведите 350 для суммы.

Комментарии:

1. Всегда ли даты будут последовательными? Или у вас может быть 31-OCT-20, за которым следует 15-NOV-20 для клиента (без строк для 1-NOV, 2-NOV и т. Д.)?

2. правильно, если нет строк для 1 ноября или 2 НОЯБРЯ, тогда просто отобразите исходную сумму за 31 октября

3. ОК. Какая у вас версия Oracle? Это можно легко сделать с match_recognize помощью, но для этого требуется версия 12.1 или выше. И, кроме того, что делать, если, например, у вас есть данные (для клиента) за 28 октября, но ничего за 29, 30, 31 октября? Вы хотите показать данные за 28 октября или вообще ничего за октябрь? Или это даже невозможно в ваших данных?

4. Вы выбрали «правильный ответ», который даст вам неправильный ответ, если в ваших данных отсутствуют даты, подобные 1 ноября. Вы сделали это после того, как я попросил вас дать разъяснения, и после того, как я прокомментировал ниже этот ответ, указав, что он НЕ будет корректно обрабатывать ситуации такого типа. Все, что я могу сказать, это БЛЕСТЯЩЕ !

Ответ №1:

Хммм . . .

 select t.*,
       (case when next_amount <> amount or next2_amount <> amount
             then greatest(next_amount, next2_amount)
             else next_amount
        end) as imputed_next_2_days
from (select t.*,
             lead(amount) over (partition by customer_name order by date) as next_amount,
             lead(amount, 2) over (partition by customer_name order by date) as next2_amount
      from t
     ) t
where date = last_day(date);
  

Комментарии:

1. Вам не хватает аргумента of 2 во втором вызове to lead() ?

2. Кроме того, обратите внимание на мой вопрос к OP и его ответ. LEAD работает с логическими смещениями (следующая строка, следующая строка после этого), а не с физическими смещениями (один день, два дня).).

Ответ №2:

Вы можете использовать следующий запрос:

 Select * from
  (Select t.*, 
          row_number() over (partition by customer_name order by dt desc) as rn
     From your_table t
    Where extract(day from t.dt   2) between 2 and 4)
Where rn = 1
  

Совет дня: не используйте зарезервированные ключевые слова oracle в качестве имени столбца. (Дата)