MySQL2

多表查询

1、笛卡尔集

在默认情况下:当两个表查询时,规则
1.从第一张表中,取出一行和第二张表的每一行进行组合,返回结果[含有两张表的所有列.
2.一共返回的记录数第一张表行数*第二张表的行数3.这样多表查询默认处理返回的结果,称为笛卡尔集
3.解决这个问题需要写出正确的过滤条where

-- 多表查询
-- ?显示雇员名,雇员工资及所在部门的名字【笛卡尔集】
-- 老韩分析
-- 1.雇员名,雇员工资来自emp表
-- 2.部门的名字来自dept表
-- 3.需求对emp和dept查询
SELECT ename, sal, emp.deptno FROM emp,dept
WHERE emp.`deptno` = dept.`deptno`

2、多表查询

​​​​​​​​
在这里插入图片描述

SQL
-- ?显示各个员工的姓名,工资,及其工资的级别
-- 思路姓名,工资来自emp 
-- 工资级别salgrade 
SELECT ename, sal, grade
FROM emp , salgrade
WHERE sal BETWEEN losal AND hisal;
 
 SELECT * FROM salgrade
 SELECT * FROM emp
  
-- 学员练习:显示雇员名,雇员工资及所在部门的名字,并按部部门排序[降序排].
SELECT ename, sal, dname,emp.`deptno`
FROM emp , dept
WHERE emp.`deptno` = dept.`deptno`
ORDER BY deptno DESC

3、自联接

自连接是指在同一张表的连接查询[将同一张表看做两张表。

自连接的特点
1.把同一张表当做两张表使用
2.需要给表取别名 语法:表名+空格+ 别名
3.列不明确,可以指定列的别名

-- 多表值间的自连按
-- 思考题:显示公司员工名字和他的上级的名字
-- 分析:员工名字在emp,上级的名子的名子emp
-- 员工和上级是通过emp表的mgr列关联
SELECT worker.ename AS '职员名', boss.ename AS '上级名'
FROM emp worker, emp boss
WHERE worker.mgr = boss. empno ;

4、子查询

什么是子查询
子查询是指嵌入在其它sql语句中的select语句,也叫嵌套查询

  1. 单行子查询 单行子查询是指只返回一行数据的子查询语句
  2. 多行子查询 多行子查询指返回多行数据的子查询使用关键字in

4·1单行子查询

-- 请思考:如何显示与SMITH同一部门的所有员工
-- 1、先查询SMITH(ename)的部门编号
SELECT deptno FROM emp
WHERE ename = 'SMITH'-- 20
-- 2、把上面的select语句当作子查询来使用
SELECT * FROM emp
WHERE deptno = (SELECT deptno FROM emp
WHERE ename = 'SMITH'-- 20
)

4·2多行子查询

-- 课堂练习:如何查询和部门10的工作相同的雇员的
-- 名字、岗位、工资、部门号,但是不10号自己的雇员.
# 1、查询10号部门有那些工作
SELECT DISTINCT job FROM emp
WHERE deptno = 10
#完整语句
SELECT ename , job , sal ,deptno FROM emp
WHERE job IN (
SELECT DISTINCT job FROM emp
WHERE deptno = 10
)AND deptno != 10

4·3 ALL ANY 用法

ALL
-- 请思考:显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
SELECT ename , sal, deptno
FROM emp
WHERE sal > ALL(
SELECT sal FROM emp WHERE deptno = 30 -- 查询出30号部门所有人工资
)
SELECT ename , sal, deptno
FROM emp
WHERE sal > 
(SELECT MAX(sal) FROM emp WHERE deptno = 30)-- 查询出30号部门中最高工资
ANY
-- 请思考:如何显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号
SELECT ename , sal, deptno
FROM emp
WHERE sal > ANY(
SELECT sal FROM emp WHERE deptno = 30 -- 查询出30号部门所有人工资
)
SELECT ename , sal, deptno
FROM emp
WHERE sal > 
(SELECT MIN(sal) FROM emp WHERE deptno = 30)-- 查询出30号部门中最低工资

4·4多列子查询

多列子查序则是指查询返回多个列数据的子查询语句

-- 多列子值询
-- 请思考如何查询与allen的部门和岗位完全相同的所有雇员(并且不含allen本人)
-- (字段1,字段2...) = (select 字段1,字段2 from 。 。。。)
-- 分析:1.得到allen的部门和岗位
SELECT deptno , job
FROM emp
WHERE ename = 'ALLEN' ;
-- 分析:2把上面的查询当做子查询来使用,并且使用多列子查询的语法进行匹配
SELECT*FROM emp
WHERE(deptno , job) = (
	SELECT deptno , job FROM emp
	WHERE ename = 'ALLEN')
	AND ename != 'ALLEN'
	
-- 请查询和宋江数学,英语,语文成绩完全相同的学生
-- 1、查询宋江的成绩
SELECT * FROM student
WHERE `name` = '宋江'
-- 2、查询与宋江成绩相同的人
SELECT * FROM student
WHERE (english ,math , chinese)=(
SELECT english ,math , chinese FROM student
WHERE `name` = '宋江'
)

4·5子查询习题

-- 子查询练习
-- 请思考:查找每个部门工资高于本部门平均工资的人的资料
-- 这里要用到数据查询的小技巧,把一个子查询当作一个临时表使用

-- 1、先求出各个部门的平均工资
SELECT deptno , AVG(sal) AS avg_sal
	FROM emp 
	GROUP BY deptno
-- 2、把上面的结果当成子查询,和emp进行多表查询
SELECT ename , sal , temp.avg_sal ,emp.`deptno` FROM emp ,
(
	SELECT deptno , AVG(sal) AS avg_sal
	FROM emp 
	GROUP BY deptno
) temp
	WHERE emp.deptno = temp.deptno 
	AND emp.`sal` > temp.avg_sal 
	
	
-- 查找每个部门工资最高的人的详细资料	
SELECT ename , sal , temp.max_sal ,emp.`deptno` FROM emp ,
(
	SELECT deptno , MAX(sal) AS max_sal -- 各个部门最高工资
	FROM emp 
	GROUP BY deptno
) temp
	WHERE emp.deptno = temp.deptno 
	AND emp.`sal` = temp.max_sal 
	

SELECT * FROM dept
SELECT * FROM emp
-- 查询每个部门的信息(包括:部门名,编号,地址)和人员数量
-- 1、部门名,地址只在dept表中编号在dept和emp中
-- 人员只在emp表中
-- 各个部门的人员数量构建出一个临时表
SELECT COUNT(*), deptno FROM emp
	GROUP BY deptno
-- 2、将emp和临时表做多表查询
SELECT dept.`deptno` ,loc ,dname ,per_num AS '人数'
	FROM dept, (SELECT COUNT(*) AS per_num, deptno FROM emp
	GROUP BY deptno) temp
	WHERE dept.`deptno` = temp.deptno

5、表复制和去重

复制:

CREATE TABLE my_tab01
( 
	id INT,
	`name` VARCHAR(32),
	sal DOUBLE,
	job VARCHAR (32),
	deptno INT
);

SELECT * FROM my_tab01

-- 演示如何自我复制
-- 1.先把emp表的记录复制到my _tab01
INSERT INTO my_tab01
	(id, `name`, sal, job ,deptno)
SELECT empno, ename, sal, job,deptno 
FROM emp
-- 2、自我复制
INSERT INTO my_tab01
	SELECT * FROM my_tab01
-- 如何删除一张表的重复记录
CREATE TABLE my_tab02 LIKE emp -- 把emp表的结构(列)复制到my_tab02
INSERT INTO my_tab02
	SELECT * FROM emp

去重:

3.考虑去重my_tab02的记录
-- 思路
-- (1)先创建一张临时表my_tmp ,该表的结构和 my_tab02一样
CREATE TABLE my_tmp LIKE my_tab02
-- (2)把my_tab02 的记录通过distinct关键字处理后把记录复制到my_tmp
INSERT INTO my_tmp	
	SELECT DISTINCT * FROM my_tab02
SELECT*  FROM my_tmp
-- (3)清除掉my_tab02记录
DELETE FROM my_tab02
-- (4)把my_tmp表的记录复制到my _tab02
INSERT INTO my_tab02	
	SELECT * FROM my_tmp
-- (5) drop掉临时表my_tmp
DROP TABLE my_tmp
 

6、合并查询

union 合并且去重
union all 合并不去重

-- 合并查询
-- union all 就是将两个查询结果合并,不会去重
SELECT ename , sal,job FROM emp WHERE sal>2500 
UNION ALL
SELECT ename , sal,job FROM emp WHERE job = 'MANAGER'
-- union 将两个查询结果合并去重
SELECT ename , sal,job FROM emp WHERE sal>2500 
UNION 
SELECT ename , sal,job FROM emp WHERE job = 'MANAGER'

7、外连接

两表之间没有匹配的记录
●外连接
1.左外连接 (如果左侧的表完全显示我们就说是左外连接)
2、右外连接 (如果右侧的表完全显示我们就说是右外连接)

语法:select … from表1left join表2 on
(表1 是左表,表2是右表)


-- 使用左连接
-- (显示所有人的成绩,如果没有成绩,也要显示该人的姓名和id号,成绩显示为空)
SELECT `name`, stu.`id`,exam.`grade`
	 FROM stu LEFT JOIN exam
	ON stu.`id` = exam.`id`

结果
在这里插入图片描述

-- 右外连接
SELECT `name`, stu.`id`,exam.`grade`
	 FROM stu RIGHT JOIN exam
	ON stu.`id` = exam.`id`

结果
在这里插入图片描述

-- 练习
-- 列出部门名称和这些部门的员工信息(名字和工作),同时列出那些没有员工的部门名。emp,dept,dept
-- 1.使用左外连接实现
SELECT * FROM emp
SELECT * FROM dept

SELECT ename, job,dname
	 FROM dept LEFT JOIN emp
	ON dept.`deptno` = emp.`deptno`
-- 2.使用右外连接实现
SELECT ename, job,dname
	 FROM emp RIGHT JOIN dept
	ON dept.`deptno` = emp.`deptno`

结果
在这里插入图片描述

8、约束

8·1主键

主键

primary key(主键)-细节说明
· primary key不能重复而且不能为null。
·一张表最多只能有一个主键,但可以是复合主键主键的指定方式有两种
·直接在字段名后指定:字段名primakry key在表定义最后写primary key(列名);
·使用desc表名,可以看到primary key的情况
·复合主键:primary key(列1,列2) 列1,列2添加的值不能同时相同

8·2非空

在这里插入图片描述

8·3唯一

在这里插入图片描述

– unqiue使用细节
– 1.没有指定not null ,则unique字段可以有多个null
– 如果一个列(字段),是unique not null 则使用效果类似 primary key
– 2.一张表可以有多个unique字段

语法

-- unqiue使用细节
-- 1.没有指定not null ,则unique字段可以有多个null 
-- 如果一个列(字段),是unique not null 则使用效果类似 primary key
CREATE TABLE tab2(
	id INT UNIQUE NOT NULL,
	`name` VARCHAR(32) UNIQUE
)
-- 2.一张表可以有多个unique字段
CREATE TABLE tab3(
	id INT UNIQUE,
	`name` VARCHAR(32) UNIQUE
)

unique与primary key的区别
unique可以有null primary key 不可以

8·4外键

foreign key(外键)
用于定义主表和从表之间的关系:外键约束要定义在从表上,主表则必须具有主键约束或是unique约束,当定义外键约束后,要求外键列数据必须在主表的主键列存在或是为null

在这里插入图片描述

8·5check

在这里插入图片描述

#8·6约束练习

商店售货系统表设计案例
现有一个商店的数据库shop_db,记录客户及其购物情况,由下面三个表组成:商品goods(商品号goods_id,商品名goods_name,单价unitprice,商品类别category,供应商provider);
客户customer(客户号customer_id,姓名name,住址address,电邮email,性别sex,身份证card_id);
购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,购买数量nums);
1建表,在定义中要求声明[进行合理设计]:
(1)每个表的主外键;
(⑵)客户的姓名不能为空值;
(3)电邮不能够重复;
(4)客户的性别[男|女]check枚举…
(5)单价unitprice在1.0 - 9999.99之间check

-- 新建数据库
CREATE DATABASE shop_db
-- 建表
-- goods(商品号goods_id,商品名goods_name,单价unitprice,商品类别category,供应商provider);
CREATE TABLE goods(
	goods_id INT PRIMARY KEY, -- 商品号
	good_name VARCHAR(64) NOT NULL DEFAULT'', -- 商品名
	unitprice DECIMAL(10,2) NOT NULL DEFAULT 0
		CHECK (unitprice >= 1.0 AND unitprice <= 9999.99), -- 单价
	category INT NOT NULL DEFAULT 0, -- 商品类别
	provider VARCHAR(64) NOT NULL DEFAULT'' -- 供应商
)
-- 客户customer(客户号customer_id,姓名name,住址address,电邮email,性别sex,身份证card_id);
CREATE TABLE customer(
	customer_id INT PRIMARY KEY, -- 商品号
	`name` VARCHAR(32) NOT NULL DEFAULT'', -- 单价
	address VARCHAR(64) NOT NULL DEFAULT'', -- 商品类别
	email VARCHAR(64)UNIQUE NOT NULL,
	sex ENUM('男','女'), -- 性别
	card_id CHAR(18)
	)
	
-- 购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,购买数量nums);
CREATE TABLE purchase(
	order_id INT UNSIGNED PRIMARY KEY,
	customer_id INT NOT NULL DEFAULT 0,
	goods_id INT NOT NULL DEFAULT 0,
	nums INT NOT NULL DEFAULT 0,
	FOREIGN KEY (customer_id) REFERENCES customer(customer_id),
	FOREIGN KEY (goods_id) REFERENCES goods(goods_id)
)
SELECT * FROM goods;
SELECT * FROM customer;
SELECT * FROM purchase;

