约束的作用:
对添加进表中的数据进行限制和检查,保证表中的数据正确性、有效性和完整性。 -- 建议在创建表的时候创建约束,因为这里表中没有数据。
约束种类:
约束名 | 约束关键字 |
---|---|
主键 | primary key |
唯一 | unique |
非空 | not null |
默认 | default |
外键 | foreign key |
主键约束
主键的作用
几乎每张表都需要创建主键,用来唯一标识表中的每一条记录。 每个表都应该有一个主键,并且每个表只能有一个主键。
哪个字段应该作为表的主键?
通常不用业务字段作为主键,单独给每张表设计一个id的字段,把id作为主键。 -- 主键是给数据库和程序使用的,不是给最终的客户使用的。 所以主键有没有含义没有关系,只要不重复,非空就行。
主键的特点:
-- 1) 唯一 -- 2) 非空 -- 3)主键可以多个字段(联合主键)
创建主键方式:
1. 在创建表的时候给字段添加主键 字段名 字段类型 PRIMARY KEY 2. 在已有表中添加主键 ALTER TABLE 表名 ADD PRIMARY KEY(字段名);
-- 创建表学生表st1, 包含字段(id, name, age)将id做为主键 CREATE TABLE st1( id INT PRIMARY KEY , NAME VARCHAR(20), age INT ); CREATE TABLE tab( rid INT, `date` DATE, uid INT, PRIMARY KEY(rid,uid), -- 联合主键 ); -- 插入重复的主键值 INSERT INTO st1 VALUES(1, '张三', 20); -- 报错 -- Duplicate entry '1' for key 'PRIMARY' 重复的记录 INSERT INTO st1 VALUES(1, '李四', 30); -- 插入NULL的主键值 Column 'id' cannot be null 列不能为空 INSERT INTO st1 VALUES(NULL, '李四',30);
删除主键
删除主键 ALTER TABLE 表名 DROP PRIMARY KEY; 具体操作: -- 删除 st1 表的主键 通常情况下,一般不删除主键 ALTER TABLE st1 DROP PRIMARY KEY; -- 在已有表中添加主键 ALTER TABLE st1 ADD PRIMARY KEY(id);
主键自增
主键如果让我们自己添加很有可能重复, 我们通常希望在每次插入新记录时,数据库自动生成主键字段的值 AUTO_INCREMENT 表示自动增长(字段类型必须是整数类型) 默认地 AUTO_INCREMENT 的开始值是 1, 如果希望修改起始值,请使用下列 SQL 语法 创建表时指定起始值 CREATE TABLE 表名( 列名 int primary key AUTO_INCREMENT ) AUTO_INCREMENT=起始值; 创建好以后修改起始值 ALTERTABLE 表名 AUTO_INCREMENT=起始值;
-- 创建学生表st2时, 包含字段(id, name, age)将id做为主键并自动增长 CREATE TABLE st2 ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT ); SELECT * FROM st2; -- 插入数据 -- Column count doesn't match value count at row 1 INSERT INTO st2 VALUES('张三',18); INSERT INTO st2 (NAME,age) VALUES('张三',18); INSERT INTO st2 (NAME,age) VALUES('李四',20); -- 另一种写法 INSERT INTO st2 VALUES(NULL, '李白',20); -- 删除表 DROP TABLE IF EXISTS st2; -- 创建表时指定起始值 -- 指定自增长从1000开始 CREATE TABLE st2 ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT ) AUTO_INCREMENT = 1000; INSERT INTO st2 (NAME,age) VALUES('张三',18); INSERT INTO st2 (NAME,age) VALUES('李四',20); SELECT * FROM st2; -- 再创建表 CREATE TABLE st2 ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT ); -- 创建学生表st2后, 将id添加自动增长 ALTER TABLE st2 MODIFY id INT AUTO_INCREMENT; -- 创建好以后修改起始值 ALTER TABLE st2 AUTO_INCREMENT=2000; INSERT INTO st2 (NAME,age) VALUES('张三',18); INSERT INTO st2 (NAME,age) VALUES('李四',20); SELECT * FROM st2;
DELETE和TRUNCATE对自增长的影响
DELETE:不会影响自增长的值,使用原来的自增长。 TRUNCATE:会,从1开始重新计数
唯一约束
-- 什么是唯一约束:表中某一列不同出现重复的值 -- 唯一约束的基本格式 字段名 字段类型 UNIQUE
实现唯一约束
-- 创建学生表st3, 包含字段(id, name),name这一列设置唯一约束,不能出现同名的学生 CREATE TABLE st3 ( id INT PRIMARY KEY, NAME VARCHAR(20) UNIQUE ); DESC st3; -- 添加一个同名的学生 INSERT INTO st3 VALUES (1, '张三'); SELECT * FROM st3; -- Duplicate entry '张三' for key 'name' INSERT INTO st3 VALUES (2, '张三'); -- 重复插入多个null会怎样? INSERT INTO st3 VALUES (2, NULL); INSERT INTO st3 VALUES (3, NULL); SELECT * FROM st3;
非空约束
什么是非空约束: 表中的某一列不能为NULL 非空约束的基本语法格式 字段名 字段类型 NOT NULL
-- 创建表学生表st4, 包含字段(id,name,gender)其中name不能为NULL CREATE TABLE st4 ( id INT PRIMARY KEY, NAME VARCHAR(20) NOT NULL, gender CHAR(1) ); DESC st4; -- 添加一条记录其中姓名不赋值 INSERT INTO st4 VALUES(1,'张三','男'); SELECT * FROM st4; -- Column 'name' cannot be null INSERT INTO st4 VALUES(2,NULL,'男');
默认值
什么是默认值: 某一列,如果没有输入值,则使用指定的默认值。 默认值的语法: 字段名 字段类型 DEFAULT 默认值
-- 创建一个学生表 st5,包含字段(id,name,address), 地址默认值是广州 CREATE TABLE st5 ( id INT PRIMARY KEY, NAME VARCHAR(20), address VARCHAR(20) DEFAULT '广州' ); DESC st5; -- 添加一条记录,使用默认地址 INSERT INTO st5 (id,NAME) VALUES (1,'张三'); SELECT * FROM st5; -- 添加一条记录,不使用默认地址 INSERT INTO st5 VALUES (2,'张三疯','深圳'); INSERT INTO st5 VALUES (3,'李白',NULL); INSERT INTO st5 VALUES (4,'李白',DEFAULT); -- 加一个性别属性,默认为男 ALTER TABLE st5 ADD sex CHAR(1) DEFAULT '男';
外键约束
单表的缺点
创建一个员工表包含如下列(id, name, age, dep_name, dep_location),id主键并自动增长,添加5条数据 CREATE TABLE emp ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(30), age INT, dep_name VARCHAR(30), dep_location VARCHAR(30) ); -- 添加数据 INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('张三', 20, '研发部', '广州'); INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('李四', 21, '研发部', '广州'); INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('王五', 20, '研发部', '广州'); INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('老王', 20, '销售部', '深圳'); INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('大王', 22, '销售部', '深圳'); INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('小王', 18, '销售部', '深圳');
以上数据表的缺点:
出现大量重复的数据,假如有1000个员工,有10个部门。大量部门的数据是重复的。
解决方案:
创建成两张表,一张员工表,另一张部门表
-- 创建一个部门表,主表(主表是一方) CREATE TABLE department( id INT PRIMARY KEY AUTO_INCREMENT, -- 主键 dep_name VARCHAR(20), dep_location VARCHAR(30) ); -- 添加部门数据 INSERT INTO department VALUES (NULL,'研发部','广州'),(NULL,'销售部','深圳'); SELECT * FROM department; -- 创建一个员工表,有外键的表是从表,(从表是多方) CREATE TABLE employee( id INT PRIMARY KEY AUTO_INCREMENT, -- 主键 NAME VARCHAR(20), age INT, dep_id INT -- 创建一个外键 ); SELECT * FROM employee; INSERT INTO employee (NAME, age, dep_id) VALUES ('张三', 20, 1); INSERT INTO employee (NAME, age, dep_id) VALUES ('李四', 21, 1); INSERT INTO employee (NAME, age, dep_id) VALUES ('王五', 20, 1); INSERT INTO employee (NAME, age, dep_id) VALUES ('老王', 20, 2); INSERT INTO employee (NAME, age, dep_id) VALUES ('大王', 22, 2); INSERT INTO employee (NAME, age, dep_id) VALUES ('小王', 18, 2);
问题:当我们在employee的dep_id里面输入不存在的部门,数据依然可以添加.
但是并没有对应的部门,实际应用中不能出现这种情况。
employee的dep_id中的数据只能是department表中存在的id
目标: 需要约束dep_id只能是department表中已经存在id
解决方式: 使用外键约束
什么是外键约束
-- 什么是外键: 从表中引用了主表中主键的那一列 -- 主表: 一方就是主表,约束别人的一方 -- 从表: 多方就是从表,被约束的一方
创建约束的语法
新建表时增加外键: [CONSTRAINT] [外键约束名称] FOREIGN KEY(外键字段名) REFERENCES 主表名(主键字段名) 已有表增加外键: ALTER TABLE 从表 ADD [CONSTRAINT] [外键约束名称] FOREIGN KEY (外键字段名) REFERENCES 主表(主键字段名);
-- 1) 删除副表/从表 employee DROP TABLE employee; -- 2) 创建从表 employee 并添加外键约束emp_depid_fk, 如果没有起名,系统也会自动添加一个名字 CREATE TABLE employee( id INT PRIMARY KEY AUTO_INCREMENT, -- 主键 NAME VARCHAR(20), age INT, dep_id INT, -- 创建一个外键 -- 添加外键约束 CONSTRAINT emp_depid_fk FOREIGN KEY (dep_id) REFERENCES department(id) ); -- 3) 正常添加数据 INSERT INTO employee (NAME, age, dep_id) VALUES ('张三', 20, 1); INSERT INTO employee (NAME, age, dep_id) VALUES ('李四', 21, 1); INSERT INTO employee (NAME, age, dep_id) VALUES ('王五', 20, 1); INSERT INTO employee (NAME, age, dep_id) VALUES ('老王', 20, 2); INSERT INTO employee (NAME, age, dep_id) VALUES ('大王', 22, 2); INSERT INTO employee (NAME, age, dep_id) VALUES ('小王', 18, 2); SELECT * FROM employee; -- 4) 部门错误的数据添加失败 -- Cannot add or update a child row: 从表中的记录 INSERT INTO employee (NAME, age, dep_id) VALUES ('小小王', 16, 6);
删除外键
-- 删除employee表的emp_depid_fk外键 ALTER TABLE employee DROP FOREIGN KEY emp_depid_fk; -- 在employee表情存在的情况下添加外键 ALTER TABLE employee ADD CONSTRAINT aaa_bbb FOREIGN KEY(dep_id) REFERENCES department(id);
外键的级联
出现新的问题:要把部门表中的id值2,改成5,能不能直接更新呢?
-- Cannot delete or update a parent row: 不能更新主表中的行 UPDATE department SET id=5 WHERE id=2; -- 要删除部门id等于1的部门, 能不能直接删除呢? -- Cannot delete or update a parent row 不能删除主表中的行 DELETE FROM department WHERE id=1;
什么是级联操作:
在修改和删除主表的主键时,同时更新或删除副表的外键值,称为级联操作。 -- 只能在创建表的时候创建级联 ON UPDATE CASCADE 级联更新 ON DELETE CASCADE 级联删除
-- 删除employee表(从表) -- 如果从表存在的情况下,不能直接删除主表 -- Cannot delete or update a parent row: a foreign key constraint fails DROP TABLE department; DROP TABLE employee; -- 重新创建employee表,添加级联更新和级联删除-- 只能在创建表的时候创建级联 CREATE TABLE employee( id INT PRIMARY KEY AUTO_INCREMENT, -- 主键 NAME VARCHAR(20), age INT, dep_id INT, -- 创建一个外键 -- 添加外键约束 CONSTRAINT emp_depid_fk FOREIGN KEY (dep_id) REFERENCES department(id) ON UPDATE CASCADE ON DELETE CASCADE ); -- 再次添加数据到员工表和部门表 INSERT INTO employee (NAME, age, dep_id) VALUES ('张三', 20, 1); INSERT INTO employee (NAME, age, dep_id) VALUES ('李四', 21, 1); INSERT INTO employee (NAME, age, dep_id) VALUES ('王五', 20, 1); INSERT INTO employee (NAME, age, dep_id) VALUES ('老王', 20, 2); INSERT INTO employee (NAME, age, dep_id) VALUES ('大王', 22, 2); INSERT INTO employee (NAME, age, dep_id) VALUES ('小王', 18, 2); SELECT * FROM employee; SELECT * FROM department; -- 把部门表中id等于1的部门改成id等于9 UPDATE department SET id=9 WHERE id=1; -- 删除部门号是2的部门 DELETE FROM department WHERE id=2;
数据约束小结
约束名 | 关键字 | 说明 |
---|---|---|
主键 | primary key | 1) 唯一2) 非空3) 可以有多列 |
默认 | default | 如果没有输入值,使用默认值 |
非空 | not null | 不能为空 |
唯一 | unique | 不能重复 |
外键 | foreign key | 从表中的外键值,不能出现主表中没有的主键值 |
创建员工表和部门表,使用级联更新 1) 创建主键和外键约束 2) 员工表的主键使用整型,宽3位,使用自动增长,零填充,从100开始。 2) 员工姓名使用非空唯一约束 3) 员工加一个性别属性,默认为男 4) 添加3个部门。向1号部门添加2个员工,向2号部门添加2个员工,向3号部门添加1个员工。 5) 将102号员工转到3号部门中 6) 更新1号部门为10号部门,观察部门表和员工表的变化。 7) 删除3号部门,看会不会出现问题。 8) 添加一个员工到5号部门,看有没有问题。
-- 部门表 CREATE TABLE depart ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) -- 部门名 ) -- 员工表 CREATE TABLE employee ( id INT(3) ZEROFILL PRIMARY KEY AUTO_INCREMENT,--zerofill 零填充 NAME VARCHAR(20) NOT NULL UNIQUE, gender CHAR(1) DEFAULT '男', depart_id INT, FOREIGN KEY (depart_id) REFERENCES depart(id) ON UPDATE CASCADE ) AUTO_INCREMENT = 100; -- 添加3个部门。向1号部门添加2个员工,向2号部门添加2个员工,向3号部门添加1个员工。 INSERT INTO employee (NAME,gender,depart_id) VALUES ('张三','男',1),('张四','女',1),('王五','男',2),('刘六','男',2),('孙七','男',3); SELECT * FROM employee; -- 将2号员工转到3号部门中 UPDATE employee SET depart_id = 3 WHERE id = 102; -- 更新1号部门为10号部门,观察部门表和员工表的变化。 UPDATE depart SET id=10 WHERE id=1; SELECT * FROM employee; -- 删除3号部门,看会不会出现问题(删除异常) DELETE FROM depart WHERE id=3; -- 添加一个员工到5号部门,看有没有问题。(出现异常) INSERT INTO employee (NAME,gender,depart_id) VALUES ('小红','女',5);