Oracle数据库开发——表(数据完整性约束)

创建表时候,都要考虑到数据完整性,所以先提一下,数据完整性约束:
主键约束(primary key)、唯一性约束(unique)、检查约束(check)、外键约束(foreign key)、非空约束(not null)。

主键约束(primary key):主键可以确保一个表中没有重复的键值数据行。作为主键的列或者列的组合,其值必须唯一,且不能为NULL。
   一个表只能定义一个主键约束,同时Oracle Database自动为主键列建立一个唯一性索引,用户可以为该索引指定存储位置和存储参数。
   主键约束可以定义在列级,也可以定义在表级。
   由多列组成的主键叫做复合主键,一个复合主键中的列的数量不能超过32个。
   
唯一性约束(unique):确保列或列的组合具有唯一值(若没有非空约束,这个值是可以为空的),Oracle Database自动为主键列建立一个唯一性索引,用户可以为该索引指定存储位置和存储参数。
   唯一性约束可以定义在列级,也可以定义在表级。

检查约束(check):检查约束用来限制列的取值范围,实现对数据的自动检查。
  一个列可以定义多个检查约束,其表达式中必须引用相应的列,且表达式中不能包含子查询,SYSDATE/USER等SQL函数和ROWID、ROWNUM等伪劣。
  检查约束可以定义在列级或表级。
  
外键约束(foreign key):外键约束的定义使得数据库中表与表之间建立了父子关系。外键约束用来定义子表中列的取值只能是父表中参照列的值,或者为空。
  父表中被参照的列必须有唯一性约束或主键约束,外键约束可以定义在一列或多列组合上,可以定义在列级或表级。
  外键可以是自参照约束,即外键可以指向同一个表。

非空约束(not null):非空约束限制列的取值不能为NULL,一个表中可以定义多个非空约束。非空约束只能定义在列级。

例1:验证列主键系统自动创建唯一索引
创建一个订单表,订单号为主键:
create table tab_orders
( order_id varchar2(20) constraint O_PK primary key
,order_date date default sysdate
,qty integer
,payterms varchar2(12)
,goods_id number(6)
);

查看系统是否为主键列自动创建了唯一索引?

SQL> select t.index_name,t.index_type,t.table_name,t.uniqueness from user_indexes t where index_name = 'O_PK';
 
INDEX_NAME                     INDEX_TYPE                  TABLE_NAME                     UNIQUENESS
------------------------------ --------------------------- ------------------------------ ----------
O_PK                           NORMAL                      TAB_ORDERS                     UNIQUE
 
SQL> select x.constraint_name,x.constraint_type,x.index_name from user_constraints x where x.table_name = 'TAB_ORDERS';
 
CONSTRAINT_NAME                CONSTRAINT_TYPE INDEX_NAME
------------------------------ --------------- ------------------------------
O_PK                           P               O_PK 

结果显示系统自动创建了唯一索引。

例2: 表级主键——联合主键
上面一个是列级约束,那么表级约束是怎么建立的?
其实表级约束通常是针对多个列建立的约束,因此,表级约束的定义独立于列的定义。以( ,)形式
create table tab_bookauthors
(author_id varchar2(15)
,book_id number(6)
,author_ord number
,constraint BA_PK primary key (author_id,author_ord)
);

SQL> select t.index_name,t.index_type,t.table_name,t.uniqueness from user_indexes t where index_name = 'BA_PK';
 
INDEX_NAME                     INDEX_TYPE                  TABLE_NAME                     UNIQUENESS
------------------------------ --------------------------- ------------------------------ ----------
BA_PK                          NORMAL                      TAB_BOOKAUTHORS                UNIQUE
 
SQL> select x.constraint_name,x.constraint_type,x.index_name from user_constraints x where x.table_name = 'TAB_BOOKAUTHORS';
 
CONSTRAINT_NAME                CONSTRAINT_TYPE INDEX_NAME
------------------------------ --------------- ------------------------------
BA_PK                          P               BA_PK
 
SQL> select * from user_ind_columns z where z.INDEX_NAME = 'BA_PK';
 
INDEX_NAME                     TABLE_NAME                     COLUMN_NAME     COLUMN_POSITION COLUMN_LENGTH CHAR_LENGTH DESCEND
------------------------------ ------------------------------ --------------- --------------- ------------- ----------- -------
BA_PK                          TAB_BOOKAUTHORS                AUTHOR_ID                     1            15          15 ASC
BA_PK                          TAB_BOOKAUTHORS                AUTHOR_ORD                    2            22           0 ASC


中间休息了两天,下面继续...

约束的定义
约束的定义,约束可以在创建表的时候定义,也可以在表创建完整之后,单独添加。
create table中定义约束的语法:
定义列级约束:
create table [schema].table_name
(
column1 datatype [constraint constraint_name]
,column2 datatype [constraint constraint_name]
,...
);

带有定义表级约束的:
create table [schema].table_name
(
column1 datatype [constraint constraint_name]
,column2 datatype [constraint constraint_name]
,...
,[constraint constraint_name] constraint_type ([column1,column2,...]|[condition])
);

