学习MySQL-第五章

目录

21,去除重复记录

22,连接查询

22.1什么是连接查询

22.2连接查询的分类

22.3当两张表进行连接查询时,没有任何条件的限制会发生什么现象?

22.4怎么避免笛卡尔积现象?

22.5内连接之等值连接

22.6内连接之非等值连接

22.7内连接之自连接

22.8外连接

22.9三张表,四张表怎么连接?

 23,子查询

23.1什么是子查询

23.2子查询都可以出现在哪里

23.3where子句中的子查询

23.4from子句中的子查询

23.5select后面出现的子查询(这个内容不需要掌握,了解即可!)

24,union合并查询结果集


21,去除重复记录

注意:原表数据不会被修改,只是查询结果去重

去重需要使用一个关键字:distinct

mysql> select distinct job from emp;

+-------------------+

| job                  |

+-------------------+

| CLERK            |

| SALESMAN    |

| MANAGER     |

| ANALYST        |

| PRESIDENT   |

+--------------------+

mysql> select ename,distinct job from emp;

这样写是错误的,语法错误

distinct只能出现在所有字段的最前方

//distinct出现在job,deptno两个字段之前,表示两个字段联合起来去重

mysql> select distinct job,deptno from emp;

+---------------------+-----------+

| job                    | deptno   |

+--------------------+------------+

| CLERK           |     20       |

| SALESMAN    |     30       |

| MANAGER     |     20       |

| MANAGER     |     30       |

| MANAGER     |     10       |

| ANALYST       |     20       |

| PRESIDENT  |     10       |

| CLERK           |     30      |

| CLERK           |     10       |

+-------------------+------------+

例:统计一下工作岗位的数量

mysql> select count(distinct job) from emp;

+---------------------------------+

| count(distinct job)             |

+---------------------------------+

|                   5                    |

+---------------------------------+

distinct只能出现在所有字段的前方,但是可以用分组函数

22,连接查询

22.1什么是连接查询

从一张表中单独查询,称为单表查询

emp表和dept表联合起来查询数据,从emp表中取员工名字,从detp表中取部 门名字

这种跨表查询,多张表联合起来查询数据,被称为连接查询

22.2连接查询的分类

根据语法的年代分类

SQL92:1992年的时候出现的语法

SQL99:1999年的时候出现的语法

这里重点学习SQL99,这个过程简单演示一下SQL92的例子

根据表连接的方式分类

  • 内连接
  • 等值连接
  • 非等值连接
  • 自连接
  • 外连接
  • 左外连接(左连接)
  • 右外连接(右连接)
  • 全连接(不讲)

22.3当两张表进行连接查询时,没有任何条件的限制会发生什么现象?

例:查询每个员工所在部门名称?

 

mysql> select ename,dname from emp,dept;

这样会有14*4=56条记录

注意:

当两张表进行连接查询,没有任何条件限制的时候,最终查询结果条数,是两张表条数的乘积,这种现象被称为:笛卡尔现象。(笛卡尔发现的,这是一个数学现象。)

22.4怎么避免笛卡尔积现象?

连接时加条件,满足这个条件的记录被筛选出来!

mysql> select ename,dname from emp,dept where emp.deptno=dept.deptno;

 

上面的查询还是比较费时的,还有更简洁的做法,就是在select的字段前面加上表明限定,另外结合起别名就可以提高效率

//表起别名,很重要

mysql> select e.ename,d.dname from emp e,dept d where e.deptno=d.deptno;//SQL92 语法

 

 思考:最终查询的结果条数是14条,但是匹配的过程中,匹配的次数减少了吗?

没有,还是56次,只不过进行了四选一,次数没有减少

注意:通过笛卡尔积现象得出,表的连接次数越多效率越低,尽量避免表连接的次数

22.5内连接之等值连接

例:查询每个员工所在的部门名称,显示员工名和部门名?