结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9、自增长

在某张表中,存在一个id列(整数),我们希望在添加记录的时候该列从1开始,自动的增长,怎么处理? increment.sql
在这里插入图片描述
自增长使用细节
1.一般来说自增长是和primary key配合使用的2.自增长也可以单独使用[但是需要配合一个unique]
3.自增长修饰的字段为整数型的(虽然小数也可以但是非常非常
少这样使用)
4.自增长默认从1开始,你也可以通过如下命令修改
alter table表名auto_increment =新的开始值;
5.如果你添加数据时,给自增长字段(列)指定的有值,则以指
定的值为准, 如果指定了自增长,一般来说,就按照自增长的规则来添加数据

CREATE TABLE t24
(id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(32)NOT NULL DEFAULT '',
`name` VARCHAR (32)NOT NULL DEFAULT 0)
DESC t24
INSERT INTO t24 VALUES(NULL, '',0)
SELECT * FROM t24
INSERT INTO t24 
	(email , `name`)VALUES('',0)
ALTER TABLE t24 AUTO_INCREMENT = 100
INSERT INTO t24 VALUES(NULL, '',0)

10、索引

说起提高数据库性能,索引是最物美价廉的东西了。不用加内存,不用改程序,不用调sql,查询速度就可能提高百倍干倍。

