约束

本文详细介绍了数据库中的五种约束:非空约束、唯一约束、主键约束、检查约束和外键约束,包括各自的定义、作用及如何在实际操作中应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  在数据库之中,约束是保护数据完整性的一种手段,所有的数据在进行更新的时候,都要进行约束的判断,如果符合约束的要求,则可以执行具体的更新操作,反之会出现错误。例如:如果说现在在表中的字段是NUMBER,但是执行的时候数据设置成了VARCHAR2,那么肯定无法保存,所以这本身就是一种约束,而比较注重的约束有五种:非空约束、唯一约束、主键约束、检查约束、外键约束。

1.1、非空约束(NOT NULL,NK)

  所谓的非空约束指的是表中某一个字段的内容不允许设置为NULL,如果要定义这样的约束,只需要在定义数据表字段的后面增加一个“NOT NULL”即可。

DROP TABLE member PURGE ;
CREATE TABLE member(
    mid     NUMBER      ,
    name        VARCHAR2(20)    NOT NULL
) ;

范例:增加正确的数据

INSERT INTO member(mid,name) VALUES(1,'张三') ;

范例:插入错误的数据

INSERT INTO member(mid) VALUES(1) ;

  此时由于没有设置name内容,所以程序会出现“ORA-01400: 无法将 NULL 插入 (“SCOTT”.”MEMBER”.”NAME”)”错误提示信息。
这里写图片描述


1.2、唯一约束(UNIQUE,UK)

  唯一约束指的是表中某一个列上的数据不允许出现重复,例如:如果现在做一张用户信息的统计表,那么每一个用户的email地址是绝对不应该重复的,所以在此情况下就可以利用UNIQUE加以定义,表示唯一的,不可重复的列。
  

DROP TABLE member PURGE ;
CREATE TABLE member(
    mid     NUMBER      ,
    name        VARCHAR2(20)    NOT NULL ,
    email       VARCHAR2(20)    UNIQUE
) ;

  发现在email字段上增加了唯一约束的限制,那么下面同样分别插入正确以及错误的数据来观察。

范例:插入正确的数据

INSERT INTO member(mid,name,email) VALUES(1,'张三','mldn@163.com') ;
INSERT INTO member(mid,name,email) VALUES(2,'李四',null) ;

  唯一约束本身并不包含对NULL的限定。

范例:插入错误的数据

INSERT INTO member(mid,name,email) VALUES(3,'王五','mldn@163.com') ;

  此时由于email数据重复,所以执行时出现了以下的错误提示“ORA-00001: 违反唯一约束条件 (SCOTT.SYS_C0010818)”。但是,可以发现,此时出现的错误提示信息,并不像最早非空约束那样提示完整。
  首先对于每一种约束而言,在Oracle中都是以数据库对象的形式保存的,那么每一个数据库对象在进行保存时都一定需要设置一个名称,这些名称都要在相应的数据字典上保存。用户可以直接查看“user_cons_columns”数据字典查看每一个约束名称到底在那张表的那个列上使用。

COL owner FOR A15 ;
COL constraint_name FOR A15 ;
COL table_name FOR A15 ;
COL column_name FOR A15 ;
SELECT owner,constraint_name,table_name,column_name FROM user_cons_columns ;

  用户不可能根据错误的提示约束名称再去查找数据字典表而后再找到错误的列是那一个,用户应该想办法可以直接设置一个名字,并且这个名字也设置的更加有意义一些,这样就可以直接进行具体那个字段上的错误提示了。所以在Oracle之中,一般约束的名称都会采用“约束类型简写_字段”的方式命名,例如:唯一约束简称UK,如果在email字段上设置的唯一约束,那么约束的名称就是“UK_EMAIL”,这样一来,一旦出现了错误,可以立刻知道那里有错误。如果要想为约束设置名字,则在定义的时候需要使用CONSTRAINT进行指定。

范例: 为约束设置名字

CREATE TABLE member(
    mid NUMBER  ,
    name    VARCHAR(2) NOT NULL,
    email   VARCHAR(2),
    CONSTRAINT uk_email UNIQUE(email)
);

  随后同样执行出现违反约束的操作,出现的错误提示“ORA-00001: 违反唯一约束条件 (SCOTT.UK_EMAIL)”。


1.3、主键约束(PRIMARY KEY,PK)

  主键约束 = 非空约束 + 唯一约束,是两种约束的一集合。即:某些字段不能重复而且不能为空,例如:人员的唯一编号,或者是每一个中国公民的身份证号。

范例: 定义主键约束

DROP TABLE member PURGE ;
CREATE TABLE member(
    mid     NUMBER      PRIMARY KEY ,
    name        VARCHAR2(20)    NOT NULL 
) ;

范例: 插入错误数据,同一个 mid 设置两次 – INSERT INTO member(mid,name) VALUES(1,’张三’);

INSERT INTO member(mid,name) VALUES(1,'张三');

