MySQL系列——连接、子查询、union合并、limit

8 连接查询

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

emp表和dopt表联合起来查询数据,从emp表中取员工名字,从dopt表中取部门名字。
这种跨表查询,多张表联合起来查询数据,被称为连接查询。

#根据语法的年代分类:
SQL92:1992年的时候出现的语法
SQL99:1999年的时候出现的语法
我们这里重点学习SQL99.(这个过程中简单演示一个SQL92的例子)

#根据表连接的方式分类:
内连接: 等值连接 非等值连接 自连接
外连接: 左外连接(左连接)    右外连接(右连接)
全连接:

8.1 笛卡尔积现象

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

如何避免笛卡尔积现象:
连接时加条件,满足这个条件的记录被筛选出来!(并不能减少表的匹配次数,只是查询出的结果变少了)

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

思考:最终查询的结果条数是14条,但是匹配的过程中,匹配的次数减少了吗?
还是56次,只不过进行了四选一。次数没有减少。

8.2 内连接:等值连接

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
    join
        dept d
    on
        e.deptno = d.deptno;

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

SQL99语法格式:
  from
    a
  inner join
  #inner可以省略
    b
  on
    a和b的连接条件
  where
    筛选条件

inner可以省略(带着inner可读性更好!!!一眼就能看出来是内连接)

8.3 内连接:非等值连接

select 
    e.ename, e.sal, s.grade
from
    emp e
join
    salgrade s
on
    e.sal between s.losal and s.hisal; // 条件不是一个等量关系,称为非等值连接。

8.4 内连接:自连接

select 
    a.ename as '员工名', b.ename as '领导名'
from
    emp a
join
    emp b
on
    a.mgr = b.empno; //员工的领导编号 = 领导的员工编号
以上就是内连接中的:自连接,技巧:一张表看做两张表

8.5 外连接

// outer是可以省略的,带着可读性强。
select 
    e.ename,d.dname
from
    emp e 
right outer join 
    dept d
on
    e.deptno = d.deptno;

1)right代表什么?

    表示将join关键字右边的这张表看成主表,主要是为了将这张表的数据全部查询出来,捎带着关联查询左边的表。在外连接当中,两张表连接,产生了主次关系。

带有right的是右外连接,又叫做右连接。
带有left的是左外连接,又叫做左连接。
任何一个右连接都有左连接的写法。
任何一个左连接都有右连接的写法。

2)外连接的查询结果条数一定是 >= 内连接的查询结果条数

3)三张表,四张表怎么连接?

语法:
  select 
    ...
  from
    a
  join
    b
  on
    a和b的连接条件
  join
    c
  on
    a和c的连接条件
  right join
    d
  on
    a和d的连接条件

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

9 子查询

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

子查询都可以出现在哪里呢?
select
  ..(select).
from
  ..(select).
where
  ..(select).

9.1 where子句中的子查询:

第一步:查询最低工资是多少
  select min(sal) from emp;
  +----------+
  | min(sal) |
  +----------+
  |   800.00 |
  +----------+

第二步:找出>800的
  select ename,sal from emp where sal > 800;

第三步:合并
  select ename,sal from emp where sal > (select min(sal) from emp);

9.2 from子句中的子查询:

**注意:from后面的子查询,可以将子查询的查询结果当做一张临时表。**
案例:找出每个岗位的平均工资的薪资等级。

    第一步:找出每个岗位的平均工资(按照岗位分组求平均值)
        select job,avg(sal) from emp group by job;
        +-----------+-------------+
        | job       | avgsal      |
        +-----------+-------------+
        | ANALYST   | 3000.000000 |
        | CLERK     | 1037.500000 |
        | MANAGER   | 2758.333333 |
        | PRESIDENT | 5000.000000 |
        | SALESMAN  | 1400.000000 |
        +-----------+-------------+  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;

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

        +-----------+-------------+-------+
        | job       | avgsal      | grade |
        +-----------+-------------+-------+
        | CLERK     | 1037.500000 |     1 |
        | SALESMAN  | 1400.000000 |     2 |
        | ANALYST   | 3000.000000 |     4 |
        | MANAGER   | 2758.333333 |     4 |
        | PRESIDENT | 5000.000000 |     5 |
        +-----------+-------------+-------+