先创建表,然后添加约束
create table [schema].table_name(...);

alter table [schema].table_name add constraint constraint_name constraint_type (column1,column2)[condition];

个人感觉上先创建表,然后去添加更好一些,感觉比较清晰吧= =#。
习惯上,NOT NULL 、unique、 check 约束直接在创建表的时候定义,然后单独去定义主外键约束。
还是看看oracle是怎么保存的吧
例3:
create table demo1
(col1 varchar2(4) constraint DO1_PK primary key
,col2 varchar2(10) unique
,col3 number not null
)
;
create table demo2
(col1 varchar2(4)
,col2 varchar2(10) 
,col3 number not null
);
alter table demo2 add constraint DO2_PK primary key(col1);
alter table demo2 add constraint DO2_UI unique(col2); 

用PL/SQL查看建表语句
-- Create table
create table DEMO1
(
  COL1 VARCHAR2(4) not null,
  COL2 VARCHAR2(10),
  COL3 NUMBER not null
)
tablespace USERS
  pctfree 10
  initrans 1
  maxtrans 255;
-- Create/Recreate primary, unique and foreign key constraints 
alter table DEMO1
  add constraint DO1_PK primary key (COL1)
  using index 
  tablespace USERS
  pctfree 10
  initrans 2
  maxtrans 255;
alter table DEMO1
  add unique (COL2)
  using index 
  tablespace USERS
  pctfree 10
  initrans 2
  maxtrans 255;
================================================================== 
-- Create table
create table DEMO2
(
  COL1 VARCHAR2(4) not null,
  COL2 VARCHAR2(10),
  COL3 NUMBER not null
)
tablespace USERS
  pctfree 10
  initrans 1
  maxtrans 255;
-- Create/Recreate primary, unique and foreign key constraints 
alter table DEMO2
  add constraint DO2_PK primary key (COL1)
  using index 
  tablespace USERS
  pctfree 10
  initrans 2
  maxtrans 255;
alter table DEMO2
  add constraint DO2_UI unique (COL2)
  using index 
  tablespace USERS
  pctfree 10
  initrans 2
  maxtrans 255;
  
这里可以看到表demo1在PL/SQL里面保存的语句被拆分开了
在查看下用户视图
SQL> select x.table_name,x.constraint_name,x.constraint_type,x.index_name from user_constraints x where x.table_name in ('DEMO1','DEMO2');
 
TABLE_NAME                     CONSTRAINT_NAME                CONSTRAINT_TYPE INDEX_NAME
------------------------------ ------------------------------ --------------- ------------------------------
DEMO1                          SYS_C003893                    C               
DEMO1                          DO1_PK                         P               DO1_PK
DEMO1                          SYS_C003895                    U               SYS_C003895
DEMO2                          SYS_C003891                    C               
DEMO2                          DO2_PK                         P               DO2_PK
DEMO2                          DO2_UI                         U               DO2_UI

这里第二列SYS开头的是系统定义唯一标示名,因为用户没有定义约束名。最后一列SYS开头是索引名唯一标示名。

看到这里,我的感觉是虽然创建方式不同,但是oracle保存方式是相同的。
通常先create table,再alter add约束,用户会给约束起名字(constraint),需要系统创建唯一索引的约束,索引名与约束名相同。
直接创建的约束,有时候为了建表语句书写的简便(或者用户忽略忘记了),添加约束名,系统会默认分给约束一个唯一标示名,需要系统创建唯一索引的约束,索引名与约束名相同。
以上是个人观点,有不对的地方请指正。


添加约束
例4:
create table employees
(emp_id char(10)
,ename varchar2(20)
,job_id number(6)
,job_lv integer
,pub_id char(4)
,hiredate date
);
create table jobs
(jobid number(6) primary key
,jobname varchar2(20) not null
,minlvl integer
,maxlvl integer
);
--为employee的emp_id添加一个主键约束
alter table employees add constraint E_PK primary key(emp_id);

--为employee的job_id添加外键,参照表为jobs的job_id
alter table employees add constraint E_FK foreign key(job_id) references jobs(jobid) on delete cascade;

--为employee的ename添加非空约束
alter table employees modify ename constraint E_NN not null;

注意:当为表添加非空约束时,必须使用modify子句,而不是add子句。


删除约束
--删除employees的主键约束
alter table employees drop constraint E_PK;  --指定约束名删除约束

--也可以用
alter table employees drop primary key;    --指定约束内容删除约束

注意,删除主键约束、唯一约束的同时系统为自动删除对应的唯一性索引。如果想保留唯一性索引,可以使用keep index子句。
   alter table employees drop constraint E_PK keep index;
   如果主键被其他外键参照,可以使用cascade关键字指出删除主键约束的同时把参照该主键的外键一起删除。
alter table employees drop constraint E_PK cascade;

下面来验证
例5: 
接着例4,先查看EMPLOYEES,JOBS的约束视图
SQL> select x.table_name,x.constraint_name,x.constraint_type,x.index_name from user_constraints x where x.table_name in ('EMPLOYEES','JOBS');
 
