MySQL三部曲之渐入佳境
Posted Richard_i
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL三部曲之渐入佳境相关的知识,希望对你有一定的参考价值。
连接查询
-
什么是连接查询
- 在实际开发中,大部分的情况都不是从单表中查询数据,一般是多张表联合查询取出最终结果。
- 实际开发中,一般一个业务会对应多张表,如学生和班级,起码两张表。
stuno stuname classno classname ------------------------------------------------------------ 1 张三 1 深圳中学高三1班 2 李四 1 深圳中学高三1班
- 学生和班级信息存储到一张表中,数据会存在大量的重复,导致数据冗余。
连接查询的分类?
- 根据语法出现的年代划分,包括
- SQL92 (一些老的DBA可能还在用这种语法。DBA :Database Administrator 数据库管理员)
- SQL99 (比较新的语法)
- 根据表的连接方式划分,包括
- 内连接
- 等值连接
- 非等值连接
- 自连接
- 外连接
- 左外连接(左连接)
- 右外连接(右连接)
- 全连接(很少用,略!)
- 内连接
笛卡尔积现象
-
在表的连接查询方面有一种现象被称为:笛卡尔积现象(笛卡尔乘积现象)
-
笛卡尔积现象:当两张表进行连接查询时候,没有任何条件限制,最终的查询结果条数是两张表记录条数的乘积。
- 案例:找出每一个员工的部门名称,要求显示员工名和部门名。
mysql> select ename,dname from emp,dept; +--------+------------+ | ename | dname | +--------+------------+ | SMITH | ACCOUNTING | | SMITH | RESEARCH | | SMITH | SALES | | SMITH | OPERATIONS | | ALLEN | ACCOUNTING | | ALLEN | RESEARCH | | ALLEN | SALES | | ALLEN | OPERATIONS | ...... 56 rows in set (0.00 sec)
-
关于表的别名
- 表别名的好处?
- 执行效率高
- 可读性好
mysql> select e.ename, d.dname from emp e, dept d;
- 表别名的好处?
如何避免笛卡尔积现象?
-
加条件过滤;
- 避免了笛卡尔积现象,会减少记录的匹配次数吗?
- 不会!次数还是56次,只不过显示的是有效记录。
-
案例:找出每一个员工的部门名称,要求显示员工名和部门名。
mysql> select e.ename, d.dname from emp e , dept d -> where e.deptno = d.deptno; // SQL92,老语法,以后不用 +--------+------------+ | ename | dname | +--------+------------+ | CLARK | ACCOUNTING | | KING | ACCOUNTING | | MILLER | ACCOUNTING | | SMITH | RESEARCH | | JONES | RESEARCH | | SCOTT | RESEARCH | | ADAMS | RESEARCH | | FORD | RESEARCH | | ALLEN | SALES | | WARD | SALES | | MARTIN | SALES | | BLAKE | SALES | | TURNER | SALES | | JAMES | SALES | +--------+------------+ 14 rows in set (0.09 sec)
内连接之等值连接
-
最大的特点是:条件是等量关系。
- 案例:找出每一个员工的部门名称,要求显示员工名和部门名。
mysql> select e.ename, d.dname from emp e , dept d -> where e.deptno = d.deptno; // SQL 92,老语法,以后不用 (SQL 99) 常用的 mysql> select e.ename, d.dname from emp e -> join dept d -> on d.deptno = e.deptno; //内连接中的 inner 可以省略,带着 inner 目的是可读性好一些 mysql> select e.ename, d.dname from emp e -> inner join dept d -> on d.deptno = e.deptno; 语法格式: ... A join B on 连接条件 where... //还可加 where 过滤
- SQL99的语法更加清晰一些,表的连接条件和where条件分离了
内连接之非等值连接
-
最大的特点是:连接条件中的关系是非等量关系。
- 案例:找出每个员工的工资等级,要求显示员工名、工资、工资等级。
// inner 可以省略 mysql> select e.ename, e.sal , s.grade from emp e -> join salgrade s on e.sal between s.losal and s.hisal; +--------+---------+-------+ | ename | sal | grade | +--------+---------+-------+ | SMITH | 800.00 | 1 | | ALLEN | 1600.00 | 3 | | WARD | 1250.00 | 2 | | JONES | 2975.00 | 4 | | MARTIN | 1250.00 | 2 | | BLAKE | 2850.00 | 4 | | CLARK | 2450.00 | 4 | | SCOTT | 3000.00 | 4 | | KING | 5000.00 | 5 | | TURNER | 1500.00 | 3 | | ADAMS | 1100.00 | 1 | | JAMES | 950.00 | 1 | | FORD | 3000.00 | 4 | | MILLER | 1300.00 | 2 | +--------+---------+-------+ 14 rows in set (0.00 sec)
自连接
-
最大的特点是:一张表看做两张表,自己连接自己。
- 案例:找出每个员工的上级领导,要求显示员工名和对应的领导名字。
mysql> select a.ename as '员工', b.ename as '领导' -> from emp a -> join emp b -> on a.mgr = b.empno; (员工的领导编号 = 领导的员工编号) +--------+-------+ | 员工 | 领导 | +--------+-------+ | SMITH | FORD | | ALLEN | BLAKE | | WARD | BLAKE | | JONES | KING | | MARTIN | BLAKE | | BLAKE | KING | | CLARK | KING | | SCOTT | JONES | | TURNER | BLAKE | | ADAMS | SCOTT | | JAMES | BLAKE | | FORD | JONES | | MILLER | CLARK | +--------+-------+ 13 rows in set (0.06 sec)
外连接
-
什么是外连接?和内连接有什么区别?
-
内连接:假设A和B表进行连接,使用内连接的话,凡是A表和B表能够匹配上的记录查询出来,这就是内连接。
-
A表和B表没有主副之分,两张表是平等的。
- 外连接:假设A和B表进行连接,使用外连接的话,AB两张表中有一张表是主表,一张是副表,主要查询主表 中的数据,连带着查询副表,当副表中的数据没有和主表的数据匹配上,副表自动模拟出null与之匹配。
-
外连接的分类
-
左外连接:(左连接):表示左边的这张表是主表
-
右外连接:(右连接):表示右边的这张表是主表
-
左连接有右连接的写法,右连接也会有对应的左连接的写法。
-
全连接,省
内连接: mysql> select a.ename as '员工', b.ename as '领导' -> from emp a -> join emp b -> on a.mgr = b.empno; (员工的领导编号 = 领导的员工编号) 外连接: (左边表是主表,此时king也显示出来,模拟出null) left / right outer 可以省略 mysql>select a.ename as '员工', b.ename as '领导' -> from emp a -> left outer join emp b -> on a.mgr = b.empno; +--------+-------+ | ename | ename | +--------+-------+ | SMITH | FORD | | ALLEN | BLAKE | | WARD | BLAKE | | JONES | KING | | MARTIN | BLAKE | | BLAKE | KING | | CLARK | KING | | SCOTT | JONES | | KING | NULL | | TURNER | BLAKE | | ADAMS | SCOTT | | JAMES | BLAKE | | FORD | JONES | | MILLER | CLARK | +--------+-------+ 14 rows in set (0.00 sec)
-
案例:找出没有员工的部门
mysql> select d.* from emp e -> right outer join -> dept d -> on e.deptno = d.deptno -> where e.deptno is null; +--------+------------+--------+ | DEPTNO | DNAME | LOC | +--------+------------+--------+ | 40 | OPERATIONS | BOSTON | +--------+------------+--------+ 1 row in set (0.04 sec)
三张表连接
-
案例:找出每一个员工的部门名称以及工资等级。
表示A表和B表现进行表连接,连接之后A表继续和C表进行连接。 mysql> select e.ename, d.dname, e.sal, s.grade -> from emp e -> join dept d -> on d.deptno = e.deptno -> join salgrade s -> on e.sal between s.losal and s.hisal; +--------+------------+---------+-------+ | ename | dname | sal | grade | +--------+------------+---------+-------+ | SMITH | RESEARCH | 800.00 | 1 | | ALLEN | SALES | 1600.00 | 3 | | WARD | SALES | 1250.00 | 2 | | JONES | RESEARCH | 2975.00 | 4 | | MARTIN | SALES | 1250.00 | 2 | | BLAKE | SALES | 2850.00 | 4 | | CLARK | ACCOUNTING | 2450.00 | 4 | | SCOTT | RESEARCH | 3000.00 | 4 | | KING | ACCOUNTING | 5000.00 | 5 | | TURNER | SALES | 1500.00 | 3 | | ADAMS | RESEARCH | 1100.00 | 1 | | JAMES | SALES | 950.00 | 1 | | FORD | RESEARCH | 3000.00 | 4 | | MILLER | ACCOUNTING | 1300.00 | 2 | +--------+------------+---------+-------+ 14 rows in set (0.00 sec)
-
案例:找出每一个员工的部门名称以及工资等级、以及上级领导。
select e.ename '员工' , d.dname '部门名称',e.sal '工资',s.grade '工资等级', g.ename '领导' from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between losal and hisal left join emp g on e.mgr = g.empno; // 员工的领导编号=领导的员工编号(左外连接,自连接)
子查询
-
什么是子查询?子查询都可以出现在哪里?
- select语句当中嵌套select语句,被嵌套的select语句是子查询。
- 子查询出现在哪里?
select ...(select) from ... (select) where... (select)
where 子句中使用子查询
找出高于平均工资的员工信息
mysql> select * from emp where sal > (select avg(sal) from emp);
from后面嵌套查询
- from后面跟的是表,嵌套查询的结果被当成一个表
找出每个部门平均薪水的薪资等级
第一步找出部门平均工作
mysql> select deptno,avg(sal) from emp group by deptno; //每个部门平均薪水
+--------+-------------+
| deptno | avg(sal) |
+--------+-------------+
| 10 | 2916.666667 |
| 20 | 2175.000000 |
| 30 | 1566.666667 |
+--------+-------------+
3 rows in set (0.00 sec)
将以上查询结果当做一个临时表t,让t表和salgrade s 表做连接,条件是:on t.avgsal between s.losal and s.hisal;
-------------------------------------------------------------------
select t.*, s.grade
from (select deptno, avg(sal) as avgsal from emp group by deptno) t
join salgrade s
on t.avgsal between s.losal and s.hisal;
--------------------------------------------------------------------
+--------+-------------+-------+
| deptno | avgsal | grade |
+--------+-------------+-------+
| 10 | 2916.666667 | 4 |
| 20 | 2175.000000 | 4 |
| 30 | 1566.666667 | 3 |
+--------+-------------+-------+
3 rows in set (0.00 sec)
找出每个部门平均的薪水等级。
第一步: 找出每个员工的薪水等级。
mysql> select e.deptno, e.ename, e.sal, s.grade
-> from emp e
-> join salgrade s
-> on e.sal between s.losal and hisal;
+--------+--------+---------+-------+
| deptno | ename | sal | grade |
+--------+--------+---------+-------+
| 20 | SMITH | 800.00 | 1 |
| 30 | ALLEN | 1600.00 | 3 |
| 30 | WARD | 1250.00 | 2 |
| 20 | JONES | 2975.00 | 4 |
| 30 | MARTIN | 1250.00 | 2 |
| 30 | BLAKE | 2850.00 | 4 |
| 10 | CLARK | 2450.00 | 4 |
| 20 | SCOTT | 3000.00 | 4 |
| 10 | KING | 5000.00 | 5 |
| 30 | TURNER | 1500.00 | 3 |
| 20 | ADAMS | 1100.00 | 1 |
| 30 | JAMES | 950.00 | 1 |
| 20 | FORD | 3000.00 | 4 |
| 10 | MILLER | 1300.00 | 2 |
+--------+--------+---------+-------+
14 rows in set (0.06 sec)
第二步:基于以上结果,继续按照deptno分组,求grade平均值
mysql> select e.deptno , avg(s.grade)
-> from emp e
-> join salgrade s
-> on e.sal between s.losal and hisal
-> group by e.deptno;
+--------+--------------+
| deptno | avg(s.grade) |
+--------+--------------+
| 10 | 3.6667 |
| 20 | 2.8000 |
| 30 | 2.5000 |
+--------+--------------+
3 rows in set (0.00 sec)
在select后面嵌套子查询
-
案例:找出每个员工所在的部门名称,要求显示员工名和部门名。
mysql> select e.ename,d.dname from -> emp e -> join dept d -> on e.deptno = d.deptno; -------------------------------------------------------------------------- mysql> select e.ename, -> (select d.dname from dept d where e.deptno = d.deptno) as dname -> from emp e;
union
-
union 可以将查询结果集相加
-
特点:第一个查询的列的数量和第二个查询的列数量要一致
-
可将两张不想干的表中的数据拼接在一起显示
-
案例:找出工作岗位是SALESMAN和MANAGER的员工
第一种: mysql> select ename,job from emp where job ='salesman' or job = 'manager'; 第二种: mysql> select ename,job from emp where job in('manager','salesman'); 第三种: mysql> select ename,job from emp where job = 'manager' -> union -> select ename,job from emp where job = 'salesman'; +--------+----------+ 可将两张不想干的表中的数据拼接在一起显示 mysql> select ename from emp -> union -> select dname from dept; +------------+ | ename | +------------+ | SMITH | | ALLEN | | WARD | | JONES | | MARTIN | | BLAKE | | CLARK | | SCOTT | | KING | | TURNER | | ADAMS | | JAMES | | FORD | | MILLER | | ACCOUNTING | | RESEARCH | | SALES | | OPERATIONS | +------------+ -------------------------------------------------------------- 第一个查询的列的数量和第二个查询的列数量要一致,否则报错 mysql> select ename , sal from emp -> union -> select dname from dept; ERROR 1222 (21000): The used SELECT statements have a different number of columns
limit (重点)
-
limit是MySQL特有的,其他数据库没有,不通用(Oracle中有一个相同的机制,叫做 rownum)
-
limit取结果集中的部分数据,这是它的作用。
-
语法机制:limit starIndex, length
- starIndex : 表示起始位置
- length :表示取几个
-
案例:取出工资前五名的员工(思路:降序取前五个)
mysql> select ename,sal from emp order by sal desc; // 取前五个 mysql> select ename,sal from emp order by sal desc limit 0,5; // 直接写一个数字,前面默认的是0 mysql> select ename,sal from emp order by sal desc limit 5;
-
limit 是SQL语句最后执行的一个环节
执行顺序 select... 5 from... 1 where... 2 group by... 3 having... 4 order by... 6 limit...; 7
-
案例:找出工资排名在第4到第9名的员工
mysql> select ename,sal from emp order by sal desc limit 3,6; +--------+---------+ | ename | sal | +--------+---------+ | JONES | 2975.00 | | BLAKE | 2850.00 | | CLARK | 2450.00 | | ALLEN | 1600.00 | | TURNER | 1500.00 | | MILLER | 1300.00 |<
以上是关于MySQL三部曲之渐入佳境的主要内容,如果未能解决你的问题,请参考以下文章