#sql #oracle
Вопрос:
Итак, запрос прост, но я сталкиваюсь с проблемами при реализации логики Sql. Вот запрос, предположим, у меня есть такие записи, как
Phoneno Company Date Amount
83838 xyz 20210901 100
87337 abc 20210902 500
47473 cde 20210903 600
Ожидаемый результат-прогресс за последние 7 дней в среднем за каждую дату (текущая дата за 6 дней до этого).
Date amount avg
20210901 100 100
20210902 500 300
20210903 600 400
Я пытался
Select date, amount, select
avg(lg) from (
Select case when lag(amount)
Over (order by NULL) IS NULL
THEN AMOUNT
ELSE
lag(amount)
Over (order by NULL) END AS LG)
From table
WHERE DATE>=t.date-7) as avg
From table t;
Но я получаю неправильные средние значения. Кто-нибудь может, пожалуйста, помочь?
Примечание: Я тоже пробовал без задержек, это тоже приводит к неправильным средним значениям
Комментарии:
1. либо это mysql, либо oracle, но не то и другое вместе.
2. Помечайте только ту базу данных, которую вы используете.
3. Добавлена база данных
Ответ №1:
Вы можете использовать self join
для группировки дат
select distinct
a.dt,
b.dt as preceding_dt, --just for QA purpose
a.amt,
b.amt as preceding_amt,--just for QA purpose
avg(b.amt) over (partition by a.dt) as avg_amt
from t a
join t b on a.dt-b.dt between 0 and 6
group by a.dt, b.dt, a.amt, b.amt; --to dedupe the data after the join
Если вы хотите, чтобы ваш correlated subquery
подход работал, вам на самом деле это не нужно lag
.
select dt,
amt,
(select avg(b.amt) from t b where a.dt-b.dt between 0 and 6) as avg_lg
from t a;
Если у вас нет нескольких строк на дату, это становится еще проще
select dt,
amt,
avg(amt) over (order by dt rows between 6 preceding and current row) as avg_lg
from t;
Кроме того, условие DATE>=t.date-7
, которое вы использовали, оставлено открытым с одной стороны, что означает, что оно будет соответствовать множеству дат, которые не должны были быть определены.
Комментарии:
1. Также ценю ваши усилия, я хочу знать, почему это сработало в моем запросе
2. @HimanshuAhuja Надеюсь, мое редактирование поможет
3. Великий человек! Вот что я делал, о чем я думал, когда использовал один и тот же запрос, запутанный в предложении where, я думаю
Ответ №2:
Вы можете использовать аналитическую функцию с предложением windowing для получения результатов:
SELECT DISTINCT BillingDate,
AVG(amount) OVER (ORDER BY BillingDate
RANGE BETWEEN TO_DSINTERVAL('7 00:00:00') PRECEDING
AND TO_DSINTERVAL('0 00:00:00') FOLLOWING) AS RUNNING_AVG
FROM accounts
ORDER BY BillingDate;
Вот DBFiddle, показывающий запрос в действии (ССЫЛКА)