我正在寻找一种可能更好的方法。
我已经在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
应包含先前3条记录的Filecount
的平均值(按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-“无法修改映射到非键保留表的列” *原因:试图插入或更新联接视图的列, 映射到非保留键的表。 *操作:直接修改基础基表。
我认为这应该可行,因为两个连接条件都在主键中,因此是唯一的。我目前正在上述答案中采用第一种方法,但是它变得越来越大,感觉应该对此有一个更好的解决方案。
我想尝试的其他事项:
AVG()
。但是,有人告诉我subselect的速度可能很慢,并且在Oracle性能方面,联接更好。邓诺(Dunno)确实是这样,还没有做任何测试编辑:我的插入内容现在看起来像这样。我已经汇总了一天的文件计数,因为每个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;
答案 0 :(得分:2)
您可以将分析平均值与window子句一起使用:
select dt, customer, filecount,
avg(filecount) over (partition by customer order by dt
rows between 3 preceding and 1 preceding) as avgfilecount
from tmp_foo
order by dt desc;
DT CUSTOMER FILECOUNT AVGFILECOUNT
---------- -------- ---------- ------------
2019-04-30 x 10 4.66666667
2019-04-29 x 2 6
2019-04-28 x 3 9
2019-04-27 x 9
,然后使用merge语句进行更新:
merge into tmp_foo t
using (
select dt, customer,
avg(filecount) over (partition by customer order by dt
rows between 3 preceding and 1 preceding) as avgfilecount
from tmp_foo
) s
on (s.dt = t.dt and s.customer = t.customer)
when matched then update set t.avgfilecount = s.avgfilecount;
4 rows merged.
select dt, customer, filecount, avgfilecount
from tmp_foo
order by dt desc;
DT CUSTOMER FILECOUNT AVGFILECOUNT
---------- -------- ---------- ------------
2019-04-30 x 10 4.66666667
2019-04-29 x 2 6
2019-04-28 x 3 9
2019-04-27 x 9
您没有显示原始的插入语句;可以向其中添加分析计算,并避免单独的更新步骤。
此外,如果您希望前两个日期值的计算方式类似于前两个“缺失”天数为零,则可以使用sum
和除法来代替avg
:>
select dt, customer, filecount,
sum(filecount) over (partition by customer order by dt
rows between 3 preceding and 1 preceding)/3 as avgfilecount
from tmp_foo
order by dt desc;
DT CUSTOMER FILECOUNT AVGFILECOUNT
---------- -------- ---------- ------------
2019-04-30 x 10 4.66666667
2019-04-29 x 2 4
2019-04-28 x 3 3
2019-04-27 x 9
这取决于您期望这些最后计算出的值是什么。