MySQL三部曲之渐入佳境

Posted Richard_i

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL三部曲之渐入佳境相关的知识,希望对你有一定的参考价值。

连接查询

  • 什么是连接查询

    • 在实际开发中,大部分的情况都不是从单表中查询数据,一般是多张表联合查询取出最终结果。
    • 实际开发中,一般一个业务会对应多张表,如学生和班级,起码两张表。
    stuno    stuname		classno			classname
    ------------------------------------------------------------
    1		 张三				1				深圳中学高三12		 李四				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)
    
  • 关于表的别名

    • 表别名的好处?
      1. 执行效率高
      2. 可读性好
    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也显示出来,模拟出nullleft / 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三部曲之渐入佳境的主要内容,如果未能解决你的问题,请参考以下文章

    企业主流MySQL高可用集群架构三部曲之PXC

    编译安装lamp三部曲之mysql-技术流ken

    MySQL三部曲之初见端倪

    MySQL三部曲之初见端倪

    企业中MySQL高可用集群架构三部曲之MM+keepalived

    企业中MySQL主流高可用架构实战三部曲之MHA