ORACLE 多表关联 UPDATE 语句

摘要:
快乐无极,15:18,开发文档,评论(0),,阅读(539),Viaaceplus||引用地址:注意:该地址仅在今日23:59:59之前有效为了方便起见,建立了以下简单模型,和构造了部分测试数据:在某个业务受理子系统BSS中,--客户资料表createtablecustomers(customer_idnumber(8)notnull,--客户标示city_namevarchar2(10)notn
快乐无极 , 15:18 , 开发文档 , 评论(0) , , 阅读(539) , Via aceplusORACLE 多表关联 UPDATE 语句第1张 | | ORACLE 多表关联 UPDATE 语句第2张ORACLE 多表关联 UPDATE 语句第3张引用地址:
注意: 该地址仅在今日23:59:59之前有效 为了方便起见,建立了以下简单模型,和构造了部分测试数据:
在某个业务受理子系统BSS中,
--客户资料表
create table customers
(
customer_id number(8)not null,-- 客户标示
city_name varchar2(10) not null,-- 所在城市
customer_type char(2)not null,-- 客户类型
...
)
create unique index PK_customers on customers (customer_id)
由于某些原因,客户所在城市这个信息并不什么准确,但是在
客户服务部的CRM子系统中,通过主动服务获取了部分客户20%的所在
城市等准确信息,于是你将该部分信息提取至一张临时表中:
create table tmp_cust_city
(
customer_id number(8) not null,
citye_name varchar2(10) not null,
customer_typechar(2) not null
)
1) 最简单的形式
--经确认customers表中所有customer_id小于1000均为'北京'
--1000以内的均是公司走向全国之前的本城市的老客户:)
update customers
setcity_name='北京'
wherecustomer_id<1000
2) 两表(多表)关联update -- 仅在where字句中的连接
--这次提取的数据都是VIP,且包括新增的,所以顺便更新客户类别
update customers a -- 使用别名
setcustomer_type='01' --01 为vip,00为普通
whereexists (select 1
from tmp_cust_city b
whereb.customer_id=a.customer_id
)
3) 两表(多表)关联update -- 被修改值由另一个表运算而来
update customers a -- 使用别名
setcity_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
whereexists (select 1
from tmp_cust_city b
whereb.customer_id=a.customer_id
)
-- update 超过2个值
update customers a -- 使用别名
set(city_name,customer_type)=(select b.city_name,b.customer_type
from tmp_cust_city b
whereb.customer_id=a.customer_id)
whereexists (select 1
from tmp_cust_city b
whereb.customer_id=a.customer_id
)
注意在这个语句中,
=(select b.city_name,b.customer_type
from tmp_cust_city b
whereb.customer_id=a.customer_id
)

