Ask Hoegh(8)——都是唯一索引惹的祸

问:

最近有个项目提出新需求,其中一个业务表的主键字段需要修改;
麻烦的是,对于新的主键字段,表的已有数据中包含重复数据,
请问这个需求可以实现吗?具体该如何操作?


答:

首先这个需求肯定是可以实现的,在具体演示如何实现之前,我们先回顾一下针对Oracle约束的一组关键字 Ena ble/Disable/Validate/Novalidate

一、Enable/Disable/Validate/Novalidate


Validate Novalidate
已有记录 新增/删除记录 已有记录
新增/删除记录
Enable Yes Yes
No Yes
Disable Yes
No
No
No

Validate确保已有数据符合约束;

Novalidate不必考虑已有数据是否符合约束。

 

除非Novalidate被指定,Enable默认Validate

除非Validate被指定,Disable默认Novalidate

 

Enable ValidateEnable相同,检查已有记录和新增记录,确保都符合约束;

Enable Novalidate 允许已有记录不必满足约束条件,但新增/修改的记录必须满足;

Disable Validate禁用约束,删除约束上的索引,不允许修改任何被约束的记录;

Disable NovalidateDisable相同,禁用约束,删除约束上的索引,且允许修改被约束的记录。


     针对我们的问题,我们需要关注的是 Enable Novalidate,也就是说 允许已有记录不必满足约束条件,但新增 / 修改的记录必须满足。

二、创建测试表

点击(此处)折叠或打开

  1. SQL> select * from v$version;

  2. BANNER
  3. ----------------------------------------------------------------
  4. Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
  5. PL/SQL Release 10.2.0.4.0 - Production
  6. CORE    10.2.0.4.0    Production

  7. TNS for 64-bit Windows: Version 10.2.0.4.0 - Production
  8. NLSRTL Version 10.2.0.4.0 - Production

  9. SQL> create table hoegh(x number,y number,z number,
  10.   2 constraint pk_hoegh primary key(x,y));

  11. Table created

  12. SQL> insert into hoegh values(1,1,1);

  13. 1 row inserted

  14. SQL> insert into hoegh values(1,2,1);

  15. 1 row inserted

  16. SQL> commit;

  17. Commit complete

  18. SQL>
  19. SQL> select * from hoegh;

  20.          X Y Z
  21. ---------- ---------- ----------
  22.          1 1 1
  23.          1 2 1

三、针对非主键约束的Enable Novalidate

     我们以check约束为例看一下如何使用 Enable Novalidate关键字。

点击(此处)折叠或打开

  1. SQL> alter table hoegh add constraint check_z check(z>1) enable validate;

  2. alter table hoegh add constraint check_z check(z>1) enable validate

  3. ORA-02293: 无法验证 (HOEGH.CHECK_Z) - 违反检查约束条件

  4. SQL> alter table hoegh add constraint check_z check(z>1) enable novalidate;

  5. Table altered

  6. SQL> insert into hoegh values(2,1,1);

  7. insert into hoegh values(2,1,1)

  8. ORA-02290: 违反检查约束条件 (HOEGH.CHECK_Z)

  9. SQL>
      我们可以看到,第一次我们尝试添加 Enable Validate的check约束,但是已有数据中违反了该约束,因此添加失败;第二次尝试添加Enable Novalidate的check约束,成功了。
     同样的,外键约束也可以参考上述语句来添加或修改,那么主键约束可以吗?


四、针对主键约束的Enable Novalidate

     1.查看当前约束和索引

点击(此处)折叠或打开

  1. SQL> select constraint_name,constraint_type FROM user_constraints where table_name='HOEGH';

  2. CONSTRAINT_NAME CONSTRAINT_TYPE
  3. ------------------------------ ---------------
  4. PK_HOEGH P

  5. SQL>
  6. SQL> select index_name,index_type,uniqueness from user_indexes where table_name='HOEGH';

  7. INDEX_NAME INDEX_TYPE UNIQUENESS
  8. ------------------------------ --------------------------- ----------
  9. PK_HOEGH NORMAL UNIQUE

  10. SQL>

      2.删除当前主键约束和索引