唯一索引

语法
CREATE UNIQUE INDEX 索引名 ON 表名(列名)) ;

添加唯一索引
CREATE UNIQUE INDEX id_index ON t25 (id) ;

在这里插入图片描述
0代表是唯一索引,反之,1代表不是唯一索引

普通索引

语法
CREATE INDEX 索引名 ON 表名(列名)) ;
ALTER TABLE 表名 ADD INDEX 索引名 (列名)

-- 方式1
CREATE UNIQUE INDEX id_index ON t25 (id) 
-- 方式2
ALTER TABLE t25 ADD INDEX id_index (id)

如果某列的值,是不会重复的,则优先考虑使用unique索引,否则使用普通索引

添加主键索引

语法
ALTER TABLE 表名 ADD PRIMARY KEY (列名)

ALTER TABLE t26 ADD PRIMARY KEY (id)

删除索引

– 删除索引

-- 删除索引
DROP INDEX id_index ON t25

修改索引

先删掉索引,再重新添加

查询索引

-- 查询索引
SHOW INDEX FROM t25 -- 方式1
SHOW KEYS FROM t25 -- 方式2

索引练习及总结

-- 索引练习
-- 要求:
-- 1.创建一张订单表order (id号,商品名,订购人,数量).
-- 要求id号为主键,请使用2种方式来创建主键.
-- (提示:为练习方便,可以是order1 , order2 )
CREATE TABLE `order`(
	id INT PRIMARY KEY,
	goods_name VARCHAR(32) NOT NULL DEFAULT '',
	people VARCHAR(32)NOT NULL DEFAULT '',
	`count` INT
)
-- 方式2
CREATE TABLE `order2`(
	id INT ,
	goods_name VARCHAR(32) NOT NULL DEFAULT '',
	people VARCHAR(32)NOT NULL DEFAULT '',
	`count` INT
);
ALTER TABLE `order2` ADD PRIMARY KEY(id);
SHOW KEYS FROM `order2`
SHOW KEYS FROM `order`