(select 1
from tmp_cust_city b
whereb.customer_id=a.customer_id
)
是两个独立的子查询,查看执行计划可知,对b表/索引扫描了2篇;
如果舍弃where条件,则默认对A表进行全表
更新,但由于(select b.city_name from tmp_cust_city b where whereb.customer_id=a.customer_id)
有可能不能提供"足够多"值,因为tmp_cust_city只是一部分客户的信息,
所以报错(如果指定的列--city_name可以为NULL则另当别论):
01407, 00000, "cannot update (%s) to NULL"
// *Cause:
// *Action:
一个替代的方法可以采用:
update customers a -- 使用别名
setcity_name=nvl((select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id),a.city_name)
或者
setcity_name=nvl((select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id),'未知')
-- 当然这不符合业务逻辑了
4) 上述3)在一些情况下,因为B表的纪录只有A表的20-30%的纪录数,
考虑A表使用INDEX的情况,使用cursor也许会比关联update带来更好的性能:
set serveroutput on
declare
cursor city_cur is
select customer_id,city_name
from tmp_cust_city
order by customer_id;
begin
for my_cur in city_cur loop
update customers
setcity_name=my_cur.city_name
wherecustomer_id=my_cur.customer_id;
/** 此处也可以单条/分批次提交,避免锁表情况 **/
-- if mod(city_cur%rowcount,10000)=0 then
-- dbms_output.put_line('----');
-- commit;
-- end if;
end loop;
end;
5) 关联update的一个特例以及性能再探讨
在oracle的update语句语法中,除了可以update表之外,也可以是视图,所以有以下1个特例:
update (select a.city_name,b.city_name as new_name
from customers a,
tmp_cust_city b
whereb.customer_id=a.customer_id
)
setcity_name=new_name
这样能避免对B表或其索引的2次扫描,但前提是 A(customer_id) b(customer_id)必需是unique index
或primary key。否则报错:
01779, 00000, "cannot modify a column which maps to a non key-preserved table"
// *Cause: An attempt was made to insert or update columns of a join view which
// map to a non-key-preserved table.
// *Action: Modify the underlying base tables directly.
6)oracle另一个常见错误
回到3)情况,由于某些原因,tmp_cust_city customer_id 不是唯一index/primary key
update customers a -- 使用别名
setcity_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
whereexists (select 1
from tmp_cust_city b
whereb.customer_id=a.customer_id
)
当对于一个给定的a.customer_id
(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
返回多余1条的情况,则会报如下错误:
01427, 00000, "single-row subquery returns more than one row"
// *Cause:
// *Action:
一个比较简单近似于不负责任的做法是
update customers a -- 使用别名
setcity_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id and rownum=1)
如何理解 01427 错误,在一个很复杂的多表连接update的语句,经常因考虑不周,出现这个错误,
仍已上述例子来描述,一个比较简便的方法就是将A表代入 值表达式 中,使用group by 和
having 字句查看重复的纪录
(select b.customer_id,b.city_name,count(*)
from tmp_cust_city b,customers a
where b.customer_id=a.customer_id
group by b.customer_id,b.city_name
having count(*)>=2
)

免责声明:文章转载自《ORACLE 多表关联 UPDATE 语句》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇处理大并发量订单处理的 KafKa部署总结WPF做的小型音乐播放器升级版下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

oracle 查询字段备注

select    A.column_name 字段名,B.comments 备注from    user_tab_columns A,user_col_comments Bwhere    A.Table_Name = B.Table_Name    and A.Column_Name = B.Column_Name    and A.Table_Nam...

oracle优化的几个简单步骤

数据库优化的讨论可以说是一个永恒的主题。资深的Oracle优化人员通常会要求提出性能问题的人对数据库做一个statspack,贴出数据库配置等等。还有的人认为要抓出执行最慢的语句来进行优化。但实际情况是,提出疑问的人很可能根本不懂执行计划,更不要说statspack了。而我认为,数据库优化,应该首先从大的方面考虑:网络、服务器硬件配置、操作系统配置、Ora...

Golang 对MongoDB的操作简单封装

使用MongoDB的Go驱动库mgo,对MongoDB的操作做一下简单封装 初始化 操作没有用户权限的MongoDB var globalS *mgo.Session func init() { s, err := mgo.Dial(dialInfo) if err != nil { log.Fatalf("Create...

Oracle 数据库监听配置

一、监听器(LISTENER)   监听器是Oracle基于服务器端的一种网络服务,主要用于监听客户端向数据库服务器端提出的连接请求。既然是基于服务器端的服务,那么它也只存在于数据库服务器端,进行监听器的设置也是在数据库服务器端完成的。   二、本地服务名(Tnsname)   Oracle客户端与服务器端的连接是通过客户端发出连接请求,由服务器端监听器...

Linux上的oracle巡检脚本

修改自大神博客:http://www.cnblogs.com/jyzhao/p/5364049.html 脚本巡检的优化:自动化,节省时间。 脚本需加强:巡检结果中有大量的sqlplus连接信息,后期考虑用shell只过滤出有用信息,优化查看。 开始介绍: 1.环境sentos67、redhat6 2.可以将脚本放至/home/oracle/checkdi...

Oracle 后台进程 详细说明

一. 进程概述 先来看一下Oracle 11g 的架构图。 看起来比较模糊,我已经上传到了csdn 的下载。 是个pdf 文件, 2m 多。 那个看起来比较清楚。 也对每个进程做了解释。 下载地址:Oracle 11g 架构图 from Oracle University http://download.csdn.net/source/2346700 进...