范例: 插入错误的数据,设置为 NULL – ORA-01400: 无法将 NULL 插入 (“SCOTT”.”MEMBER”.”MID”)

INSERT INTO member(mid,name) VALUES(null,'张三');

  但是直接在字段后面设置的唯一约束一定是没有名字的,而且可以范县并没有专门的主键错误的提示信息,而是用的其他两种约束的提示信息,那么现在就算定义了名字,实际上也是定义的唯一约束的名字,但是毕竟这个是主键约束,所以其约束类型简写还应该是 PK。

范例: 定义约束名称

DROP TABLE member PURGE;
CREATE TABLE member(
    mid NUMBER  ,
    name    VARCHAR(20) NOT NULL,
    CONSTRAINT pk_mid PRIMARY KEY(mid)
);

  此时,如果设置的主键信息重复,则会出现 ORA-00001: 违反唯一约束条件 (SCOTT.PK_MID) 错误提示。
  但是从一般开发来讲,每一张实体表(类似于emp或dept)一般都会存在一个主键,但是也会有一些人会将多个字段同时设置为主键,那么这种情况称为复合主键。

DROP TABLE member PURGE ;
CREATE TABLE member(
    mid     NUMBER      ,
    name        VARCHAR2(20)    ,
    CONSTRAINT pk_mid_name PRIMARY KEY (mid,name)
) ;

  此时的代码将mid和name全部都设置为主键,只有到mid和name的数据全部相同的时候,才表示违反了唯一约束,所以以下的数据都是正确的。
范例: 正确的数据

INSERT INTO member(mid,name) VALUES(1,'张三') ;
INSERT INTO member(mid,name) VALUES(2,'张三') ;
INSERT INTO member(mid,name) VALUES(1,'李四') ;

  一般正常的设计人员都不会这样定义,所以以后看见的时候,可以从你的心里的深处深深的发出一种鄙视。


1.4、检查约束(CHECK,CK)

  检查约束非常的好理解,就是设置一系列的过滤条件,满足此条件,则数据可以更新,例如:设置性别的时候,可以是男、女、中,例如:设置年龄的时候,每个人的年龄范围是0~250。如果要设置检查约束,直接利用CHECK即可。

范例:定义检查约束

DROP TABLE member PURGE ;
CREATE TABLE member(
    mid     NUMBER      ,
    name    VARCHAR2(20)    NOT NULL,
    sex     VARCHAR2(10) ,
    age     NUMBER(3)   CHECK (age BETWEEN 0 AND 250) ,
    CONSTRAINT pk_mid PRIMARY KEY (mid) ,
    CONSTRAINT ck_sex CHECK (sex IN ('男','女')) 
) ;

范例:增加错误的年龄 – ORA-02290: 违反检查约束条件 (SCOTT.SYS_C0010830)

INSERT INTO member(mid,name,sex,age) VALUES(1,'张三','男',888) ;

范例:增加错误的性别 —— ORA-02290: 违反检查约束条件 (SCOTT.CK_SEX)

INSERT INTO member(mid,name,sex,age) VALUES(1,'张三','不男非女',10) ;

  如果在数据表之中设置了过多的检查约束,那么会直接影响到数据库的性能,所以一般可以把这些检查约束的操作交给程序去完成。

1.5、外键约束(FOREIGN KEY,FK)

 
  外键约束与其他的四类约束不同,他是在两张数据表上设置的约束,进行子表与父表数据统一有效的连接而定义的。下面首先通过一个具体的程序,来研究一下外键约束之所以会存在的原因。
  例如:现在要求设计数据表,可以实现每一个学生(编号,姓名)有多本书(编号、名称、价格)的数据保存,这个时候数据库创建脚本该如何去定义?

DROP TABLE student PURGE;
DROP TABLE book PURGE;
CREATE TABLE student(
    stuid NUMBER,
    name VARCHAR2(50) NOT NULL,
    CONSTRAINT pk_stuid PRIMARY KEY(stuid)
);
CREATE TABLE book(
    bid NUMBER,
    title VARCHAR2(50) NOT NULL,
    stuid NUMBER
);

范例:定义一些正确的数据

INSERT INTO student(stuid,name) VALUES(1,'张三') ;
INSERT INTO student(stuid,name) VALUES(2,'李四') ;
INSERT INTO book(bid,title,price,stuid) VALUES(1001,'Java',89,1) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1002,'JSP',79,1) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1003,'Android',99,1) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1101,'Oracle',59,2) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1102,'MySQL',19,2) ;

范例:统计出每一个学生所拥有的书的数量以及所花费的购买图书的资金总和。

SELECT s.stuid,s.name,COUNT(b.bid),SUM(b.price)
FROM student s,book b
WHERE s.stuid=b.stuid
GROUP BY s.stuid,s.name;

  但是这个时候由于缺少约束的限制,那么以下的错误数据也有可能增加。
范例:错误数据

