Oracle-约束

目录

  • 我们为什么需要约束?
  • 约束分类
    • NOT NULL
    • UNIQUE
      • 联合唯一约束
    • PRIMARY KEY
    • FOREIGN KEY
    • CHECK
    • DEFAULT
  • 约束的增、删
    • 增加约束
    • 删除约束

我们为什么需要约束?

  我们在设计数据库时,每张表、每一列,都会给它明确的定义并规划了用途。但设计时我们规划好了,使用时就是喜欢有人捣乱,胡乱写一些不符合最初设计目的数据进来,该怎么避免呢?。就比如我们往学生考试成绩表中写s_id字段时,写一个学生信息表中不存在的学生s_id编号进来,也是可以成功写入的,但这并不符合我们的预期。

  如何才能保证数据的完整性及可靠性呢?按照一般的控制手法(类比初中时学的如何消除噪音),我一时间大概可以想到三种:

  • 1.消灭不合规数据的源头,即在写入前就先进行判断数据是否合规,在java等用来写入数据库的语言中进行判断,或者更前的页面中用js等进行判断。
  • 2.消灭不合规数据的写入路径,即在写入的过程中进行判断,不合规的不准写入。
  • 3.已写入后进行检查,不合规数据已经写入数据库了,那么就在数据端定时进行数据检查(job+存储过程),发现并处理不合规数据。

  SQL中的约束,则是第二种方式,在写入过程中进行判断。

约束分类

  SQL中的约束是针对字段级别来进行限制的,可以在创建表的同时进行字段的约束声明,或者在表创建后补上约束。需要注意的是,如果创建后已有不符合想要加上的约束的数据,则无法直接添加约束,需处理掉这部分数据后再添加约束。

  常用SQL的约束主要有以下六类:

关键词 作用
NOT NULL 非空约束
UNIQUE 唯一值约束
PRIMARY KEY 主键约束
FOREIGN KEY 外键约束
CHECK 检查约束
DEFAULT 默认值约束

  看了命名和简单描述应该就大致知道它的作用了,接下来详细介绍下。

NOT NULL

  NOT NULL,见名知意,就是该字段不能为null空值,如果在写入数据时没用给该字段赋值,则无法写入。以学生信息表为例,设置classes字段不能为空:

  create table t_student
  (s_id number,
  name  varchar2(20) ,
  age   number,
  gender varchar2(10),
  classes varchar2(5) not null   -- not null,非空
  );

  往该表中插入数据时,如果未给classes指定值或值为空,均不准插入,会提示ORA-01400错误:

	--未指定值
	insert into t_student(s_id,name,age,gender) values(1,'小虎',20,'male');
	--指定值为null
  	insert into t_student(s_id,name,age,gender,classes) values(1,'小虎',20,'male',null);

  约束的影响这么大,分分钟给报错的,每个约束没有自己的名字岂不是很没排面?来,给整上,用constraint来指定约束名:

  create table t_student
  (s_id number,
  name  varchar2(20) ,
  age   number,
  gender varchar2(10),
  classes varchar2(5) constraint nn_student_classes not null   
  );

  约束名也有命名规范,具体看每个公司的要求,清晰的约束名可以在报错时快速定位到问题点,nn_student_classes就代表:非空+表明+字段。

UNIQUE

  唯一约束,用来限制该列的值只能出现一次,如果其他行中的这一列,存在值相同的列,则不允许本次的插入或修改。学生信息表中的学生ID编号就应该是这样的,那么:

  create table t_student
  (s_id number constraint UN_student_id unique,
  name  varchar2(20) ,
  age   number,
  gender varchar2(10),
  classes varchar2(5) constraint NN_student_classes not null
  );

  有了唯一约束后,如果我们插入两条id相同的数据,则第二条无法插入成功,会报错ORA-00001:unqiue constraint(UN_student_id),我们通过约束名UN_student_id就可以很快定位到问题点:

	--第一条数据插入成功
  	insert into t_student(s_id,name,age,gender,classes) values(1,'小虎',20,'male','A');
  	--第二条数据s_id相同,插入失败
  	insert into t_student(s_id,name,age,gender,classes) values(1,'小猪',18,'male','A');

  除了insert,在进行更新update时也需要遵守约束条件,如果新值已存在,则无法更新。

  我们也可以在表声明的末尾来声明约束(NOT NULL约束不支持):

  create table t_student
  (s_id number ,
  name  varchar2(20) ,
  age   number,
  gender varchar2(10),
  classes varchar2(5) constraint NN_student_classes not null,
  constraint UN_student_id unique (s_id)
  );

  需要注意的是,如果我们分别s_id和name创建唯一约束,应该写为:

  create table t_student
  (s_id number ,
  name  varchar(20) ,
  age   number,
  gender varchar(10),
  classes varchar(5) constraint NN_student_classes not null,
  constraint UN_student_id unique (s_id),
  constraint UN_student_name unique (name)
  );

