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

#sql #oracle #group-by #case

#sql #Oracle #группировка по #случай

Вопрос:

Учитывая таблицу, которая выглядит следующим образом, как бы я мог создать другой запрос, который принимает эти данные, сравнивает sales_net_amt с самой ранней и самой последней даты для этого store_id и возвращает одну строку для каждого store_id, отображая обычный текст для того, «увеличилось» или «уменьшилось» сверхурочное время в другом столбце?

введите описание изображения здесь

Для вычисляемого столбца я предполагаю, что мог бы просто использовать предложение «case when», но я не уверен, как я мог бы получить два отдельных значения последней и самой ранней дат для сравнения. Лучшее, что я мог сделать, это создать запрос, который отображал последние и самые ранние даты и их sales_net_amt, но я понятия не имею, как я могу добавить вычисляемый столбец в базу существующих значений

введите описание изображения здесь

Это запрос, который я сделал (столбец QUARTER не нужен и делает запрос излишне подробным, просто подумал, что я бы добавил его на данный момент на случай, если я в конечном итоге его использую):

 select case when extract(month from full_date) between 1 and 3 then substr(item_scan_timestamp, -4) || 'Q1'
     when extract(month from full_date) between 4 and 6 then substr(item_scan_timestamp, -4) || 'Q2'
     when extract(month from full_date) between 7 and 9 then substr(item_scan_timestamp, -4) || 'Q3'
     when extract(month from full_date) between 10 and 12 then substr(item_scan_timestamp, -4) || 'Q4' end quarter, r.store_id, p.full_date, r.sales_net_amt
from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
where (r.store_id, p.full_date) in (select r.store_id, max(p.full_date) full_date
        from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
        group by r.store_id)
union all
select case when extract(month from full_date) between 1 and 3 then substr(item_scan_timestamp, -4) || 'Q1'
     when extract(month from full_date) between 4 and 6 then substr(item_scan_timestamp, -4) || 'Q2'
     when extract(month from full_date) between 7 and 9 then substr(item_scan_timestamp, -4) || 'Q3'
     when extract(month from full_date) between 10 and 12 then substr(item_scan_timestamp, -4) || 'Q4' end quarter, r.store_id, p.full_date, r.sales_net_amt
from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
where (r.store_id, p.full_date) in (select r.store_id, min(p.full_date) full_date
        from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
        group by r.store_id)
order by store_id, full_date, sales_net_amt;

select store_id, full_date, sales_net_amt
from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
order by store_id;
 

Приветствуются любые советы.

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

1. Какую версию Oracle DB вы используете?

2. @etch_45 Оракул 12c

Ответ №1:

Вы можете использовать KEEP предложение в GROUP BY , если вам нужна одна запись на хранилище следующим образом:

 select store_id, 
       case when max(SALES_NET_AMT) keep (dense_rank first order by FULL_DATE desc) 
                  > max(SALES_NET_AMT) keep (dense_rank first order by FULL_DATE) 
            then 'Increased' 
            else 'Decreased' 
      end as result
  from your_Table t
group by store_id
 

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

1. Эй, это отлично работает! Можете ли вы объяснить, что делает предложение keep в этом сценарии? Не могли бы вы также разделить данные как часть функции window, а не использовать предложение group by ?

2. Предложение KEEP предоставляет данные на основе других значений группы. Вы должны прочитать об этом из документации oracle.

Ответ №2:

Предполагая, что ваш FULL_DATE столбец на самом деле является датой, вы можете использовать FIRST_VALUE и LAST_VALUE , чтобы получить первое и последнее значения по дате, а затем сравнить их:

 SELECT DISTINCT STORE_ID,
       CASE WHEN LAST_VALUE(SALES_NET_AMT) OVER (PARTITION BY STORE_ID ORDER BY FULL_DATE) >
                 FIRST_VALUE(SALES_NET_AMT) OVER (PARTITION BY STORE_ID ORDER BY FULL_DATE) THEN 'Increased'
            ELSE 'Decreased'
       END AS SALES_CHANGE
FROM YourTable
 

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

1. Это работает отлично. Можете ли вы объяснить ключевые различия между этим методом и методом @Tejash? Я никогда не знал об оконных и аналитических функциях, пока не прочитал ваш ответ и не провел некоторые исследования по нему, поэтому я не понимаю, что именно делает каждая часть запроса.

2. @Andrew в этом запросе используются оконные функции ( last_value и first_value ), которые эффективно сортируют строки по full_date и выбирают значение sales_net_amt , соответствующее этим строкам, в то время как другое решение выполняет агрегацию, используя keep для фильтрации строк, по которым оно выполняет агрегацию. Я подозреваю, что этот запрос будет быстрее — он немного менее сложный, — но было бы интересно увидеть результаты производительности на реальных данных.