INSERT INTO book(bid,title,price,stuid) VALUES(2101,'小学数学',1,9) ;
INSERT INTO book(bid,title,price,stuid) VALUES(2102,'中学数学',2,8) ;

  在学生表中,现在并没有编号为8或9的学生信息,所以以上的两条数据一定是错误的数据,但是由于此时缺少里约束的保护,所以这个数据是可以保存的,但明显是不应该保存。最为合理的做法是:让book表中stuid字段取值范围由student表中的 stuid 来决定。即: 子表(book)中的某个字段的取值范围由父表(student)来决定。
范例:设置外键约束

DROP TABLE student PURGE;
DROP TABLE book PURGE;
CREATE TABLE student(
    stuid NUMBER,
    name VARCHAR2(50) NOT NULL,
    CONSTRAINT pk_stuid PRIMARY KEY(stuid)
);
CREATE TABLE book(
    bid NUMBER,
    title VARCHAR(50) NOT NULL,
    price NUMBER NOT NULL,
    stuid NUMBER, 
    CONSTRAINT fk_stuid FOREIGN KEY(stuid) REFERENCES student(stuid)
);

  此时由于设置了外键约束,这样 book.stuid 在进行内容设置的时候就必须参考 student.stuid 字段的定义范围,如果设置的数据不再此范围之中存在,就会出现 “ORA-02291: 违反完整约束条件(SCOTT.FK_STUID) - 未找到父类关键字” 错误提示信息。
  但是,一旦程序之中存在了外键约束之后,就会带来一系列的操作问题:
问题一:如果现在现在存在了外键约束,在删除父类之前,一定要首先删除掉其对应的子表,否则无法删除

DROP TABLE book PURGE;
DROP TABLE student PURGE;

  但是这种操作本身就会存在一个问题,如果假设是一个你所不熟悉的数据库,并且某张父表与其他的多张子表都存在外间联系,这个时候就很难立刻的区分出子表和父表,也很难立刻删除,为此提供了一个强制的删除操作。
范例:强制删除表,不关心子表

DROP TABLE student CASCADE CONSTRAINT;

  如果从开发来讲,还是建议大家考虑先后顺序,而不是这种不管不顾的删除方式。
  
问题二:设置为外键的字段,在主表之中必须设置主键或唯一约束

问题三:删除主表的数据之前,必须保证对应的子表删除掉,否则无法删除
  之所以会有这样的所发,主要的目的是为了保护数据的关联,但是很多时候可能不需要这样的关联。为此在 SQL 语法之中定义了两个数据的级联操作:
  · 级联都数据删除:级,删除主表数据的同时,对应的所有的子表的数据一起被删除掉。

范例:设置级联删除

DROP TABLE book PURGE;
DROP TABLE student PURGE;
CREATE TABLE student(
    stuid NUMBER ,
    name VARCHAR2(50) NOT NULL ,
    CONSTRAINT pk_stuid PRIMARY KEY(stuid)
);
CREATE TABLE book(
    bid NUMBER ,
    title VARCHAR2(50) NOT NULL ,
    price NUMBER NOT NULL ,
    stuid NUMBER ,
    CONSTRAINT fk_stuid FOREIGN KEY(stuid) REFERENCES student(stuid) ON DELETE CASCADE
);
INSERT INTO student(stuid,name) VALUES(1,'张三') ;
INSERT INTO student(stuid,name) VALUES(2,'李四') ;
INSERT INTO book(bid,title,price,stuid) VALUES(1001,'Java',89,1) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1002,'JSP',79,1) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1003,'Android',99,1) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1101,'Oracle',59,2) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1102,'MySQL',19,2) ;

  · 级联设置 NULL:当主表之中的数据被删除之后,对应的子表数据中的外键字段全部设置为 NULL。

DROP TABLE book PURGE ;
DROP TABLE student PURGE ;
CREATE TABLE student(
    stuid       NUMBER ,
    name        VARCHAR2(50)    NOT NULL ,
    CONSTRAINT pk_stuid PRIMARY KEY (stuid)
) ;
CREATE TABLE book(
    bid     NUMBER ,
    title       VARCHAR2(50)    NOT NULL ,
    price       NUMBER      NOT NULL ,
    stuid       NUMBER ,
    CONSTRAINT fk_stuid FOREIGN KEY(stuid) REFERENCES student(stuid) ON DELETE SET NULL
) ;
INSERT INTO student(stuid,name) VALUES(1,'张三') ;
INSERT INTO student(stuid,name) VALUES(2,'李四') ;
INSERT INTO book(bid,title,price,stuid) VALUES(1001,'Java',89,1) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1002,'JSP',79,1) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1003,'Android',99,1) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1101,'Oracle',59,2) ;
INSERT INTO book(bid,title,price,stuid) VALUES(1102,'MySQL',19,2) ;

  不管以后如何变化,数据库之间的关联的表最多只能两两关联。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值