`

ORACLE UPDATE 语句语法与性能分析

阅读更多

为了方便起见,建立了以下简单模型,和构造了部分测试数据:
  在某个业务受理子系统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_type  char(2)   not null
  )
 
1) 最简单的形式
   --经确认customers表中所有customer_id小于1000均为'北京'
   --1000以内的均是公司走向全国之前的本城市的老客户:)
   update customers
   set    city_name='北京'
   where  customer_id<1000

2) 两表(多表)关联update -- 仅在where字句中的连接
   --这次提取的数据都是VIP,且包括新增的,所以顺便更新客户类别
   update customers  a       -- 使用别名
   set    customer_type='01' --01 为vip,00为普通
   where  exists (select 1
                  from   tmp_cust_city b
                  where  b.customer_id=a.customer_id
                 )

3) 两表(多表)关联update -- 被修改值由另一个表运算而来
   update customers a   -- 使用别名
   set    city_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
   where  exists (select 1
                  from   tmp_cust_city b
                  where  b.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
                                     where  b.customer_id=a.customer_id)
   where  exists (select 1
                  from   tmp_cust_city b
                  where  b.customer_id=a.customer_id
                 )
   注意在这个语句中,
                                   =(select b.city_name,b.customer_type
                                     from   tmp_cust_city b
                                     where  b.customer_id=a.customer_id
                                    )
   与
                 (select 1
                  from   tmp_cust_city b
                  where  b.customer_id=a.customer_id
                 )
   是两个独立的子查询,查看执行计划可知,对b表/索引扫描了2篇;
   如果舍弃where条件,则默认对A表进行全表
   更新,但由于(select b.city_name from tmp_cust_city b where where  b.customer_id=a.customer_id)
   有可能不能提供"足够多"值,因为tmp_cust_city只是一部分客户的信息,
   所以报错(如果指定的列--city_name可以为NULL则另当别论):
  
01407, 00000, "cannot update (%s) to NULL"
// *Cause:
// *Action:

   一个替代的方法可以采用:
   update customers a   -- 使用别名
   set    city_name=nvl((select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id),a.city_name)
   或者
   set    city_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
        set    city_name=my_cur.city_name
        where  customer_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
            where  b.customer_id=a.customer_id
           )
    set    city_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   -- 使用别名
   set    city_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
   where  exists (select 1
                  from   tmp_cust_city b
                  where  b.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   -- 使用别名
   set    city_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)

   如何理解 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 语句语法与性能分析看法

    ORACLE UPDATE 语句语法与性能分析看法

    ORACLE_UPDATE_语句语法与性能分析

    ORACLE_UPDATE_语句语法与性能分析

    ORACLE和SQL Server的语法区别

    1. 验证所有 SELECT、INSERT、UPDATE 和 DELETE 语句的语法是有效的。进行任何必要的修改。 2. 把所有外部联接改为 SQL-92 标准外部联接语法。 3. 用相应 SQL Server 函数替代 Oracle 函数。 4. 检查所有的比较...

    Oracle_PLSQL_语法详细手册

    五、 UPDATE语句: 9 六、 DELETE语句: 10 七、 TRUNCATE语句: 11 八、 各类FUNCTIONS: 12 1. 转换函数: 12 2. 日期函数 16 3. 字符函数 20 4. 数值函数 28 5. 单行函数: 33 6. 多行函数 35 第二部分 PL/SQL语法部分 ...

    oracle和SQL的语法区别

    1. 验证所有 SELECT、INSERT、UPDATE 和 DELETE 语句的语法是有效的。进行任何必要的修改。 2. 把所有外部联接改为 SQL-92 标准外部联接语法。 3. 用相应 SQL Server 函数替代 Oracle 函数。 4. 检查所有的比较...

    SQLServer与Oracle语法差异汇总.docx

    从存储过程 自定义函数格式 游标 变量 赋值 语句结束符 大小写 Select 语法 Update语法 Delete语法 动态SQL语句 TOP用法 等各方面对比两个数据库的差异

    oracle基础语法培训.ppt

    SELECT语句 INSERT语句 UPDATE语句 DELETE删除 常用函数

    Sql Server与Oracle的区别

    1. 验证所有 SELECT、INSERT、UPDATE 和 DELETE 语句的语法是有效的。进行任何必要的修改。 2. 把所有外部联接改为 SQL-92 标准外部联接语法。 3. 用相应 SQL Server 函数替代 Oracle 函数。 4. 检查所有的比较...

    MySQL与Oracle的语法区别详细对比

    Oracle和mysql的一些简单命令对比 1) SQL&gt; select to_char(sysdate,’yyyy-mm-dd’) from dual; SQL&gt; select to_char(sysdate,’hh24-mi-ss’) from dual; mysql&gt; select date_format(now(),’%Y-%m-%d’); mysql&gt; ...

    SQL语句生成及分析器(中文绿色)

    1、支持绝大部分数据库,包括 大型数据库Oracle,Sybase(包括SQL AnyWhere),DB2,MS_SQL 中型数据库MS_Access,MySQL 桌面型数据库Paradox,DBF系列数据库... 10.4 简单SQL查询语句转换为Delete,Update,Insert语句

    SQL语句生成及分析器

    该工具的主要特色: 1、支持几乎所有类型的数据库, ...6、支持将SQL查询语句,替换为插入(Insert into)和更新(Update)语句 7、附属工具内嵌入Delphi IDE(支持Delphi 5和Delphi 6) 8、文件拖放(SQL和TXT文件)

    在Delphi中更新数据库UPDATE语句使用示例

    一个Delphi例子,配合Access数据库实现Delphi中的UPDATA数据更新实例,其实是演示如何使用SQL的Update语句,是一个数据库范畴的例子,Delphi高手请跳过,新手可下载源码学习。 运行环境:Delphi+Access

    sql语句生成与分析器.rar

    11.4 简单SQL查询语句转换为Delete,Update,Insert语句 11.5 复制为字符串(支持对Java、C#、Delphi、VB、PowerBuilder开发语言的支持) 11.6 灵活的拖放功能 11.7 在线版本更新 11.8 查询结果输出为SQL脚本...

    oracle动态性能表

    oracle动态性能表 学习动态性能表 第一篇--v$sysstat 2007.5.23  按照OracleDocument中的描述,v$sysstat存储自数据库实例运行那刻起就开始累计全实例(instance-wide)的资源使用情况。 类似于v$sesstat,该视图...

    sql server的 update from 语句的深究

    一般来说update一个表, 使用where语句即可: 代码如下: UPDATE Ttest SET  statusInd = ‘ACTIVE’  WHERE  id = 123 注意: update 语句后面的table名称,是不可以启用别名的。 那么此时的id字段,就是来自...

    oracle基本语句

    oracle最基本的sql语法,select,update等等

    MySQL中实现插入或更新操作(类似Oracle的merge语句)

    可以使用以下语句: 更新一个字段: INSERT INTO tbl (columnA,columnB,columnC) VALUES (1,2,3) ON DUPLICATE KEY UPDATE columnA=IF(columnB&gt;0,1,columnA) 更新多个字段: INSERT INTO tbl (columnA,columnB,...

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    1.7 UPDATE语句 17 1.8 DELETE语句 20 1.9 MERGE语句 22 1.10 小结 24 第2章 SQL执行 25 2.1 Oracle架构基础 25 2.2 SGA-共享池 27 2.3 库高速缓存 28 2.4 完全相同的语句 29 2.5 SGA-缓冲区缓存 32 2.6 ...

Global site tag (gtag.js) - Google Analytics