TABLE_NAME                     CONSTRAINT_NAME                CONSTRAINT_TYPE INDEX_NAME
------------------------------ ------------------------------ --------------- ------------------------------
EMPLOYEES                      E_PK                           P               E_PK
EMPLOYEES                      E_FK                           R               
EMPLOYEES                      E_NN                           C               
JOBS                           SYS_C003897                    C               
JOBS                           SYS_C003898                    P               SYS_C003898


SQL> select z.table_name,z.index_type,z.table_name,z.uniqueness from user_indexes z where z.table_name in ('EMPLOYEES','JOBS');
 
TABLE_NAME                     INDEX_TYPE                  TABLE_NAME                     UNIQUENESS
------------------------------ --------------------------- ------------------------------ ----------
JOBS                           NORMAL                      JOBS                           UNIQUE
EMPLOYEES                      NORMAL                      EMPLOYEES                      UNIQUE


然后删除EMPLOYEES的主键
alter table employees drop constraint E_PK;

SQL> select x.table_name,x.constraint_name,x.constraint_type,x.index_name from user_constraints x where x.table_name in ('EMPLOYEES','JOBS');
 
TABLE_NAME                     CONSTRAINT_NAME                CONSTRAINT_TYPE INDEX_NAME
------------------------------ ------------------------------ --------------- ------------------------------
EMPLOYEES                      E_FK                           R               
EMPLOYEES                      E_NN                           C               
JOBS                           SYS_C003897                    C               
JOBS                           SYS_C003898                    P               SYS_C003898


SQL> select z.table_name,z.index_type,z.table_name,z.uniqueness from user_indexes z where z.table_name in ('EMPLOYEES','JOBS');
 
TABLE_NAME                     INDEX_TYPE                  TABLE_NAME                     UNIQUENESS
------------------------------ --------------------------- ------------------------------ ----------
JOBS                           NORMAL                      JOBS                           UNIQUE

结果可以看到constraint E_PK 对应的唯一索引被删除了。


下面删除jobs的主键jobid,表employees的外键参照该列
SQL> alter table jobs drop primary key cascade;
 
Table altered
 
SQL> select x.table_name,x.constraint_name,x.constraint_type,x.index_name from user_constraints x where x.table_name in ('EMPLOYEES','JOBS');
 
TABLE_NAME                     CONSTRAINT_NAME                CONSTRAINT_TYPE INDEX_NAME
------------------------------ ------------------------------ --------------- ------------------------------
EMPLOYEES                      E_NN                           C               
JOBS                           SYS_C003897                    C               
 
SQL> select z.table_name,z.index_type,z.table_name,z.uniqueness from user_indexes z where z.table_name in ('EMPLOYEES','JOBS');
 
TABLE_NAME                     INDEX_TYPE                  TABLE_NAME                     UNIQUENESS
------------------------------ --------------------------- ------------------------------ ----------

结果验证了,如果主键被其他外键参照,使用cascade关键字指出删除主键约束的同时把参照该主键的外键一起删除。

约束的状态和延迟检查

(1)约束的状态
Oracle数据库表中的约束出于激活状态,即约束对表的插入或更新操作进行检验,不符合约束的操作被回退。但是,实际工作中,我们有时候
需要将约束的状态置为禁用,这样可以提高效率。
使用 alter table ... disable ...语句

语法: alter table [schema.]table_name
                modify constraint constraint_name {enable|disable};
                
需要注意的几点:
1.禁用主键使用 alter table ... disable ... cascade;后面的cascade是为了防止主键被其他表引用为外键,而导致该主键约束无法禁用。
2.禁用primary key 和unique约束时,系统会将它们对应的唯一性索引删除,并且,在重新激活时,系统重新建立相应的唯一性索引。
 如果希望保留唯一性索引,可以在禁用时候,使用keep index子句。

(2)约束的检查状态
约束的激活和禁用状态只对设置状态后的数据操作起作用,要想对表中已存在的数据也进行约束检查,则必须结合"检查状态"——validate(检查)
和novaildate(非检查)。

语法:alter table [schema.]table_name
                modify constraint constraint_name validate|novalidate;

结合,激活 和 禁用:
组合一下
enable validate :激活检查状态,Oracle数据库默认的检查状态。对表所有都进行约束条件检查。
enable novalidate : 激活非检查状态,只对更新或新插入的数据进行约束检查,不对已存在数据进行约束检查。
disable validate :禁用检查状态,在该状态下Oralce数据库不允许用户进行更新或者插入操作。(因为约束已禁用却又要求检查,无法检查)
disable novalidate : 禁用非检查状态,不对数据进行约束检查。

(3)约束的延迟检查

立即约束检查 initially immediate: 默认为该选项,执行外一个DML语句后立即检验

延迟约束检查 initially deferred: 当 事务提交或调用set constraint immediate语句时才检验。


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

转载于:http://blog.itpub.net/28929558/viewspace-1144931/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值