MySQL数据库(5)

目录

多表查询

多表查询的本质

自连接

基本概念

子查询

基本概念

子查询练习

all和any

多列子查询

表复制


多表查询

多表查询说明

多表查询的条件不能少于 表的个数-1,否则会出现笛卡尔集

在我们进行多表查询的时候,难免的会发生笛卡尔集的情况发生,那么什么是笛卡尔集呢,笛卡尔集,就是我们在进行多表查询的时候,会产生许多重复的数据,如果两张表中的,有两个相同的字段,那么会导致许多重复,没用的数据,因此我们需要避免笛卡尔集的发生

多表查询的本质

在默认情况下:当两个表查询时,规则

1.从第一张表中,取出一行 和第二张表的每一行进行组合 , 返回结果[合有两张表的所有列].

2.一共返回的记录数 第一张表行数*第二张表的行数

3.这样多表查询默认处理返回的结果,称为笛卡尔集

4.解决这个多表的关键就是要与出正确的过滤条件 where,需要程序员进行分析

代码演示:

如果想要避免笛卡尔集的情况发生,在多表查询的最后我们需要使用where条件判断,这样查询出来的数据,才不会有笛卡尔集的情况发生

-- 多表查询
-- ?显示雇员名,雇员工资及所在部门的名字 【笛卡尔集】
/*
	分析
	1. 雇员名,雇员工资 来自 emp表
	2. 部门的名字 来自 dept表
	3. 需求对 emp 和 dept查询  ename,sal,dname,deptno
	4. 当我们需要指定显示某个表的列是,需要 表.列表
*/
SELECT ename,sal,dname,emp.deptno
	FROM emp, dept 
	WHERE emp.deptno = dept.deptno
	
SELECT * FROM emp;
SELECT * FROM dept;
SELECT * FROM salgrade;
-- 小技巧:多表查询的条件不能少于 表的个数-1, 否则会出现笛卡尔集
-- ?如何显示部门号为10的部门名、员工名和工资 
SELECT ename,sal,dname,emp.deptno
	FROM emp, dept 
	WHERE emp.deptno = dept.deptno AND emp.deptno = 10

-- ?显示各个员工的姓名,工资,及其工资的级别

-- 思路 姓名,工资 来自 emp 13
--      工资级别 salgrade 5
-- 写sql , 先写一个简单,然后加入过滤条件...
SELECT ename, sal, grade 
	FROM emp , salgrade
	WHERE sal BETWEEN losal AND hisal; 


#练习: 显示雇员名,雇员工资及所在部门的名字,并按部门排序[降序排].
SELECT ename,sal,dname
	FROM emp,dept
	WHERE emp.deptno=dept.deptno
	ORDER BY dname DESC
	
	SELECT * FROM emp
	SELECT * FROM dept


自连接

基本概念

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

使用通俗的说法来说,就是 ,也是多表查询,只不过把一张表看成两张不同的表,只不过是为同一张表起了两个不同的名字而已

代码演示:

注意在代码中的使用的是同一张表,只不过分别为表起了别的名字,分别是worker 和 boss 

-- 多表查询的 自连接

-- 思考题: 显示公司员工名字和他的上级的名字

--  员工名字 在emp, 上级的名字的名字 emp
-- 员工和上级是通过 emp表的 mgr 列关联
-- 这里小结:
-- 自连接的特点 1. 把同一张表当做两张表使用
--               2. 需要给表取别名 表名  表别名 
--		 3. 列名不明确,可以指定列的别名 列名 as 列的别名		
SELECT worker.ename AS '职员名' ,  boss.ename AS '上级名'
	FROM emp worker, emp boss
	WHERE worker.mgr = boss.empno;
	#根据emp表我们可以知道,员工的mgr表示的是该员工的上级因此只需要员工的mgr等于上级的empno即可
SELECT * FROM emp;

子查询

基本概念

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

代码演示:

-- 子查询的演示
-- 请思考:如何显示与SMITH同一部门的所有员工?
/*
	1. 先查询到 SMITH的部门号得到
	2. 把上面的select 语句当做一个子查询来使用
*/
SELECT deptno 
	FROM emp 
	WHERE ename = 'SMITH'