联合唯一约束

  如果我们同时s_id和name创建唯一约束,则表示是一个联合唯一约束:

  create table t_student
  (s_id number ,
  name  varchar2(20) ,
  age   number,
  gender varchar2(10),
  classes varchar2(5) constraint NN_student_classes not null,
  constraint UN_student_id_name unique (s_id,name)
  );

  联合唯一约束的意思是:被约束的所有列的值同时存在,才不满足该约束,只要有一个列的值尚未存在,即可正常操作。如果我们插入两条数据,第一条id为1,name为“小虎”,第二条id依旧为1,只要name有变化,依旧是可以插入的:

	--第一条数据插入成功
  	insert into t_student(s_id,name,age,gender,classes) values(1,'小虎',20,'male','A');
  	--第二条数据s_id相同,但name不同,依旧插入成功
  	insert into t_student(s_id,name,age,gender,classes) values(1,'小猪',18,'male','A');

  这样的结果明显不符合我们该表设计的初衷,所以在建表时需要注意别偷懒,该写两行的就得写两行。

  联合唯一约束使用于单个字段无法确定唯一性,多个字段(可以不止两个哦)联合起来看才是唯一的情况,实际开发中比较少见。

PRIMARY KEY

  主键约束,基本上每张表设计时都需要一个主键,即常说的id,一张表中只能有一个主键。可以将主键约束看作:NOT NULL + UNIQUE + 主键索引。主键必须是非空且唯一的,并且oracle会对主键列创建创建一个索引。

  create table t_student
  (s_id number ,
  name  varchar2(20) constraint NN_student_name not null,
  age   number,
  gender varchar2(10),
  classes varchar2(5) constraint NN_student_classes not null,
  constraint PK_student_id primary key (s_id)
  );

  一张表中只能有一个主键。如果同时写了多个字段,那么是创建了一个联合主键,与联合唯一约束效果类似。

FOREIGN KEY

  外键约束,名字看上去与主键约束类似,但作用却大不相同。

  当我们有多张表,且表之间有关联时,可以使用外键约束来限制数据的值。如:学生分数表的学生id字段,就必须在学生信息表中存在对应id,我们可以通过references来在列明后直接声明约束:

  create table t_score
  (s_id number references t_student(s_id),
  score number,
  course varchar2(20)
  );

  更推荐的还是在表后使用constraint关键字的方式:

  create table t_score
  (s_id number,
  score number,
  course varchar2(20),
  constraint FK_score_id foreign key (s_id) references t_student(s_id)
  );

  如果t_student表中只有两条学生记录,s_id分别为1和2,则:

	--外键列在父列中有对应值,则插入成功
    insert into t_score(s_id,score,course) values(1,98,'语文');
    insert into t_score(s_id,score,course) values(2,88,'语文');
    --外键列在父列中无对应值,则插入失败
    insert into t_score(s_id,score,course) values(3,95,'语文');

  通过外键约束,则可以保证子表的值父表中一定存在,数据完整性得以保障。

  但是,并不建议在实际开发过程中过多使用外键约束,特别是数据库表结构错综复杂的系统。如果存在一层一层的外键约束,那么对父表进行操作时,往往由于子表的约束而导致不能操作。我们更偏向于采用方法一:在写入时判断,来对这种约束情况进行控制。

CHECK

  检查约束,用于限制列的值在规定范围以内。开发过程中也不太会使用这种约束,更多的是通过代码逻辑来判断。

  以检查学生信息表的age年龄在0到150岁之间,为例:

  create table t_student
  (s_id number ,
  name  varchar2(20) constraint NN_student_name not null,
  age   number,
  gender varchar2(10),
  classes varchar2(5) constraint NN_student_classes not null,
  constraint PK_student_id primary key (s_id),
  constraint CK_student_age check(age between 0 and 150)
  );

  在插入或更新age时,若不符合CK_student_age约束范围,则无法更改操作。

DEFAULT

  DEFAULT约束用于向列中插入默认值,如果没有指明具体的值,那么会将默认值添加到所有的新记录。

  例如,如果不给出具体值,我们默认学生性别为男性:

  create table t_student
  (s_id number ,
  name  varchar2(20) constraint NN_student_name not null,
  age   number,
  gender varchar2(10) default 'male', --默认值
  classes varchar2(5) constraint NN_student_classes not null,
  constraint PK_student_id primary key (s_id)
  );

  及时当插入数据时未指定gender的值,也会自动补为’male’。

约束的增、删

  在表创建后,也可以继续对表的字段增加或删除约束。

增加约束

  通过ALTER TABLE并ADD方式,增加约束:

ALTER TABLE t_student
ADD CONSTRAINT un_student_id UNIQUE(s_id);

  需要注意的是,同一数据库中的约束名不能重名哦。

删除约束

  通过ALTER TABLE并DROP方式,删除约束:

ALTER TABLE t_student
DROP CONSTRAINT un_student_id;

  确保被约束名在数据库中存在哦。

你可能感兴趣的:(数据库)