点击(此处)折叠或打开

  1. SQL> alter table hoegh drop constraint PK_HOEGH cascade drop index;

  2. Table altered

  3. SQL> select constraint_name,constraint_type FROM user_constraints where table_name='HOEGH';

  4. CONSTRAINT_NAME CONSTRAINT_TYPE
  5. ------------------------------ ---------------

  6. SQL> select index_name,index_type,uniqueness from user_indexes where table_name='HOEGH';

  7. INDEX_NAME INDEX_TYPE UNIQUENESS
  8. ------------------------------ --------------------------- ----------

  9. SQL>

      3.尝试添加主键约束并设置Enable Novalidate

点击( 此处 )折叠或打开
  1. SQL>
  2. SQL> alter table hoegh add constraint PK_HOEGH primary key(x,z) enable novalidate;

  3. alter table hoegh add constraint PK_HOEGH primary key(x,z) enable novalidate

  4. ORA-02437: 无法验证 (HOEGH.PK_HOEGH) - 违反主键

  5. SQL>
  6. SQL> select * from hoegh;

  7.          X Y Z
  8. ---------- ---------- ----------
  9.          1 1 1
  10.          1 2 1

  11. SQL>
      我们看到添加主键约束失败了,提示“ORA-02437: 无法验证 (SCOTT.PK_HOEGH) - 违反主键”,也就是说已有的数据不满足新的主键约束;
      虽然我们设置了 Novalidate ,但是和我们预想的结果不一致,数据库仍 然检验了已有数据。

     我们知道主键约束=唯一约束+非空约束,那么这个是不是和唯一约束有关系呢?
     接下来,我们尝试添加一个唯一约束,同时设置 Enable  Nov alidate。
点击( 此处 )折叠或打开
  1. SQL> alter table hoegh add constraint unq_xz unique(x,z) enable novalidate;

  2. alter table hoegh add constraint unq_xz unique(x,z) enable novalidate

  3. ORA-02299: 无法验证 (HOEGH.UNQ_XZ) - 找到重复关键字

  4. SQL>
    我们看到也失败了,看来根源就在这里。创建主键时系统缺省还要同时创建一个唯一索引,novalidate只是使主键约束不对已经存在的数据进行检验,并不对创建唯一索引进行控制,所以导致失败。
   那么如何解决这个问题呢?接着往下看。

     4.创建普通索引,然后添加主键约束并设置Enable Novalidate

      我们 可以在创建主键前先给该字段建个普通 非唯一索引,这样建主键时系统就会自动利用这个普通索引了。
点击( 此处 )折叠或打开
  1. SQL>
  2. SQL> create index idx_xz on hoegh(x,z);

  3. Index created

  4. SQL> alter table hoegh add constraint PK_HOEGH primary key(x,z) enable novalidate;

  5. Table altered

  6. SQL> insert into hoegh values(1,3,1);

  7. insert into hoegh values(1,3,1)

  8. ORA-00001: 违反唯一约束条件 (HOEGH.PK_HOEGH)

  9. SQL> select * from hoegh;

  10.          X Y Z
  11. ---------- ---------- ----------
  12.          1 1 1
  13.          1 2 1

  14. SQL>
  15. SQL> insert into hoegh values(1,3,2);

  16. 1 row inserted

  17. SQL> commit;

  18. Commit complete

  19. SQL>
  20. SQL> select * from hoegh;

  21.          X Y Z
  22. ---------- ---------- ----------
  23.          1 1 1
  24.          1 2 1
  25.          1 3 2

  26. SQL>
   到此,这个问题得到了圆满解决。大家如果有更好的方法欢迎不吝赐教。


                                                                                                                                                                                            ~~~~~~~ the end~~~~~~~~~
                                                                                                                                                                                                               hoegh
                                                                                                                                                                                                           2016.06.17

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30162081/viewspace-2120367/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30162081/viewspace-2120367/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值