emp e和dept d表进行连接。条件是:e.deptno=d.deptno

SQL92语法:

select

        e.ename,d.dname

from

        emp e,dept d

where

        e.deptno=d.deptno;

SQL92的缺点:

结构不清晰,表的连接条件和后期进一步筛选的条件,都放到了where 后面

SQL99语法:

select

        e.ename,d.dname

from

        emp e

(inner) join

        dept d

on

        e.deptno=d.deptno;

注:inner可以省略,带着inner可读性更好,一眼就能看出是内连接

SQL99的优点:

表连接的条件是独立的,连接之后,如果还需要进一步筛选,再往后继续 添加where

SQL99语法:

select

        ...

from

        a

join

        b

on

        a和b连接条件

where

        筛选条件

22.6内连接之非等值连接

例:找出每个员工的薪资等级,要求显示员工名,薪资,薪资等级?

select

        e.ename,e.sal,s.grade

from

        emp e

join

        salgrade s

on

        e.sal between s.losal and s.hisal;//条件不是一个等量关系,称为非等值连接

22.7内连接之自连接

例:查询员工的上级领导,要求显示员工名和对应的领导名

mysql> select empno,ename,mgr from emp;

技巧:一张表看成两张表

mysql> select a.ename as '员工名',b.ename as '领导名' from emp a join emp b on a.mgr=b.empno;//员工的领导编号=领导的员工编号

 以上就是内连接中的自连接,技巧:一张表看成两张表

22.8外连接

例:查询员工的名称与对应的岗位

内连接(A和B连接,AB两张表没有主次关系,平等的):

mysql> select e.ename,d.dname from emp e join dept d on e.deptno=d.deptno;

 内连接的特点:完成能够匹配上这个条件的数据查询出来

内连接是通过deptno把emp表和dept表连接起来,查询dept表和emp表deptno 相同的记录,但是如果要把dept表和emp表中的deptno不匹配的也找出来就要 用到外连接了

外连接(右外连接):

mysql> select e.ename,d.dname from emp e right join dept d on e.deptno=d.deptno;//在join前面加上right

外连接(左外连接)

mysql> select e.ename,d.dname from dept d left join emp e on e.deptno=d.deptno;//join前面加上left

带有right的是右外连接,又叫右连接

带有left的是左外连接,又叫左连接

任何一个右连接都有左连接的写法

任何一个左连接都有右连接的写法

right代表什么:表示将join关键字右边的这张表看成主表,主要是为了将这张表 的数据全部查询出来,捎带着关联查询左边的表

left代表什么:和right一样,表示将join左边的表看成主表

在外连接中,两张表连接产生了主次关系

join前面也可以加上outer,outer是可以省略的,上面就省略了,带着可读性强, 表示是外连接

注意:外连接的查询结果条数一定是>=内连接的查询结果条数

例:查询每个员工的上级领导,要求显示所有员工的名字和领导名

mysql> select a.ename as '员工名',b.ename as '领导名' from emp a left join emp b on a.mgr=b.empno;

22.9三张表,四张表怎么连接?

语法:

select

        ...

from

        a

join

        b

on

        a和b的连接条件

join

        c

on

        a和c的连接条件

right join

        d

on

        a和d的连接条件

一条SQL中内连接和外连接可以混合,都可以出现!

例:找出每个员工的部门名称以及工资等级,要求显示员工名,部门名,薪资,薪资等级

mysql> select e.ename,e.sal,d.deptno,s.grade from emp e join dept d on e.deptno=d.deptno join salgrade s on e.sal between s.losal and s.hisal;

 例:找出每个员工的部门名称以及工资等级,还有上级领导,要求显示员工名,领 导名,部门名,薪资,薪资等级

mysql> select e.ename,e.sal,d.deptno,s.grade,l.ename as '上级领导' from emp e join dept d on e.deptno=d.deptno join salgrade s on e.sal between s.losal and s.hisal left join emp l on e.mgr=l.empno;

 23,子查询

