Я ищу, возможно, лучший подход к этому.
Я создал временную таблицу в Oracle 11.2, которую я использую для предварительного вычисления значений, которые мне понадобятся в других выборках, вместо того, чтобы всегда генерировать их снова при каждом выборе.
create global temporary table temp_foo (
DT timestamp(6), --only the date part will be used in this example but for later things I will need the time
Something varchar2(100),
Customer varchar2(100),
MinDate timestamp(6),
MaxDate timestamp(6),
Filecount int,
Errorcount int,
AvgFilecount int,
constraint PK_foo primary key (DT, Customer)
) on commit preserve rows;
Затем я сначала вставляю некоторые фиксированные значения для всего, кроме AvgFilecount
.AvgFilecount
должен содержать среднее значение для Filecount
для 3 предыдущих записей (по дате DT
).Неважно, что результат будет преобразован в int, мне не нужны десятичные разряды
DT | Customer | Filecount | AvgFilecount
2019-04-30 | x | 10 | avg(2+3+9)
2019-04-29 | x | 2 | based on values before this
2019-04-28 | x | 3 | based on values before this
2019-04-27 | x | 9 | based on values before this
Я думал об использовании обычного оператора UPDATE, поскольку это должно быть быстрее, чем циклически перебирать значения,Я должен отметить, что в поле DT
нет пробелов, но, очевидно, есть первый, где я не найду никаких предыдущих записей.Если бы я прошел цикл, я мог бы легко вычислить AvgFilecount
с (the record before previous record/2 + previous record)/3
, что я не могу с UPDATE, поскольку я не могу гарантировать порядок их выполнения.Так что я в порядке, просто взяв последние 3 записи (по DT) и посчитав их оттуда.
То, что я думаю, будет легким обновлением, вызывает у меня головную боль.Я в основном делаю SQL Server, где я просто присоединяюсь к 3 другим записям, но в Oracle это выглядит немного иначе.Я нашел https://stackoverflow.com/a/2446834/4040068 и хотел использовать второй подход в ответе.
update
(select curr.DT, curr.temp_foo, curr.Filecount, curr.AvgFilecount as OLD, (coalesce(Minus1.Filecount, 0) + coalesce(Minus2.Filecount, 0) + coalesce(Minus3.Filecount, 0)) / 3 as NEW
from temp_foo curr
left join temp_foo Minus1 ON Minus1.Customer = curr.Customer and trunc(Minus1.DT) = trunc(curr.DT-1)
left join temp_foo Minus2 ON Minus2.Customer = curr.Customer and trunc(Minus2.DT) = trunc(curr.DT-2)
left join temp_foo Minus3 ON Minus3.Customer = curr.Customer and trunc(Minus3.DT) = curr.DT-3
order by 1, 2
)
set OLD = NEW;
, который дает мне
ORA-01779: невозможно изменить столбецкоторая сопоставляется с таблицей без сохранения ключа 01779. 00000 - «не может изменить столбец, который сопоставляется с таблицей без сохранения ключа» * Причина: была предпринята попытка вставить или обновить столбцы представления объединения, которые сопоставляются с таблицей без сохранения ключа.сохранившийся под ключ стол.* Действие: измените базовые базовые таблицы напрямую.
Я подумал, что это должно сработать, поскольку оба условия соединения находятся в первичном ключе и поэтому уникальны.В настоящее время я реализую первый подход в вышеупомянутом ответе, но он становится довольно большим, и кажется, что должно быть лучшее решение для этого.
Другие вещи, которые я думал о попытке:
- с использованием вложенного подвыбора (вложенного, потому что Oracle не знает top (n) и мне нужно отсортировать подвыбор), чтобы выбрать предыдущий3 записи, заказанные DT, а затем он выбирает внешне с помощью rownum <= 3, и тогда я могу просто использовать <code>AVG().Тем не менее, мне сказали, что отбор может быть довольно медленным, а соединения лучше в плане производительности Oracle.Не знаю, если это действительно так, не проводил никаких тестов
Редактировать: Моя вставка сейчас выглядит следующим образом.Я уже собираю количество файлов за день, так как может быть несколько записей на DT
на Customer
на Something
.
insert into temp_foo (DT, Something, Customer, Filecount)
select dates.DT, tbl1.Something, tbl1.Customer, coalesce(sum(tbl3.Filecount),0)
from table(Function_Returning_Daterange(NULL, NULL)) dates
cross join
(SELECT Something,
Code,
Value
FROM Table2 tbl2
WHERE (Something = 'Value')) tbl1
left outer join Table3 tbl3
on tbl3.Customer = tbl1.Customer
and trunc(tbl3.MinDate) = trunc(dates.DT)
group by dates.DT, tbl1.Something, tbl1.Customer;