15. 外键约束
当我们添加了外键以后,就在数据库层面建立了两张表的关系。
目的:外键用来让两个表的数据之间建立链接,保证数据的一致性和完整性
添加约束:
CREATE TABLE 表名( 列名 数据类型, … [CONSTRAINT] [外键名称] FOREIGN KEY(外键列名) REFERENCES 主表(主表列名) );
建完表后添加外键约束:
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称);
删除约束:
ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;
16. 约束的案例练习
首先,我们使用以下的案例来练习约束:
-- 删除stu表 drop table if exists stu; -- 创建stu表 CREATE TABLE stu ( id int primary key, -- 编号 主键 name varchar(10) not null unique, -- 姓名 非空,唯一 age int not null, -- 年龄 非空 gender varchar(5) not null, -- 性别 非空 math double(5,2) not null, -- 数学成绩 非空 english double(5,2) default 0 -- 英语成绩 默认为0 );
验证主键约束,其特点是非空且唯一,先添加一条数据:
insert into stu(id,name,age,gender,math,english) values(1,'小张',23,'男',66,78);
添加第二条数据时,尝试 id 添加为空值:
insert into stu(id,name,age,gender,math,english) values (null,'小李',20,'女',98,87);
尝试 id 添加为重复的值:
insert into stu(id,name,age,gender,math,english) values (1,'小陈',55,'男',56,77);
我们已经验证了主键约束,当我们添加不合法的数据时,添加失败。
验证非空约束:
当我们添加以下的数据时:
insert into stu(id,name,age,gender,math,english) values (2,NULL,20,'女',76,65);
验证唯一约束:
当我们添加以下的数据时:
insert into stu(id,name,age,gender,math,english) values (5,'小张',20,'男',86,NULL);
验证默认约束:
当我们添加以下的数据时:
insert into stu(id,name,age,gender,math) values (6,'小赵',23,'男',99);
验证外键约束:
我们使用一下的案例来验证外键约束:
-- 删除表 DROP TABLE IF EXISTS emp; DROP TABLE IF EXISTS dept; -- 部门表 CREATE TABLE dept( id int primary key auto_increment, dep_name varchar(20), addr varchar(20) ); -- 员工表 CREATE TABLE emp( id int primary key auto_increment, name varchar(20), age int, dep_id int, -- 添加外键 dep_id,关联 dept 表的id主键 CONSTRAINT fk_emp_dept FOREIGN KEY(dep_id) REFERENCES dept(id) );
此时,我们在员工表中添加了外键,相当于在数据库层面上建立了两张表的关系,此时如果员工表中有员工 a ,他属于 1 号部门,那么我们想要删除部门表中的 1 号部门就会删除失败,因为员工 a 是属于 1 号部门的,此时两张表建立了关系。
添加数据:
-- 添加 2 个部门 insert into dept(dep_name,addr) values ('研发部','西安'),('销售部', '成都'); -- 添加员工,dep_id 表示员工所在的部门 INSERT INTO emp (NAME, age, dep_id) VALUES ('张三', 20, 1), ('李四', 20, 2);
此时想要是删除销售部门时,发现删除失败。
17. 数据库设计
17.1 概念
数据库设计是软件研发过程中很重要的一个环节,在学习数据库设计之前,要先了解软件研发的步骤。
一个成熟的软件,从想法的产生到成功上线,要经历需求调研及分析,设计,编码,测试和部署等过程,在开始阶段产品经理会根据客户的需求设计产品原型,而设计一般有架构师和开发工程师完成,这其中就包括数据库设计,还有软件结构设计,接口设计等,接着就是由开发工程师来编写代码,由测试工程师来测试,接着就可以部署上线。
数据库设计就是根据业务系统的具体需求,结合我们所选用的 DBMS,为这个业务系统构造出最优的数据存储模型。通俗的说就是建立数据库中的表结构以及表与表之间的关联关系的过程,分析有哪些表,哪些字段等。
数据库设计分为以下几个步骤:
- 需求分析
- 逻辑分析
- 物理分析
- 维护设计
17.2 表的关系
表和表之间的关系有一对一的关系,主要用于表的拆分,利于把常用数据和不常用数据分开存储,提高查询的效率。一对多或者多对一的关系,例如部门表和员工表的关系,多对多的关系,例如商品和订单的关系。
一对多的关系中,在表示多的一方建立外键,指向另一方的主键,示例:
-- 删除表 DROP TABLE IF EXISTS tb_emp; DROP TABLE IF EXISTS tb_dept; -- 部门表 CREATE TABLE tb_dept( id int primary key auto_increment, dep_name varchar(20), addr varchar(20) ); -- 员工表 CREATE TABLE tb_emp( id int primary key auto_increment, name varchar(20), age int, dep_id int, -- 添加外键 dep_id,关联 dept 表的id主键 CONSTRAINT fk_emp_dept FOREIGN KEY(dep_id) REFERENCES tb_dept(id) );
查看两表结构模型:
多对多的关系中,建立第三张中间表,中间表至少包含两个外键,分别关联两方主键,例如商品表和订单表。示例:
-- 删除表 DROP TABLE IF EXISTS tb_order_goods; DROP TABLE IF EXISTS tb_order; DROP TABLE IF EXISTS tb_goods; -- 订单表 CREATE TABLE tb_order( id int primary key auto_increment, payment double(10,2), payment_type TINYINT, status TINYINT ); -- 商品表 CREATE TABLE tb_goods( id int primary key auto_increment, title varchar(100), price double(10,2) ); -- 订单商品中间表 CREATE TABLE tb_order_goods( id int primary key auto_increment, order_id int, goods_id int, count int ); -- 建完表后,添加外键 alter table tb_order_goods add CONSTRAINT fk_order_id FOREIGN key(order_id) REFERENCES tb_order(id); alter table tb_order_goods add CONSTRAINT fk_goods_id FOREIGN key(goods_id) REFERENCES tb_goods(id);
查看两表的结构模型:
一对一的关系中,在任意一方加入外键,关联另一方主键,并且设置外键为唯一(UNIQUE),例如用户和用户详情。
示例:
create table tb_user_desc ( id int primary key auto_increment, city varchar(20), edu varchar(10), income int, status char(2), des varchar(100) ); create table tb_user ( id int primary key auto_increment, photo varchar(100), nickname varchar(50), age int, gender char(1), desc_id int unique, -- 添加外键 CONSTRAINT fk_user_desc FOREIGN KEY(desc_id) REFERENCES tb_user_desc(id) );
18. 多表查询
前面学习查询操作时,一直是从一张表中查询数据,而数据库的多表查询操作也是非常重要的一部分。多表查询就是一次性从多张表中查询出需要的数据。
在MySQL中多表查询分为连接查询和子查询,而连接查询又分为内连接查询和外连接查询,外连接查询的方式有左外连接查询和右外连接查询。下面对多表查询做一些基础的练习!
下面是演示多表查询使用的 sql:
DROP TABLE IF EXISTS emp; DROP TABLE IF EXISTS dept; # 创建部门表 CREATE TABLE dept( did INT PRIMARY KEY AUTO_INCREMENT, dname VARCHAR(20) ); # 创建员工表 CREATE TABLE emp ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), gender CHAR(1), -- 性别 salary DOUBLE, -- 工资 dep_id INT, FOREIGN KEY (dep_id) REFERENCES dept(did) -- 外键,关联部门表(部门表的主键) ); -- 添加部门数据 INSERT INTO dept (dNAME) VALUES ('研发部'),('财务部'),('销售部'); -- 添加员工数据 INSERT INTO emp(NAME,gender,salary,dep_id) VALUES ('小张','男',3000,1), ('小李','女',3600,2), ('小王','男',9000,2), ('小美','女',5000,null);
执行 sql ,创建表:
18.1 内连接查询
内连接查询分为隐式内连接查询和显式内连接查询,表示查询 A 集合和 B 集合的交集。
语法:
-- 隐式内连接查询 SELECT 字段列表 FROM 表1,表2… WHERE 条件; -- 显示内连接查询 SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 条件;
隐式内连接查询示例:
select * from emp,dept where dep_id=did;
结果:
显式内连接查询示例:
select * from emp inner join dept on dep_id=did;
结果:
18.2 外连接查询
外连接查询分为作为连接查询和右外连接查询。左外连接查询:相当于查询A表所有数据和交集部分数据。
右外连接查询:相当于查询B表所有数据和交集部分数据。
语法:
-- 左外连接 SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 条件; -- 右外连接 SELECT 字段列表 FROM 表1 RIGHT [OUTER] JOIN 表2 ON 条件;
左外连接查询示例:
select * from emp left outer join dept on dep_id=did;
结果:
右外连接查询示例:
select * from emp right outer join dept on dep_id=did;
结果:
18.3 子查询
子查询是指查询中嵌套有查询,以下的几种情况通常使用嵌套查询:
子查询语句结果是单行单列,子查询语句作为条件值,使用 = != > < 等进行条件判断,例如查询员工中工资大于小李的员工信息:
select * from emp where salary >(select salary from emp where name='小李');
结果:
子查询语句结果是多行单列,子查询语句作为条件值,使用 in 等关键字进行条件判断,例如查询研发部和财务部员工信息:
select * from emp where dep_id in (select did from dept where dname='研发部' or dname= '财务部');
结果:
子查询语句结果是多行多列,子查询语句作为虚拟表,例如查询员工中工资大于3000的员工的信息和部门信息:
select * from (select * from emp where salary>3000) t1, dept where t1.dep_id=dept.did;
19. 事务
19.1 概念
数据库的事务是一种机制,包含了一组数据库操作命令。事务把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么同时成功,要么同时失败。
例如在进行转账操作时,张三转账给李四 500 元,首先会验证张三账户余额是否充足,如果是,则张三账户减少 500,李四账户增加 500 。如果在这过程中,由于某种原因出现错误,李四的账户没有增加 500 ,那么张三账户减少 500 的操作也不能完成。也就是要保证在这个过程中张三和李四账户余额总和要保持不变。
19.2 语法
开启事务:
START TRANSACTION; 或者 BEGIN;
回滚事务:
commit;
提交事务:
rollback;
小练习:张三转账给李四
DROP TABLE IF EXISTS account; -- 创建账户表 CREATE TABLE account( id int PRIMARY KEY auto_increment, name varchar(10), money double(10,2) ); -- 添加数据 INSERT INTO account(name,money) values('张三',1000),('李四',1000);
添加事务:
-- 开启事务 BEGIN; -- 转账操作 -- 1. 查询李四账户金额是否大于500 -- 2. 张三账户 -500 UPDATE account set money = money - 500 where name = '张三'; 3%0;--出现异常 -- 3. 李四账户 +500 UPDATE account set money = money + 500 where name = '李四'; -- 提交事务 COMMIT; -- 回滚事务 ROLLBACK;
如果不添加事务,张三的账户就会减少 500 ,而李四的账户并不会增加 500,这样并不符合我们的实际生活。否则张三的 500 便不翼而飞了,哈哈哈!可见事务的重要性。
19.3 特征
MySQl 事务具有四大特征,分别是:
原子性: 事务是不可分割的最小操作单位,要么同时成功,要么同时失败
一致性 :事务完成时,必须使所有的数据都保持一致状态
隔离性: 多个事务之间,操作的可见性
持久性: 事务一旦提交或回滚,它对数据库中的数据的改变就是永久的
20. 总结
科技发展,社会进步。未来对数据的定义会不断地革新,生活的方方面面都会被列入数据的行列。从某种意义上来说,数据就是信息,只是数据不能直观地带来价值,而信息可以,但未来,这两者之间的距离会越来越缩小,直至划上等号。
未来是一个数字化的时代,数据是我们最为宝贵的资源,不论是哪个专业出身,未来或多或少都会卷入数据时代的浪潮之中。而那些前提性的工作基本都是依靠数据库来完成。