9.3 select后面出现的子查询:

(这个内容不需要掌握,了解即可!!!)

案例:找出每个员工的部门名称,要求显示员工名,部门名?
    select 
        e.ename,e.deptno,(select d.dname from dept d where e.deptno = d.deptno) as dname 
    from 
        emp e;

    +--------+--------+------------+
    | ename  | deptno | dname      |
    +--------+--------+------------+
    | SMITH  |     20 | RESEARCH   |
    | ALLEN  |     30 | SALES      |
    | WARD   |     30 | SALES      |
    | JONES  |     20 | RESEARCH   |
    | MARTIN |     30 | SALES      |
    | BLAKE  |     30 | SALES      |
    | CLARK  |     10 | ACCOUNTING |
    | SCOTT  |     20 | RESEARCH   |
    | KING   |     10 | ACCOUNTING |
    | TURNER |     30 | SALES      |
    | ADAMS  |     20 | RESEARCH   |
    | JAMES  |     30 | SALES      |
    | FORD   |     20 | RESEARCH   |
    | MILLER |     10 | ACCOUNTING |
    +--------+--------+------------+

    //错误:ERROR 1242 (21000): Subquery returns more than 1 row
    select 
        e.ename,e.deptno,(select dname from dept) as dname
    from
        emp e;

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

10 union合并

案例:查询工作岗位是MANAGER和SALESMAN的员工?
select ename,job from emp where job = 'MANAGER' or job = 'SALESMAN';
select ename,job from emp where job in('MANAGER','SALESMAN');
+--------+----------+
| ename  | job      |
+--------+----------+
| ALLEN  | SALESMAN |
| WARD   | SALESMAN |
| JONES  | MANAGER  |
| MARTIN | SALESMAN |
| BLAKE  | MANAGER  |
| CLARK  | MANAGER  |
| TURNER | SALESMAN |
+--------+----------+

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

+--------+----------+
| ename  | job      |
+--------+----------+
| JONES  | MANAGER  |
| BLAKE  | MANAGER  |
| CLARK  | MANAGER  |
| ALLEN  | SALESMAN |
| WARD   | SALESMAN |
| MARTIN | SALESMAN |
| TURNER | 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';

11 limit

limit作用:将查询结果集的一部分取出来。通常使用在分页查询当中。
百度默认:一页显示10条记录。
分页的作用是为了提高用户的体验,因为一次全部都查出来,用户体验差。可以一页一页翻页看

limit完整用法:limit startIndex, length
startIndex是起始下标,length是长度。
起始下标从0开始。

缺省用法:limit 5; 这是取前5

注意:mysql当中limit在order by之后执行!!!!!!

分页
每页显示3条记录
第1页:limit 0,3        [0 1 2]
第2页:limit 3,3        [3 4 5]
第3页:limit 6,3        [6 7 8]
第4页:limit 9,3        [9 10 11]

有0,substr没有0
每页显示pageSize条记录
第pageNo页:limit (pageNo - 1) * pageSize , pageSize

public static void main(String[] args){
  // 用户提交过来一个页码,以及每页显示的记录条数
  int pageNo = 5; //第5页
  int pageSize = 10; //每页显示10条

  int startIndex = (pageNo - 1) * pageSize;
  String sql = "select ...limit " + startIndex + ", " + pageSize;
}

记公式:
limit (pageNo-1)*pageSize , pageSize

关于DQL语句的大总结:
select 
  ...
from
  ...
where
  ...
group by
  ...
having
  ...
order by
  ...
limit
  ...

执行顺序?
  1.from
  2.where
  3.group by
  4.having
  5.select
  6.order by
  7.limit..
全部评论
都是mysql的核心啊,感谢分享
点赞 回复 分享
发布于 2022-08-14 13:44

相关推荐

点赞 评论 收藏
分享
迷茫的大四🐶:💐孝子启动失败,改为启动咏鹅
点赞 评论 收藏
分享
评论
点赞
6
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务