数据库的关联查询

一. 分组查询

1. 概述

把结果先按照分组的形式,再进行数据分析

2. 测试

2.1 查询每个部门里员工的最高薪资

select deptno,max(sal) from emp group by deptno;

2.2 查询每个部门里员工的最高薪资和平均值

select max(sal),avg(sal),deptno from emp group by deptno;
如果出现了聚合函数(max,min,avg,sum,count),非聚合列,必须分组

2.3 查询每个岗位的员工的最高薪资和最低薪资

select max(sal),min(sal),job from emp group by job;

2.4 查询平均工资小于8000的部门

select deptno from emp group by deptno having avg(sal)<8000;
having 和 group by 是固定搭配,用来过滤分组后的数据
不可用where,where中不能出现聚合函数

2.5 deptno出现的次数大于2

select deptno,count(deptno) from emp group by deptno having count(deptno)>2;

3. where和having区别

3.1 where和having都用于对表中记录进行筛选过滤.

3.2 where用于在分组之前对记录进行筛选过滤,而having用于对分组之后的记录进行筛选过滤.

3.3 where子句中不能使用多行函数和列别名,但可以使用表别名.

3.4 having子句中可以使用多行函数、列别名和表别名.

二. 数据库事务(Database Transation)

1. 概述

为了保证数据的安全,如果要操作多条SQL,要么全部成功,要么全部失败 .

2. ACID特点

2.1 原子性(Atomicity,或称不可分割性): 多条SQL是密不可分的,整体的结果要么全成功,要么全失败.

2.2 一致性(Consistency): 保证数据的守恒,总和不变.

2.3 隔离性(Isolation,或称独立性): 数据库支持高并发(即允许多个并发事务同时对其数据进行读写操作),但是操作之间是独立的、被隔离的.

2.4 持久性(Durability): 是指SQL语句对数据库的操作(增删改),影响是永久的.

3. 隔离级别

3.1 读未提交(Read uncommitted): 性能最好,但可能发生并发数据问题,安全性最差.

3.2 读已提交(Read committed): 性能稍差,但是数据安全 (Oracle默认的隔离级别).

3.3 可重复读(Repeatable Read): 性能一般,但是安全性较好 (MySQL默认的隔离级别).

3.4 串行化(Serializable): 表级锁,读写都加锁,效率低下,安全性高,不能并发.

4. 事务的隔离

在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务,如果需要在一个事务中包含多条SQL语句,那么就需要手动开启事务和结束事务.

开启事务: start transaction

结束事务: commit(提交事务) 或 rollback(回滚事务)

在执行上去了语句之前,先执行start transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条生气了语句所作出的影响会持久化到数据库中.或者rollback,表示回滚,即回滚到事务的起点,之前做的所有操作都被撤销.

MySQL 8.0之前使用:
SELECT @@tx_isolation;

MySQL 8.0中使用:
SELECT @@transaction_isolation;

在这里插入图片描述
Repeatable Read(可重读)
MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行.

5. 事务处理

5.1 在MySQL中只有使用了Innodb 数据库引擎的数据库或表才支持事务.

5.2 事务处理可以用来维护数据的完整性,保证成批的SQL语句要么全部执行,要么全部不执行.

5.3 事务用来管理 insert 、update 、delete语句,因为这些操作才会"破坏"数据,查询select语句不会.

5.4 MySQL默认数据库的事务是开启的,执行SQL后自动提交.

5.5 MySQL的事务也可以改为手动提交,那么就会有两个步骤:先开启,写完SQL语句后,再手动提交.

6. 测试

6.1 begin: 开启事务

6.2 commit / rollback: 关闭事务
i. commit: 提交事务,产生永久影响
ii. rollback: 回滚事务,数据库里没有新数据

6.3 查询SQL,commit之后才有数据,没有commit或者rollback都查不到

三. 约束 constraints

1. 非空约束 not null

DROP TABLE IF EXISTS tb_user;  #如果表存在则删除,慎用会丢失数据

CREATE TABLE tb_user(
  id INT AUTO_INCREMENT,
  NAME VARCHAR(30) UNIQUE NOT NULL,
  age INT,
  phone VARCHAR(20) UNIQUE NOT NULL,
  email VARCHAR(30) UNIQUE NOT NULL,
  PRIMARY KEY (id)
);

DESC tb_user;

#id为自增主键,null值无效,数据库会自动用下一个id值替代
#age因为运行为null,所以可以设置为null
INSERT INTO tb_user (id,age) VALUES(NULL,NULL);

2. 唯一约束 unique

name字段创建了唯一约束,插入数据时数据会进行检查,如果插入的值相同,就会检查报错

DROP TABLE IF EXISTS tb_user;  #如果表存在则删除,慎用会丢失数据

CREATE TABLE tb_user(
  id INT,
  NAME VARCHAR(30) UNIQUE NOT NULL,
  phone VARCHAR(20) UNIQUE NOT NULL,
  email VARCHAR(30) UNIQUE NOT NULL,
  PRIMARY KEY (id)
);

DESC tb_user;

INSERT INTO tb_user (id,NAME) VALUES(1,'tony');
INSERT INTO tb_user (id,NAME) VALUES(2,'tony');

执行上面语句会出现错误

