Oracle笔记之约束

时间:2021-08-14 23:48:17

约束用于保证数据库中某些数据的完整性,给某一列添加一个约束可以保证不满足约束的数据是绝对不会被接受的。

约束主要有那么五种类型:非空约束、唯一约束、主键约束、外键约束、校验约束。

使用如下命令检索某个表上的所有约束(需要注意WHERE条件中的表名和用户名需要大写,不然检索不到):

SELECT *
FROM all_constraints
WHERE table_name = 'T_USER' AND owner = 'SCOTT';

结果如下:

SQL> SELECT *
2 FROM all_constraints
3 WHERE table_name = 'T_ORDER' AND owner = 'SCOTT';
OWNER CONSTRAINT_NAME CONSTRAINT_TYPE TABLE_NAME SEARCH_CONDITION R_OWNER R_CONSTRAINT_NAME DELETE_RULE STATUS DEFERRABLE DEFERRED VALIDATED GENERATED BAD RELY LAST_CHANGE INDEX_OWNER INDEX_NAME INVALID VIEW_RELATED
------------------------------ ------------------------------ --------------- ------------------------------ -------------------------------------------------------------------------------- ------------------------------ ------------------------------ ----------- -------- -------------- --------- ------------- -------------- --- ---- ----------- ------------------------------ ------------------------------ ------- --------------
SCOTT SYS_C005264 C T_ORDER "USER_ID" IS NOT NULL ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1
SCOTT SYS_C005266 R T_ORDER SCOTT SYS_C005258 NO ACTION ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1

对于上面的CONSTRAINT_NAME,如果在创建的时候不指定的话Oracle就会自动生成一个,自动生成的不能见名知义鬼知道什么意思...

对于上面的CONSTRAINT_TYPE:

C:校验约束,表

O:只读约束

P:主键约束

R:外键约束

U:唯一约束

V:校验约束,视图

使用下面这个命令查看列级别的约束:

SELECT * FROM user_cons_columns WHERE CONSTRAINT_NAME='FK_ORDER_USER';

列级约束定义:在定义列的时候定义的约束。

表级约束定义:在列定义完之后再定义的约束,注意这里并不一定是表创建完成之后,只要在列声明完事之后再声明的就算是表级定义。

列级的定义不能自己取约束名,Oracle会自动生成,自动生成的约束名类似这个样式的:SYS_C005271,一点也不友好啊,使用表级约束定义可以自己指定一个见名知义的约束名。

举个例子说明列级定义和表级定义:

列级定义主键:

CREATE TABLE t_user(
id INT PRIMARY KEY
);

表级定义主键:

CREATE TABLE t_user(
id INT ,
CONSTRAINT PK_USER_ID PRIMARY KEY (id)
);

约束的类型

非空约束(NOT NULL )

任何列都可以赋予一个NOT NULL约束,授予非空约束的列在插入数据的时候必须有数据,对于字符串类型的列,如果没有值可插入但是又有非空约束的话,那么传入一个空串即可,同理,对于数据类型的可以用0表示NULL,只要在业务上别有歧义。

设置非空约束是很有必要的,比如对于一些经常在WHERE条件中用到的被检索的字段如果有NULL的话就不能使用索引了。

创建表的时候指定非空约束:

CREATE TABLE t_user(
id INT PRIMARY KEY ,
username VARCHAR2(50) NOT NULL
);

查看t_user表中的约束:

SQL> SELECT *
2 FROM all_constraints
3 WHERE table_name = 'T_ORDER' AND owner = 'SCOTT';
OWNER CONSTRAINT_NAME CONSTRAINT_TYPE TABLE_NAME SEARCH_CONDITION R_OWNER R_CONSTRAINT_NAME DELETE_RULE STATUS DEFERRABLE DEFERRED VALIDATED GENERATED BAD RELY LAST_CHANGE INDEX_OWNER INDEX_NAME INVALID VIEW_RELATED
------------------------------ ------------------------------ --------------- ------------------------------ -------------------------------------------------------------------------------- ------------------------------ ------------------------------ ----------- -------- -------------- --------- ------------- -------------- --- ---- ----------- ------------------------------ ------------------------------ ------- --------------
SCOTT SYS_C005271 C T_ORDER "USERNAME" IS NOT NULL ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1
SCOTT SYS_C005272 P T_ORDER ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1 SYS_C005272

一个C非空约束,一个P主键约束,为啥是C呢,因为这样啊:

username VARCHAR2(50) NOT NULL == username VARCHAR2(50) CHECK(username IS NOT NULL)

NOT NULL实际上就相当于添加了一个IS NOT NULL的CHECK。

表创建完毕再增加非空约束:

ALTER TABLE t_user MODIFY username NOT NULL;

删除非空约束:

ALTER TABLE t_user MODIFY username NULL;

唯一约束(UNIQUE)

如果将某个列设置为唯一,那么列中每行的数据不能重复,虽然不能重复,但是可以为null。

创建表的时候指定唯一约束:

CREATE TABLE t_user(
id INT PRIMARY KEY ,
username VARCHAR2(50) ,
email VARCHAR2(255) UNIQUE
);

