#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
для фильтрации строк, по которым оно выполняет агрегацию. Я подозреваю, что этот запрос будет быстрее — он немного менее сложный, — но было бы интересно увидеть результаты производительности на реальных данных.