-- 要求:
-- 2.创建一张特价菜谱表menu(id号,菜谱名,厨师,点餐人身份证,价格).
-- 要求id号为主键,点餐人身份证是unique请使用两种方式来创建unique.
-- (提示:为练习方便,可以是menu1 , menu2)
CREATE TABLE menu1(
	id INT,
	menu_name VARCHAR(32),
	cook VARCHAR(32),
	id_card CHAR(18),
	price DOUBLE
);
ALTER TABLE menu1 ADD PRIMARY KEY(id);
CREATE UNIQUE INDEX id_card_index ON menu1(id_card);

-- 方式2
CREATE TABLE menu2(
	id INT,
	menu_name VARCHAR(32),
	cook VARCHAR(32),
	id_card CHAR(18),
	price DOUBLE
);
ALTER TABLE menu2 ADD PRIMARY KEY(id);
ALTER TABLE menu2 ADD UNIQUE INDEX (id_card);

SHOW KEYS FROM menu1
SHOW KEYS FROM menu2

-- 要求:
-- 3.创建一张运动员表sportman (id号,名字,特长).
-- 要求id号为主键,名字为普通索引,请使用三种方式来创建索引
-- (提示:为练习方便,可以是不同表名sportman1 , sportman2)
CREATE TABLE sportman(
	id INT PRIMARY KEY,
	`name` VARCHAR(32),
	`specialty` VARCHAR(32)
);
ALTER TABLE sportman ADD INDEX(`name`);
-- 方式2
CREATE TABLE sportman2(
	id INT PRIMARY KEY,
	`name` VARCHAR(32),
	`specialty` VARCHAR(32)
);
CREATE INDEX name_index ON sportman2(id);
SHOW KEYS FROM sportman
SHOW KEYS FROM sportman2