-- 下面的答案.	
SELECT * 
	FROM emp
	WHERE deptno = (
		SELECT deptno 
		FROM emp 
		WHERE ename = 'SMITH'
	)

-- 课堂练习:如何查询和部门10的工作相同的雇员的
-- 名字、岗位、工资、部门号, 但是不含10号部门自己的雇员.

/*
	1. 查询到10号部门有哪些工作
	2. 把上面查询的结果当做子查询使用
*/
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 
	

子查询练习

代码演示:

-- 查询ecshop中各个类别中,价格最高的商品

-- 查询 商品表
-- 先得到 各个类别中,价格最高的商品 max + group by cat_id, 当做临时表
-- 把子查询当做一张临时表可以解决很多很多复杂的查询

SELECT cat_id , MAX(shop_price) 
	FROM ecs_goods
	GROUP BY cat_id
	
	
-- 这个最后答案	
SELECT goods_id, ecs_goods.cat_id, goods_name, shop_price 
	FROM (
		SELECT cat_id , MAX(shop_price) AS max_price
		FROM ecs_goods
		GROUP BY cat_id
	) temp , ecs_goods
	WHERE  temp.cat_id = ecs_goods.cat_id 
	AND temp.max_price = ecs_goods.shop_price 

all和any

代码演示:

-- all 和 any的使用

-- 请思考:显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
#先查询部门号为30的所有员工的工资  在使用all操作符 all表示比我们查询出来中最大的工资还要大 工资的人
SELECT ename, sal, deptno
	FROM emp
	WHERE sal > ALL(
		SELECT sal 
			FROM emp
			WHERE deptno = 30
		) 
-- 可以这样写
SELECT ename, sal, deptno
	FROM emp
	WHERE sal > (
		SELECT MAX(sal) 
			FROM emp
			WHERE deptno = 30
		) 

-- 请思考:如何显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号

# any表示比最小的大就可以了
SELECT ename, sal, deptno
	FROM emp
	WHERE sal > ANY(
		SELECT sal 
			FROM emp
			WHERE deptno = 30
		)

 SELECT ename, sal, deptno
	FROM emp
	WHERE sal > (
		SELECT MIN(sal) 
			FROM emp
			WHERE deptno = 30
		)

多列子查询

代码演示:

-- 多列子查询

-- 请思考如何查询与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'



-- 请查询 和宋江数学,英语,语文   
-- 成绩 完全相同的学生
#先查询宋江的数学,英语,语文 成绩
SELECT math, english, chinese FROM student WHERE `name` = '宋江'

SELECT * 
	FROM student
	WHERE (math, english, chinese) = (SELECT math, english, chinese FROM student WHERE `name` = '宋江')

SELECT * FROM student;

表复制

表的复制会在一些的特定去情况下去使用,比如我们为了对某个sql语句进行效率测试,我们需要海量数据时,可以使用此法为表创建海量数据

代码演示:

-- 表的复制
-- 为了对某个sql语句进行效率测试,我们需要海量数据时,可以使用此法为表创建海量数据

#创建一张表
CREATE TABLE my_tab01 
	( id INT,
	  `name` VARCHAR(32),
	  sal DOUBLE,
	  job VARCHAR(32),
	  deptno INT);

#查看表的结构	  
DESC my_tab01
#查询表
SELECT * FROM my_tab01;

-- 演示如何自我复制
-- 1. 先把emp 表的记录复制到 my_tab01
#就是把emp表中的这些字段(empno, ename, sal, job, deptno) 插入到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;
SELECT COUNT(*) FROM my_tab01;

-- 如何删除掉一张表重复记录
-- 1. 先创建一张表 my_tab02, 
-- 2. 让 my_tab02 有重复的记录

CREATE TABLE my_tab02 LIKE emp; -- 这个语句 把emp表的结构(列),复制到my_tab02

DESC my_tab02;

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

CREATE TABLE my_tmp LIKE my_tab02
-- (2) 把my_tmp 的记录 通过 distinct 关键字 处理后 把记录复制到 my_tmp
INSERT INTO my_tmp 
	SELECT DISTINCT * FROM my_tab02;

-- (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;


+
SELECT * FROM my_tab02;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值