Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1213407
  • 博文数量: 398
  • 博客积分: 10110
  • 博客等级: 上将
  • 技术积分: 4055
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-23 20:01
个人简介

新博客http://www.cnblogs.com/zhjh256 欢迎访问

文章分类

全部博文(398)

文章存档

2012年(1)

2011年(41)

2010年(16)

2009年(98)

2008年(142)

2007年(100)

我的朋友

分类: Oracle

2008-01-06 21:47:59

基本方法

       通常会见到的情况,某张表中缺少某些数据,某个用户将一部分数据通过文本文件传输过来,要求更新表中的数据。如下:

create table invoices (

invoice#  number,

amount      number,

po_xref      varchar2(15));

 

insert into invoices (invoice#, amount) values (16535,45.67);

insert into invoices (invoice#, amount) values (16536,100.00);

insert into invoices (invoice#, amount) values (16537,66.99);

 

select * from invoices;

 

  INVOICE#     AMOUNT PO_XREF
---------- ---------- ---------------
     16535      45.67
     16536        100
     16537      66.99

提供的文本文件数据如下:

16535,GH-78346DD
16537,F9-7456QAI

       我们可以创建一个外部表进行访问:

create directory exttab as 'c:\';
grant read, write on directory exttab to public;

create table poxref (
invoice#     number,
xref        varchar2(15))
organization external
(type oracle_loader
default directory exttab
access parameters
  (records delimited by newline
   fields terminated by ','
   missing field values are null)
location ('textfile.csv')
)
reject limit unlimited;

 

SQL> select * from poxref;

 

  INVOICE# XREF

---------- ---------------

     16535 GH-78346DD

     16537 F9-7456QAI

然后我们就可以使用相关的子查询进行更新:

SQL> update invoices i set po_xref=(select xref from poxref where invoice#=i.invoice#);

 

3 rows updated

 

SQL> select * from invoices;

 

  INVOICE#     AMOUNT PO_XREF

---------- ---------- ---------------

     16537      66.99 F9-7456QAI

     16535      45.67 GH-78346DD

     16536        100

       这种情况下,我们可以看到更新两行。也可以扩展到相关删除:

SQL> delete from invoices i

where invoice# =(select invoice# from poxref where xref=i.po_xref);

 

2 rows deleted

相关子查询的问题是?

       如下:

SQL> delete from invoices;

 

1 row deleted

 

SQL> COMMIT;

 

Commit complete

 

SQL> insert into invoices (invoice#, amount) values (16535,45.67);

 

1 row inserted

 

SQL> insert into invoices (invoice#, amount) values (16536,100.00);

 

1 row inserted

 

SQL> insert into invoices (invoice#, amount) values (16537,66.99);

 

1 row inserted

 

SQL> update invoices set PO_XREF='hjr' where invoice#=16536;

 

1 row updated

 

SQL> commit;

 

Commit complete

SQL> select * from invoices;

 

  INVOICE#     AMOUNT PO_XREF

---------- ---------- ---------------

     16535      45.67

     16536        100 hjr

     16537      66.99

 

SQL> update invoices i set po_xref=(select xref from poxref where invoice#=i.invoice#);

 

3 rows updated

 

SQL> select * from invoices;

 

  INVOICE#     AMOUNT PO_XREF

---------- ---------- ---------------

     16535      45.67 GH-78346DD

     16536        100

     16537      66.99 F9-7456QAI

       可以看到,这里实际上更新了三行,而我们的意图是更新两行。因为内部选择的输出没有匹配16536的条目,外部更新语句将PO_XREF更新为NULL,因此会出现这种结果。

       要修复该问题,可以执行以下查询:

SQL> rollback;

 

Rollback complete

 

SQL> update invoices i set po_xref=(select xref from poxref where invoice#=i.invoice#) where PO_XREF is null;

 

2 rows updated

 

SQL> select * from invoices;

 

  INVOICE#     AMOUNT PO_XREF

---------- ---------- ---------------

     16535      45.67 GH-78346DD

     16536        100 hjr

     16537      66.99 F9-7456QAI

       外查询的WHERE恰当的限制了更新的纪录。

 

       还有一种方法是首先创建一个视图仅包含需要更新的数据,然后更新视图:

SQL> update invoices set PO_XREF=NULL where invoice# in (16535,16537);

 

2 rows updated

 

SQL> commit;

 

Commit complete

 

SQL> create view viewinvoice as select * from invoices where PO_XREF is null;

 

View created

 

SQL> update viewinvoice v set po_xref=(select xref from poxref p where invoice#=v.invoice#);

 

2 rows updated

SQL> select * from invoices;

 

  INVOICE#     AMOUNT PO_XREF

---------- ---------- ---------------

     16535      45.67 GH-78346DD

     16536        100 hjr

     16537      66.99 F9-7456QAI

虽然这种方法可行,但是需要每次都创建额外的视图。

 

       很幸运,不一定要创建视图,可以使用内嵌视图:

UPDATE (SELECT po_xref, xref
        FROM invoices i, poxref   p
        WHERE i.invoice# = p.invoice#)
SET po_xref = xref;

可以使用这种方法更新,但是需要在相关的列上包含唯一约束。

否则将得到ORA-01779: 无法修改与非键值保存表对应的列错误。

还有一种通过使用未文档化提示的方法避免增加唯一索引实现:

UPDATE (SELECT /*+ BYPASS_UJVC */ po_xref, xref

FROM invoices i, poxref   p

        WHERE i.invoice# = p.invoice#)

SET po_xref = xref;

 

阅读(1358) | 评论(0) | 转发(0) |
0

上一篇:对象标识符

下一篇:关于段压缩

给主人留下些什么吧!~~