在这里插入图片描述

11、事务

·什么是事务
事务用于保证数据的一致性,它由一组相关的dml语句组成该组的dml语句要么全部成功,要么全部失败。
如:转账就要用事务来处理,用以保证数据的一致性。

在这里插入图片描述

-- 事务的一个重要的概念和具体探作--看一个图[看示意图]
-- 演示
-- 1.创建一张测试表
CREATE TABLE t27
( id INT,
`name`VARCHAR(32));
-- 2.开始事务
START TRANSACTION
-- 3.设置保存点
SAVEPOINT a
-- 执行dml
INSERT INTO t27 VALUES(1,'jack')
-- 3.设置保存点
SAVEPOINT b
-- 执行dml
INSERT INTO t27 VALUES(2,'tom')
SELECT * FROM t27
-- 回退到b
ROLLBACK TO b
-- 回退到a
ROLLBACK TO a
-- 回退到全部
ROLLBACK
-- 提交事务(结束事务)
COMMIT

在这里插入图片描述

隔离级别

事务隔离级别介绍
1.多个连接开启各自事务操作数据库中数据时,数据库系统要负
责隔离操作,以保证各个连接在获取数据时的准确性。(通俗解释)
2、如果不考虑隔离性,可能会引发如下问题:
脏读
不可重复读幻读

脏读(dirty read):当一个事务读取另一个事务尚未提交的修改时,产生脏读
不可重复读(nonrepeatable read):同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生不可重复读。
幻读(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻读。

在这里插入图片描述

SET SESSION TRANSACTION ISOLATION LEVEL 隔离级别

SET SESSION TRANSACTION ISOLATION LEVEL Repeatable read;

事务的acid特性
1.原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态
3.隔离性(lsolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
4.持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

12、引擎

在这里插入图片描述

在这里插入图片描述

13、视图

emp表的列信息很多,有些信息是个人重要信息(比如sal, commmgr, hiredate),如果我们希望某个用户只能查询emp表的(empno.ename, job和deptno )信息,有什么办法?

对视图的总结
1.视图是根据基本来创建的视图是虚拟的表2.视图也有列,数据来自基表
3.通过视图可以修改基表的数据
4.基本的改变,也会影响到视图的数据

 -- 创建视图
CREATE VIEW emp_viewO1
AS
SELECT empno, ename, job, deptno FROM emp;
--查看视图
DESC emp_view01
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值