用mergemerge into lzyrealamount_gsm_0912 a using (select svcnum, sum(chrgamount) as chrgamount from lzysvcnum_acctinsht group by svcnum ) b on(a.msisdn=b.svcnum and a.innetmonth <= '200911') when matched then update set (a.chargefee=b.chrgamount)
这个我看过了啊,能不能讲一下merge它的原理。还有,比如说下面句子 MERGE INTO products p USING newproducts np ON (1=0) WHEN NOT MATCHED THEN INSERT VALUES (np.product_id, np.product_name, np.category) WHERE np.category = 'BOOKS' 你把p表和np表对调有什么区别。 on()中的条件和where条件有什么不同,如果我把where的条件放到on()里面,效果有什么区别啊?
MERGE INTO products p -- 更新表 P USING newproducts np -- 使用表 NP ON (1=0) -- 更新的条件 WHEN NOT MATCHED THEN -- 如果不能更新 INSERT -- 插入语句 VALUES (np.product_id, np.product_name, np.category) WHERE np.category = 'BOOKS' -- 插入语句条件 我没用过MERGE INTO 大概我是这么理解的 应该没错
哈哈,大神就是大神。 那如果我这样写 MERGE INTO products p USING newproducts np ON (np.category = 'BOOKS') -- 更新的条件 WHEN MATCHED THEN INSERT VALUES (np.product_id, np.product_name, np.category) 会是什么结果啊?
哦,我都是在网上搜的,对游标也不了解。我分析了一下,把里面的很多条件拿出来单独测试 --这是原句 update lzyrealamount_gsm_0912 a --这个表数据量774906 set chargefee = (select sum(chrgamount) from lzysvcnum_acctinsht where svcnum = a.msisdn) where a.innetmonth <= '200911' and exists (select 1 from lzysvcnum_acctinsht --这个表数据量4469617 where svcnum = a.msisdn); --set后面的子查询 select sum(chrgamount) from lzysvcnum_acctinsht,lzyrealamount_gsm_0912 a where svcnum = a.msisdn;--没有建立索引单独执行一次耗时平均为22.5秒,建立索引平均时间为10.5秒 --满足更新条件的数据总条数 select count(*) from lzyrealamount_gsm_0912 a--这个表数据量774906 where a.innetmonth <= '200911' and exists (select 1 from lzysvcnum_acctinsht --这个表数据量4469617 where svcnum = a.msisdn);--符合条件的数据为352081条,搜索时间为30秒,为总表数量的一半 你说用什么方法优化比较好啊,我现在想把满足更新条件的语句抽出来,然后用游标循环 for abc (select chargefee from lzyrealamount_gsm_0912 a where a.innetmonth <= '200911' and exists (select 1 from lzysvcnum_acctinsht where svcnum = a.msisdn)) loop abc := (select sum(chrgamount) from lzysvcnum_acctinsht where svcnum = a.msisdn); end loop; 你说这个行不啊,我也不太懂。可能语法也有问题
免得你走弯路了,我直接把你贴的那段SQL语句改写好了,你去执行下,我猜的没错的话,30秒内可以更新完毕。 begin for cr in (select a.rowid, sum(b.chrgamount) chrgamount from lzyrealamount_gsm_0912 a,lzysvcnum_acctinsht b where a.msisdn = b.svcnum and a.innetmonth <= '200911') loop update lzyrealamount_gsm_0912 set chargefee = cr.chrgamount where rowid = cr.rowid; end loop; end;
哈哈,你人太好了begin for abc in (select chargefee from lzyrealamount_gsm_0912 a where a.innetmonth <= '200911' and exists (select 1 from lzysvcnum_acctinsht where svcnum = a.msisdn)) loop select sum(chrgamount) into abc.chargefee from lzysvcnum_acctinsht,lzyrealamount_gsm_0912 where svcnum = msisdn; end loop; end;这是我刚才用的方法,结果老报错,说什么number too large 哎,大神就是大神啊。
我靠,你真乃神人也,40秒搞定。 对了,你少了个group by a.rowid,我太崇拜你了
不好意思,写错了,这里纠正下: begin for cr in (select a.rowid, sum(b.chrgamount) chrgamount from lzyrealamount_gsm_0912 a,lzysvcnum_acctinsht b where a.msisdn = b.svcnum and a.innetmonth <= '200911' group by a.rowid) loop update lzyrealamount_gsm_0912 set chargefee = cr.chrgamount where rowid = cr.rowid; end loop; end;如果你执行下也会发现,会报一个不是分组的错误,因为这里面用到了分组汇总,忘了加了。
using (select svcnum, sum(chrgamount) as chrgamount
from lzysvcnum_acctinsht
group by svcnum ) b
on(a.msisdn=b.svcnum and a.innetmonth <= '200911')
when matched then update set (a.chargefee=b.chrgamount)
MERGE INTO products p
USING newproducts np
ON (1=0)
WHEN NOT MATCHED THEN
INSERT
VALUES (np.product_id, np.product_name, np.category)
WHERE np.category = 'BOOKS'
你把p表和np表对调有什么区别。
on()中的条件和where条件有什么不同,如果我把where的条件放到on()里面,效果有什么区别啊?
USING newproducts np -- 使用表 NP
ON (1=0) -- 更新的条件
WHEN NOT MATCHED THEN -- 如果不能更新
INSERT -- 插入语句
VALUES (np.product_id, np.product_name, np.category)
WHERE np.category = 'BOOKS' -- 插入语句条件
我没用过MERGE INTO 大概我是这么理解的 应该没错
那如果我这样写
MERGE INTO products p
USING newproducts np
ON (np.category = 'BOOKS') -- 更新的条件
WHEN MATCHED THEN INSERT
VALUES (np.product_id, np.product_name, np.category)
会是什么结果啊?
再不行,forall bulk+limit更新
注意你是在过程里写的,注意字面量用绑定变量替代!~
基本就这么几个技巧!
大神们能不能给出一个理论上的比较,对于大数据量那种方法比较好。现在我知道的有update表关联,merge,游标,还有你刚才说的inline视图(等等百度上学习下)。那种比较适合,或者组合起来使用
我看过merge的原理了,在9i中,它的作用是查询B表(用作比较的表)的数据在A表(咱们要进行更新或者插入的表)中是否存在,存在就更新,否则就插入。所以大家使用的时候一定要小心啊。merge的操作次数完全由B表的数据条数来决定(当然要考虑where条件判断)决定。我还想问一下,游标我看很多人说当数据量比较大的时候就不行了,而且微软文档也说当数据超过2000条(我记不太清楚了啊)就不建议在使用游标了。嘿嘿,其实你才是真正解答我疑惑的人,我就想知道红色部分和蓝色部分的效率及其执行过程中的原理。那我回去改下,我开始也觉得set操作后面要调用子查询。
再是Oracle游标更新时需要用ROWID,这个微软绝对没有提供支持,这样即使是上百万数据的表中更新几万数据也不是问题。
--这是原句
update lzyrealamount_gsm_0912 a --这个表数据量774906
set chargefee = (select sum(chrgamount)
from lzysvcnum_acctinsht
where svcnum = a.msisdn)
where a.innetmonth <= '200911'
and exists (select 1 from lzysvcnum_acctinsht --这个表数据量4469617
where svcnum = a.msisdn);
--set后面的子查询
select sum(chrgamount)
from lzysvcnum_acctinsht,lzyrealamount_gsm_0912 a
where svcnum = a.msisdn;--没有建立索引单独执行一次耗时平均为22.5秒,建立索引平均时间为10.5秒
--满足更新条件的数据总条数
select count(*) from lzyrealamount_gsm_0912 a--这个表数据量774906
where a.innetmonth <= '200911'
and exists (select 1 from lzysvcnum_acctinsht --这个表数据量4469617
where svcnum = a.msisdn);--符合条件的数据为352081条,搜索时间为30秒,为总表数量的一半
你说用什么方法优化比较好啊,我现在想把满足更新条件的语句抽出来,然后用游标循环
for abc (select chargefee from lzyrealamount_gsm_0912 a
where a.innetmonth <= '200911'
and exists (select 1 from lzysvcnum_acctinsht
where svcnum = a.msisdn)) loop
abc := (select sum(chrgamount)
from lzysvcnum_acctinsht
where svcnum = a.msisdn);
end loop;
你说这个行不啊,我也不太懂。可能语法也有问题
begin
for cr in (select a.rowid, sum(b.chrgamount) chrgamount from lzyrealamount_gsm_0912 a,lzysvcnum_acctinsht b
where a.msisdn = b.svcnum and a.innetmonth <= '200911') loop
update lzyrealamount_gsm_0912 set chargefee = cr.chrgamount where rowid = cr.rowid;
end loop;
end;
for abc in (select chargefee from lzyrealamount_gsm_0912 a
where a.innetmonth <= '200911'
and exists (select 1 from lzysvcnum_acctinsht
where svcnum = a.msisdn)) loop
select sum(chrgamount) into abc.chargefee
from lzysvcnum_acctinsht,lzyrealamount_gsm_0912
where svcnum = msisdn;
end loop;
end;这是我刚才用的方法,结果老报错,说什么number too large
哎,大神就是大神啊。
我靠,你真乃神人也,40秒搞定。
对了,你少了个group by a.rowid,我太崇拜你了
begin
for cr in (select a.rowid, sum(b.chrgamount) chrgamount from lzyrealamount_gsm_0912 a,lzysvcnum_acctinsht b
where a.msisdn = b.svcnum and a.innetmonth <= '200911'
group by a.rowid) loop
update lzyrealamount_gsm_0912 set chargefee = cr.chrgamount where rowid = cr.rowid;
end loop;
end;如果你执行下也会发现,会报一个不是分组的错误,因为这里面用到了分组汇总,忘了加了。
大神,我真的太崇拜你了