23.1什么是子查询

select语句中嵌套select语句,被嵌套的select语句被称为子查询

23.2子查询都可以出现在哪里

select

        ...(select).

from

        ...(select).

where

        ...(select).

23.3where子句中的子查询

例:找出比最低工资高的员工姓名和工资?

mysql> select ename,sal from emp where sal>min(sal);

这样写不行,因为where子句中不能直接使用分组函数

实现思路:

第一步:查询最低工资是多少

mysql> select min(sal) from emp;

+---------------+

| min(sal)     |

+--------------+

|   800.00      |

+---------------+

第二步:找出>800的

mysql> select ename,sal from emp where sal>800;

第三步:合并

mysql> select ename,sal from emp where sal>(select min(sal) from emp);

23.4from子句中的子查询

注意:from后面的子查询,可以将子查询的查询结果当做一张临时表(技巧)

例:找出每个岗位的平均工资的薪资等级

第一步:找出每个岗位的平均工资(按照岗位分组求平均值)

mysql> select avg(sal),job from emp group by job;

+-------------------+-------------------+

| avg(sal)          | job                  |

+-------------------+-------------------+

| 1037.500000 | CLERK            |

| 1400.000000 | SALESMAN    |

| 2758.333333 | MANAGER     |

| 3000.000000 | ANALYST        |

| 5000.000000 | PRESIDENT   |

+-------------------+-------------------+

                 t表

第二步:把以上的查询结果就当做一张真实存在的表t

mysql> select * from salgrade;//s表

+-----------+---------+------------+

| GRADE | LOSAL | HISAL  |

+-----------+---------+-----------+

|     1        |   700  |  1200    |

|     2        |  1201 |  1400    |

|     3        |  1401 |  2000    |

|     4        |  2001 |  3000    | 

|     5        |  3001 |  9999    |

+-----------+---------+----------+

t表和s表进行表连接,条件:t表avg(sal) between s.losal and s.hisal;

mysql> select t.*,s.grade from (select avg(sal) as avgsal,job from emp group by job) as t join salgrade s on t.avgsal between s.losal and s.hisal;

23.5select后面出现的子查询(这个内容不需要掌握,了解即可!)

例:找出每个员工的部门名称,要求显示员工名,部门名?

mysql> select e.ename,(select d.dname from dept d where e.deptno=d.deptno) as dname from emp e;

//报错:ERROR 1242 (21000): Subquery returns more than 1 row

mysql> select e.ename,e.deptno,(select dname from dept) as dname from emp e;

注意:对于select后面的子查询来说,这个子查询只能一次返回1条结果,多于1 条,就报错了!

24,union合并查询结果集

例:查询工作岗位是MANAGER和SALESMAN的员工

mysql> select ename,job from emp where job='MANAGER' or job='SALESMAN';

下面用union实现

mysql> select ename,job from emp where job='MANAGER' union select ename,job from emp where job='SALESMAN';

 

 union的效率要高一些。对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔 积,成倍的翻。。。

但是union可以减少匹配的次数,在减少匹配次数的情况下,还可以完成两个结果集的拼接

a连接b连接c

a 10条记录

b 10记录

c 10条记录

匹配次数:1000

a连接b一个结果:10*10 -->100次

a连接c一个结果:10*10 -->100次

使用union的话是:100次+100次=200次(union把乘法变成了加法运算)

union在使用的时候有注意事项吗?

//错误的:union在进行结果集合并的时候,要求两个结果集的列数相同

select ename,job from emp where job='MANAGER'

union

select ename from emp where job='SALESMAN';

//mysql可以,oracle语法严格,不可以,报错。

//要求:结果集合并时列和列的数据类型也要一致

select ename,job from emp where job='MANAGER'

union

select ename,sal from emp where job='SALESMAN';

猜你喜欢

转载自blog.csdn.net/qq_52905520/article/details/126841692