Query : INSERT INTO tb_user (id,NAME) VALUES(2,'tony')
Error Code : 1062
Duplicate entry 'tony' for key 'name'

3. 主键约束 primary key

主键是一条记录的唯一标识,具有唯一性,不能重复

DROP TABLE IF EXISTS tb_user;  #如果表存在则删除,慎用会丢失数据

CREATE TABLE tb_user(
  id INT,
  NAME VARCHAR(30),
  PRIMARY KEY (id)
);

INSERT INTO tb_user (id,NAME) VALUES(1,'tony');
INSERT INTO tb_user (id,NAME) VALUES(1,'hellen');

第二句插入会报错:

Query : INSERT INTO tb_user (id,NAME) VALUES(1,'hellen')
Error Code : 1062
Duplicate entry '1' for key 'PRIMARY'

提示主键1的值已经存在.

4. 外键约束 foreign key

DROP TABLE IF EXISTS tb_user_address;  #如果表存在则删除,慎用会丢失数据
DROP TABLE IF EXISTS tb_user;  #如果表存在则删除,慎用会丢失数据

CREATE TABLE tb_user (
  id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,  #自增主键
  NAME VARCHAR(50) NOT NULL UNIQUE,  #非空,唯一索引
  sex CHAR(2) DEFAULT '男',  #默认值
  phone CHAR(18),
  age INT,
  CHECK (age>0 AND age<=200),
  createdTime DATE DEFAULT NOW()
);

CREATE TABLE tb_user_address (
  user_id INT PRIMARY KEY NOT NULL,
  address VARCHAR(200),
  FOREIGN KEY(user_id) REFERENCES tb_user(id)
);

DESC tb_user;

tb_user_address中user_id字段录入tb_user表不存在的主键值,将报错.

如果要删除tb_user表中的数据,则先需要删除tb_user_addr中约束的数据,才可以删除tb_user表中的数据.

5. 默认约束 default

DROP TABLE IF EXISTS tb_user;  #如果表存在则删除,慎用会丢失数据

CREATE TABLE tb_user (
  id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,  #自增主键
  NAME VARCHAR(50) NOT NULL UNIQUE,  #非空,唯一索引
  sex CHAR(2) DEFAULT '男',  #默认值
  phone CHAR(18),
  age INT,
  createdTime DATE DEFAULT NOW()
);

DESC tb_user;

6. 检查约束 check (了解即可)

如今很少使用,例如age超过200将会报错

DROP TABLE IF EXISTS tb_user;  #如果表存在则删除,慎用会丢失数据

CREATE TABLE tb_user (
  id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,  #自增主键
  NAME VARCHAR(50) NOT NULL UNIQUE,  #非空,唯一索引
  sex CHAR(2) DEFAULT '男',  #默认值
  phone CHAR(18),
  age INT,
  CHECK (age>0 AND age<=200),
  createdTime DATE DEFAULT NOW()
);

DESC tb_user;

四. 表关联 association

1. 概念:

表table代表了生活中一个主体,如部门表dept,员工表emp.表关联则代表了表之间的关系,如:部门和员工,商品和商品分类,老师和学生,教室和学生.

同时,也要知道,表并不都有关系,它们形成自己的小圈子.如商品和商品详情一圈,部门和员工一圈,出圈就可能没关系了,如商品和员工无关,商品和学生无关.

2. 下面我们讨论表的关系分为四种:

一对一(one to one): QQ 和QQ邮箱,员工和员工编号

一对多(one to many): 最常见,部门和员工,用户和订单

多对一(many to one): 一对多反过来,员工和部门,订单和用户

多对多(many to many): 老师和学生,老师和课程

五. 多表联查

多表查询是指基于两个和两个以上的表的查询。在实际应用中,查询单个表可能不能满足你的需求,如显示员工表emp中不只显示deptno,还要显示部门名称,而部门名称dname在dept表中。

1. 笛卡尔积 Cartesian product

把两个表的数据都拼接起来
select * from emp,dept;

上面这种查询两个表的方式称为:笛卡尔积(Cartesian product),又称直积。一般笛卡尔积没有实际的业务意义,但多表查询都是先生成笛卡尔积,再进行数据的筛选过滤。

这点很值得注意,实际开发中尽量少用多表联查,其根本原因就在这里,查询过程中,现在内存中构建一个大大的结果集,然后再进行数据的过滤。那这个构建过程,和所使用的内存资源,包括过滤时的判断,都是既耗费资源,又浪费时间。

2. 三种连接 join

连接 jion
内连接 inner join
左(外)连接 left join
右(外)连接 right join

2. inner join 交集

3. left join 左边的所有数据和右面满足了的数据

4. right join 右边的所有数据和左边满足了的数据

5. 测试

5.1 查询tony的部门信息

笛卡尔积
select * from emp,dept 
where 
emp.deptno = dept,id	//描述了两张表的关系
and 
emp.ename = 'tony';	//过滤条件

5.2 join分为内连接,外连接(左外连接left join / 右外连接right join)

内连接,取交集
select * from emp inner join dept on emp.deptno = dept.id and emp.ename = 'tony';
左连接,取左边的所有和右边满足了的
select * from emp left join dept on emp.deptno = dept.id and emp.ename = 'tony';
右连接,取右边的所有和左边满足了的
select * from emp right join dept on emp.deptno = dept.id and emp.ename = 'tony';

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