查看t_user上的约束:

SQL> SELECT *
2 FROM all_constraints
3 WHERE table_name = 'T_USER' AND owner = 'SCOTT';
OWNER CONSTRAINT_NAME CONSTRAINT_TYPE TABLE_NAME SEARCH_CONDITION R_OWNER R_CONSTRAINT_NAME DELETE_RULE STATUS DEFERRABLE DEFERRED VALIDATED GENERATED BAD RELY LAST_CHANGE INDEX_OWNER INDEX_NAME INVALID VIEW_RELATED
------------------------------ ------------------------------ --------------- ------------------------------ -------------------------------------------------------------------------------- ------------------------------ ------------------------------ ----------- -------- -------------- --------- ------------- -------------- --- ---- ----------- ------------------------------ ------------------------------ ------- --------------
SCOTT SYS_C005280 U T_USER ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 2 SYS_C005280
SCOTT SYS_C005279 P T_USER ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 2 SYS_C005279

一个唯一约束,一个主键约束。

在创建完表之后再添加唯一约束:

ALTER TABLE t_user ADD CONSTRAINT U_EMAIL UNIQUE(email); 

添加多列唯一约束,多个列的值不重复即可:

ALTER TABLE emp ADD CONSTRAINT U_ENAME_JOB UNIQUE(ename, job);

删除表中的唯一约束:

ALTER TABLE t_user DROP CONSTRAINT SYS_C005280;

主键约束(PRIMARY KEY)

1. 主键列是非空且唯一的,相当于NOT NULL+UNIQUE

2. 每个表中最多可以有一个主键约束。

3. 主键约束可以由表中的一个列或多个列组成,多个列的话称之为复合主键。

4. 主键属于表对象,所以主键有一个对象,若没有给主键指定名字,Oracle会自动分配一个唯一的名字

创建表的时候指定主键:

CREATE TABLE t_user(
id INT PRIMARY KEY
);

创建复合主键:

CREATE TABLE t_user(
id INT ,
business_id INT ,
CONSTRAINT PK_USER PRIMARY KEY (id, business_id)
);

注意复合主键只能使用表级约束定义,因为没有办法在一个列上使用两个列啊...

表创建完成之后再指定主键:

ALTER TABLE t_user
ADD CONSTRAINT PK_USER_ID PRIMARY KEY(id);

删除主键:

ALTER TABLE t_user DROP PRIMARY KEY;

在删除主键的时候可能会有错误,比如某张表的主键已经是别的表的外键了,那么尝试删除父表的时候就会报错。

来建立一个主外键关系:

DROP TABLE t_user;
CREATE TABLE t_user(
id INT PRIMARY KEY
); DROP TABLE t_order;
CREATE TABLE t_order(
id INT PRIMARY KEY ,
user_id INT REFERENCES t_user(id)
);

t_order已经有一个外键指向了t_user的主键,尝试删除t_user的主键:

SQL> ALTER TABLE t_user DROP PRIMARY KEY;
ALTER TABLE t_user DROP PRIMARY KEY
ORA-02273: 此唯一/主键已被某些外键引用

正确的姿势上加上CASCADE,表示将外键主从关系一并删除掉:

ALTER TABLE t_user DROP PRIMARY KEY CASCADE;

再查看t_order表的约束关系:

SQL> SELECT *
2 FROM all_constraints
3 WHERE table_name = 'T_ORDER' AND owner = 'SCOTT';
OWNER CONSTRAINT_NAME CONSTRAINT_TYPE TABLE_NAME SEARCH_CONDITION R_OWNER R_CONSTRAINT_NAME DELETE_RULE STATUS DEFERRABLE DEFERRED VALIDATED GENERATED BAD RELY LAST_CHANGE INDEX_OWNER INDEX_NAME INVALID VIEW_RELATED
------------------------------ ------------------------------ --------------- ------------------------------ -------------------------------------------------------------------------------- ------------------------------ ------------------------------ ----------- -------- -------------- --------- ------------- -------------- --- ---- ----------- ------------------------------ ------------------------------ ------- --------------
SCOTT SYS_C005284 P T_ORDER ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 2 SYS_C005284

只剩下一个主键约束了,外键约束已经被删除掉了。

外键约束(FOREIGN KEY)

1. 外键约束是为数据库中某个与其它表有关系的表而定义的。

2. 外键的值必须先出现在某个特定表的主键列或者有唯一约束的列中。

3. 外检的列可以包含NULL。

4. 一个表中外键可以有多个。

先创建一个用户表:

CREATE TABLE t_user(
id INT PRIMARY KEY ,
name VARCHAR2(50) NOT NULL
);

再创建一个订单表,链接到订单表:

CREATE TABLE t_order(
id INT PRIMARY KEY ,
user_id INT REFERENCES t_user(id) NOT NULL
);

查看t_order表的约束:

SQL> SELECT *
2 FROM all_constraints
3 WHERE table_name = 'T_ORDER' AND owner = 'SCOTT';
OWNER CONSTRAINT_NAME CONSTRAINT_TYPE TABLE_NAME SEARCH_CONDITION R_OWNER R_CONSTRAINT_NAME DELETE_RULE STATUS DEFERRABLE DEFERRED VALIDATED GENERATED BAD RELY LAST_CHANGE INDEX_OWNER INDEX_NAME INVALID VIEW_RELATED
------------------------------ ------------------------------ --------------- ------------------------------ -------------------------------------------------------------------------------- ------------------------------ ------------------------------ ----------- -------- -------------- --------- ------------- -------------- --- ---- ----------- ------------------------------ ------------------------------ ------- --------------
SCOTT SYS_C005268 P T_ORDER ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1 SYS_C005268
SCOTT SYS_C005267 C T_ORDER "USER_ID" IS NOT NULL ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1
SCOTT SYS_C005269 R T_ORDER SCOTT SYS_C005258 NO ACTION ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1

可以看到有三个约束,一个是主键,一个是外键,一个是外键列的非空。

对于已经创建完成的表,需要添加外键应该怎么办呢。

先删除上面t_order的外键约束:

ALTER TABLE t_order DROP CONSTRAINT SYS_C005269;

需要注意删除约束的时候需要传入约束的名字,对于自动生成的可以先去查询出然后再删除。

现在t_order表就俩约束了:

SQL> SELECT *
2 FROM all_constraints
3 WHERE table_name = 'T_ORDER' AND owner = 'SCOTT';
OWNER CONSTRAINT_NAME CONSTRAINT_TYPE TABLE_NAME SEARCH_CONDITION R_OWNER R_CONSTRAINT_NAME DELETE_RULE STATUS DEFERRABLE DEFERRED VALIDATED GENERATED BAD RELY LAST_CHANGE INDEX_OWNER INDEX_NAME INVALID VIEW_RELATED
------------------------------ ------------------------------ --------------- ------------------------------ -------------------------------------------------------------------------------- ------------------------------ ------------------------------ ----------- -------- -------------- --------- ------------- -------------- --- ---- ----------- ------------------------------ ------------------------------ ------- --------------
SCOTT SYS_C005268 P T_ORDER ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1 SYS_C005268
SCOTT SYS_C005267 C T_ORDER "USER_ID" IS NOT NULL ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1

来为其重新把外键约束添加上:

ALTER TABLE t_order
ADD CONSTRAINT FK_ORDER_USER FOREIGN KEY (user_id) REFERENCES t_user;

外键约束已添加上:

SQL> SELECT *
2 FROM all_constraints
3 WHERE table_name = 'T_ORDER' AND owner = 'SCOTT';
OWNER CONSTRAINT_NAME CONSTRAINT_TYPE TABLE_NAME SEARCH_CONDITION R_OWNER R_CONSTRAINT_NAME DELETE_RULE STATUS DEFERRABLE DEFERRED VALIDATED GENERATED BAD RELY LAST_CHANGE INDEX_OWNER INDEX_NAME INVALID VIEW_RELATED
------------------------------ ------------------------------ --------------- ------------------------------ -------------------------------------------------------------------------------- ------------------------------ ------------------------------ ----------- -------- -------------- --------- ------------- -------------- --- ---- ----------- ------------------------------ ------------------------------ ------- --------------
SCOTT SYS_C005268 P T_ORDER ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1 SYS_C005268
SCOTT SYS_C005267 C T_ORDER "USER_ID" IS NOT NULL ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED GENERATED NAME 2017/6/15 1
SCOTT FK_ORDER_USER R T_ORDER SCOTT SYS_C005258 NO ACTION ENABLED NOT DEFERRABLE IMMEDIATE VALIDATED USER NAME 2017/6/15 1

校验约束(CHECK)

校验约束是一个布尔表达式,它的返回值是TRUE或者FALSE。

校验用于检查插入的数据是否合法,是“最后一层防线”(事实上还可以用触发器实现最后防线,即在插入数据后触发一个校验动作,不合法的话就抹掉它再报错)。

创建一个用户表:

CREATE TABLE t_user(
id INT PRIMARY KEY ,
name VARCHAR2(50) NOT NULL ,
age INT NOT NULL
);

为age字段添加一个检查约束:

ALTER TABLE t_user
ADD CONSTRAINT T_STUDENT_AGE_CHECK CHECK(age>=0 AND age<=100);

当然更优雅的写法是使用BETWEEN...AND...:

ALTER TABLE t_user
ADD CONSTRAINT T_STUDENT_AGE_CHECK CHECK(age BETWEEN 0 AND 100);

在WHERE中可以使用的,在CHECK表达式中都可以使用的。

创建表的时候添加校验约束:

CREATE TABLE t_user(
id INT PRIMARY KEY ,
name VARCHAR2(50) ,
age INT CHECK(age BETWEEN 0 AND 128)
);

表创建完毕添加校验约束:

ALTER TABLE t_user
ADD CONSTRAINT T_STUDENT_AGE_CHECK CHECK(age BETWEEN 0 AND 100);

删除校验约束:

ALTER TABLE t_user DROP CONSTRAINT T_STUDENT_AGE_CHECK ;

.