Mysql之数据查询DQL

学习目的

  1. 掌握Mysl常用的查询语句
  2. 掌握数据查询在实际开发中的应用

一.Mysql数据查询(DQL)

  1. DQL概念
    DQL全称Data Query Language,意为数据查询语言。在数据库学习中,最重要的就是查询语句,因为数据库中的数据就是通过各种查询操作展示给用户。
  2. 特点
    DQL最重要的语句是select语句
  3. 语法格式
    select 字段名1,字段名2,字段名3,.... from 表名;
  4. 注意点
  • 实际开发中不建议使用 select *,效率较低(原因是在底层会将*号先转换为所有字段再去查询,不如直接写出字段去查询)
  • SQL语句中不区分大小写(Windows系统中不区分,但Linux中区分);
  • 理清每一个查询语句的执行顺序,通过分步查询,有利于理解查询的执行原理以及调试。

1.1 简单查询

  1. 查询单个字段
    select 字段名 from 表名;

  2. 查询多个字段
    select 字段名1,字段名2,字段名3,.... from 表名;

  3. 查询某个字段 乘倍数之后的结果(字段可以参与数学运算)
    select 字段名1,字段名2 *倍数, from 表名;

  4. 给查询的某个字段运算后 重新命名(as关键字)

  • 英文名:select 字段名1,字段名2 *倍数 as newName from 表名;
  • 中文名格式:select 字段名1,字段名2 *倍数 as '中文名' from 表名;
mysql> select * from emp;  //
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+

mysql> select ename,sal as month,sal*12 as year from emp;  //英文重命名
+--------+---------+----------+
| ename  | month   | year     |
+--------+---------+----------+

mysql> select ename,sal as '月薪',sal*12 as '年薪' from emp;  //中文重命名
+--------+---------+----------+
| ename  | 月薪    | 年薪     |
+--------+---------+----------+

1.2 条件查询

  1. 语法格式
    select 
      字段1,字段2,字段3...
    from
      表名
    where
      条件(字段名 = 字段数据);
  1. 执行顺序
  • 先执行from:先明确从哪个位置(哪个表中)查询数据;
  • 其次是where:明确查询的表后,需要确定查找的具体条件(一般是根据给定具体值的字段来查找);
  • 最后是select:根据具体的条件"索引"到表中,查询满足条件的数据。
  1. 条件查询运算符
运算符 运算符描述
= 等于
<>或!= 不等于
< 小于
<= 小于等于
> 大于
>= 大于等于
between … and …. 两个值之间,等同于 >= and <=
is null 为null(is not null 不为空)
and 并且
or 或者
in 包含,相当于多个or(not in不在这个范围中)
not 取非,主要用于is not null 或 not in中
like 模糊查询,支持%或下划线匹配;%匹配任意个字符,一个下划线只匹配一个字符
  1. 注意点
  • 查找某个区段之间的数据:可以使用大于小于<>号,也可以使用between and符号(闭区间),但是between and必须小范围在前,大范围在后;
  • NULL:在数据库中的NULL并不是一个值(空值),只是一个标记代表该字段没有数据,因此判断一个字段是否为空不能使用 =号,而是使用运算符 is NULL 和 is not NULL

1.2.1 and 和 or优先级

  1. 优先级
    and运算符or运算符同时出现时,and优先级高于or优先级,但是对于多个运算符同时出现(且优先级不确定时),应该使用小括号()将每一部分的运算符括起来。
  2. 代码示例
mysql> select ename,sal,deptno from emp where sal > 1000 and deptno = 20 or deptno = 30;
+--------+---------+--------+
| ename  | sal     | deptno |
+--------+---------+--------+
| TURNER | 1500.00 |     30 |
| ADAMS  | 1100.00 |     20 |
| JAMES  |  950.00 |     30 |
| FORD   | 3000.00 |     20 |
+--------+---------+--------+
4 rows in set (0.01 sec)  //查找出 4条数据结果,有一个工资等于950 select ename,sal,deptno from emp where sal>1000 and (deptno=20 or deptno=30);
+--------+---------+--------+
| ename  | sal     | deptno |
+--------+---------+--------+
| TURNER | 1500.00 |     30 |
| ADAMS  | 1100.00 |     20 |
| FORD   | 3000.00 |     20 |
+--------+---------+--------+
3 rows in set (0.00 sec)  //查找出 3条数据结果

1.2.2 in 运算符

  1. in 说明:in == 多个or
  2. in 使用格式
    select 字段1,字段2
    from 表名
    where 条件字段 in(具体值1,具体值2);
  //where 条件字段=具体值1 or 条件字段=具体值2;//上面in方式与or方式相等
  1. 特点
    字段 in(具体值1,具体值2):括号内的具体值不是指数据在某个范围内,而是可以取 等于这两个不同的具体值;
  2. not in:不在指定的具体几个值当中,和 in相反。
  3. 使用示例
select * from emp where job = 'SALESMAN' or job = 'MANAGER';  //or写法
select * from emp where job in('SALESMAN', 'MANAGER');  //in写法-等同于or

// in后面的值不是区间,是具体的值,表示取=800 or或 =5000的值
select ename,job from emp where sal in(800, 5000); 
// not in,表示不取=1000 or或 =3000的值
select ename,job from emp where sal not in(1000, 3000); 

1.2.3 like 模糊查询

  1. 说明
    使用like模糊查询的原因是在条件查询中,并不知道完整的查找条件,可能只知道查找条件的一部分。但是为了能通过这一小部分也可以查询得到想要的数据结果,就可以使用like 表示查询条件中未知的一部分
  2. like特定符
  • %:百分号%代表任意多个字符,
  • _:下划线_代表任意1个字符,但是指定了下标位置;
  1. % 与 _ 同时使用:当百分号% 与 下划线_ 同时使用时,对下划线必须使用转移字符 斜线\ 将下划线转换普通字符。
  2. 代码示例
//找出名字当中含有字母O的
select ename from emp where ename like '%O%';
//找出名字中第二个字母是A的
select ename from emp where ename like '_A%';

//找出名字中有下划线的
//select name from t_user where name like '%_%';  //错误写法,这样写是找出所有name
select name from t_user where name like '%\_%';  //正确写法
//找出名字中最后一个字母是T的
select ename from emp where ename like '%T';

1.3 排序数据

  1. 说明
    对于查找得到的所有数据,希望得到一定顺序的输出结果,因此需要对查找的数据进行排序。
  2. 排序关键字:order by,默认升序排序
  3. 语法格式
//无where子句
    select 字段1,字段2,字段3...
    from 表名
    order by 字段(需是select中的查找字段)

//有where子句(单个字段排序)
    select 字段1,字段2,字段3...
    from 表名
    where 条件(字段名 = 字段数据);
    order by 字段(需是select中的查找字段)

//有where子句(多个字段排序)
    select 字段1,字段2,字段3...
    from 表名
    where 条件(字段名 = 字段数据);
    order by 字段1, 字段2 asc, 字段3 desc  
    //字段1先默认排序,再字段2 asc升序排序,最后字段3 desc降序排序
  1. 执行步骤
  • 先执行from:先明确从哪个位置(哪个表中)查询数据;
  • 其次是where:明确查询的表后,需要确定查找的具体条件(一般是根据给定具体值的字段来查找);
  • 接着是select:根据具体的条件"索引"到表中,查询满足条件的数据;
  • 最后是order by:对所有查找到的满足条件的结果 进行排序。(order by排序时可能没有where条件子句也是可行的) 。
  1. 特点
  • 默认排序:没有指定排序规则时,order by默认为升序排序,也可以在order by字段后面加上 asc为升序排序,desc为降序排序
  • 多个字段排序:对于给查找的多个字段全部排序时,会先给写在最前面的字段先排序,依次给编写顺序的字段排序;
  • 多个字段排序且指定排序顺序:给查找的多个字段排序时,可以通过在order by的每一个字段后面指定asc或desc对每一个字段进行排序
  • 多个字段排序主导性:给查找的多个字段排序时,编写顺序越靠前的字段起到主导作用,只有当前面的字段无法完成排序时,才会启用后面的字段排序。
  1. 代码示例
//查找所有员工的薪资并排序
    select ename , sal from emp order by sal; // 默认升序
    select ename , sal from emp order by sal asc; // asc升序
    select ename , sal from emp order by sal desc; // desc降序

//按照员工工资的降序排列,当工资相同时按照员工名字升序排列
    select ename,sal from emp order by sal desc;  //先按照工资降序排列
    select ename,sal from emp order by sal desc , ename asc;  //在工资降序排列的基础上 对员工姓名升序排列

1.4 分组函数

  1. 说明
    分组函数又称为聚合函数、统计函数、组函数,主要用于数据统计使用。分组函数可以方便获得一些特殊数据,如总数、最大值、最小值、平均值等。所有的分组函数都是对"某一组"数据进行操作的

  2. 函数关键字

  • count(字段):计数,用于统计数据的个数(一行为一条数据),count(*)表示统计数据表的所有行数;
  • sum(字段):求和,用于对某个字段的所有数据求总和;
  • avg(字段):平均值,用于对某个字段的所有数据求平均数;
  • max(字段):最大值,用于获取某一字段中的最大数;
  • min(字段):最小值,用于获取某一字段中的最小数。
  1. 语法格式
//求总和
  select sum(字段) 
  from 表名;
//求最大值
  select max(字段) 
  from 表名;
//求最小值
  select min(字段) 
  from 表名;
//求平均值
  select avg(字段名) 
  from 表名;
//求数据的条数(不为NULL的记录条数)
  select count(字段名) 
  from 表名;
//求表的总行数(总记录条数)
  select count(*) 
  from 表名;
  1. 执行原理
  • 先执行from:先明确从哪个位置(哪个表中)查询数据;
  • 其次是where:明确查询的表后,需要确定查找的具体条件(一般是根据给定具体值的字段来查找);
  • 最后是select:根据具体的条件"索引"到表中,查询满足条件的数据;
  1. 特点
  • 出现位置:分组函数通常直接出现在select子句中,而不能直接出现在where子句中;
  • 执行时间:分组函数一定是在分组查询group by进行分组之后才能执行;
  • 所有的分组函数都是对"某一组" 或 "某一字段"数据进行操作的
  • 自动过滤null;所有的分组函数使用时会忽略没有数据的字段(即为null的字段),只统计有数据的字段(即使为0.0);
  • 多行处理函数:分组函数又称多行处理函数,即输入多行,最终输出的结果只有1行。sum(字段)是输入n行数据求和得出1行的结果,max(字段)是输入n行的数据得出1个/1行的最大数;
  • 分组函数--分组查询联合使用:分组函数的使用一般都会联合分组查询一起,只有两个分组联合使用才体现出其意义;
  • 所有数据库都有的规定:只要有NULL参与的运算,结果一定是NULL;而分组函数忽略掉所有NULL,因此NULL并没有参与分组函数的运算
  1. 代码示例
//查询工资总和
  select sum(sal) from emp;
//查询最高工资
  select max(sal) from emp;
//查询最低工资
  select min(sal) from emp;
//查询平均工资
  select avg(sal) from emp;
//查询总人数
//select count(*) from emp;  //count(*)表示统计所有行数/总行数
  select count(ename) from emp;
  1. 注意点
    分组函数不能直接在where子句当中使用(分组函数在group by分组之后才能执行,而where在group by之前执行)。
    select 字段 from 表名 where 字段 > avg(字段);//错误提示(不合理语句)
    select 字段 from 表名 where 字段 > (select avg(字段) from 表名);

1.4.1 单行处理函数

  1. 概念
  • 多行处理函数:输入多行数据项 最终得出1行数据结果,分组函数都是多行处理函数
  • 单行处理函数:输入一行数据项 得出1行数据结果,输入多行数据项 得出多行数据结果。
  1. 特点
  • 处理精细:对每一行输入数据及时处理,返回每一个对应的处理结果。

1.4.2 ifnull()

  1. 说明
    ifnull()属于单行处理函数,是专门处理数据为NULL的空函数。由于NULL在参与数学运算时会将整个数学运算结果变为null,为了解决这种情况,因此使用ifnull()函数将可能为null的数据字段 变为数学0参与运算。
  2. 使用格式
    ifnull(可能为NULL的字段,期望的处理值):将可能为NULL的字段数据 转换成 具体处理值的字段数据
  3. 特点
  • 将分组函数忽略NULL的特点 转变成 将NULL转换为实际有用的数据;
  • 将 让数学运算无效的NULL 转换为 可以让数学运算正常运算的实际数据。
  1. 代码示例
//原始查询--可以为NULL
mysql> select ename,comm from emp;
+--------+---------+
| ename  | comm    |
+--------+---------+
| SMITH  |    NULL |
| ALLEN  |  300.00 |
| WARD   |  500.00 |
| JONES  |    NULL |
| TURNER |    0.00 |
//计算每个员工的年薪:年薪 = 工资sal + 补贴comm
//select ename,(sal+comm)*12 as yearsal from emp;  //comm为NULL时,参与的运算结果一定是NULL

//使用ifnull()处理之后--NULL变为期望值0
mysql> select ename,ifnull(comm,0) as comm from emp;
+--------+---------+
| ename  | comm    |
+--------+---------+
| SMITH  |    0.00 |
| ALLEN  |  300.00 |
| WARD   |  500.00 |
| JONES  |    0.00 |
| TURNER |    0.00 |
//使用ifnull函数:comm为NULL 变成 comm为0
select ename,(sal+ifnull(comm,0))*12 as yearsal from emp;

1.5 分组查询

  1. 说明
    分组查询不同于分组函数,分组函数针对的是对数据进行统计/计算处理,而分组查询是对字段的查询
  2. 分组查询关键字
  • group by:按照某个字段或者某些字段进行分组,group分组 + by通过分组的字段;
  • having:对分组之后的数据进行再次过滤(效率较低,不如where子句过滤)。
  1. 语法格式
5    select  字段1,字段2,字段3,分组函数(字段)...
1    from  表名
2    where  条件子句
3    group by  分组字段
4    having  在分组字段上的条件过滤
6    order by  排序字段
  1. 执行原理
  • 首先是from:根据表名确定在哪个表中查找数据,确定表永远是第一步;
  • 第二是where:根据具体的条件子句在已知表中进行条件过滤;
  • 第三是group by:通过对字段进行分组处理,可以更加明确对分组的条件过滤;
  • 第四是having:having是在group by分组之后加上的过滤条件(此过滤效率低下不如where子句过滤);
  • 第五是select:以上的二到四都是条件过滤,从同时满足所有过滤条件的字段中 select查找对应字段名的数据(分组函数也在此时使用)
  • 最后是order by:对查找得到的字段数据进行排序输出。
  1. 特点
  • 分组函数--分组查询联合使用:分组函数的使用一般都会联合分组查询一起,只有两个分组联合使用才体现出其意义(分组查询与分组函数执行顺序前后的体现);
  • 当一条sql语句中使用group by时,select后面只能跟分组函数 和 参与分组的字段(group by的字段)
  • 当一条sql语句没有group by时,整张表的数据会自成一组。
  1. 代码示例
//自成一组:总共14个数据
mysql> select * from emp;
+-------+--------+-----------+------+---------+---------+--------+
| EMPNO | ENAME  | JOB       | MGR  |  SAL     | COMM    | DEPTNO |
+-------+--------+-----------+------+---------+---------+--------+
|  7369 | SMITH  | CLERK     | 7902 |  800.00  |    NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1600.00  |  300.00 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1250.00  |  500.00 |     30 |
|  7566 | JONES  | MANAGER   | 7839 |  2975.00 |    NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 |  1250.00 | 1400.00 |     30 |
|  7698 | BLAKE  | MANAGER   | 7839 | 2850.00  |    NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 2450.00  |    NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 3000.00  |    NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 5000.00  |    NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1500.00  |    0.00 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1100.00  |    NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 |  950.00  |    NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 3000.00  |    NULL |     20 |
|  7934 | MILLER | CLERK     | 7782 | 1300.00  |    NULL |     10 |
+-------+--------+-----------+------+------------+---------+---------+--------+

//分组查询:先根据job工种分组,再求每一个工种的平均薪资(5个工种5个数据)
mysql> select ename,job,avg(sal) from emp group by job;
+-------+-----------+-------------+
| ename | job       | avg(sal)    |
+-------+-----------+-------------+
| SCOTT | ANALYST   | 3000.000000 |
| SMITH | CLERK     | 1037.500000 |
| JONES | MANAGER   | 2758.333333 |
| KING  | PRESIDENT | 5000.000000 |
| ALLEN | SALESMAN  | 1400.000000 |
+-------+-----------+-------------+

//分组查询:先根据sal工资分组,再求每一个工资的平均薪资(12种工资12个数据)
mysql> select ename,job,avg(sal) from emp group by sal;
+--------+-----------+-------------+
| ename  | job       | avg(sal)    |
+--------+-----------+-------------+
| SMITH  | CLERK     |  800.000000 |
| JAMES  | CLERK     |  950.000000 |
| ADAMS  | CLERK     | 1100.000000 |
| WARD   | SALESMAN  | 1250.000000 |
| MILLER | CLERK     | 1300.000000 |
| TURNER | SALESMAN  | 1500.000000 |
| ALLEN  | SALESMAN  | 1600.000000 |
| CLARK  | MANAGER   | 2450.000000 |
| BLAKE  | MANAGER   | 2850.000000 |
| JONES  | MANAGER   | 2975.000000 |
| SCOTT  | ANALYST   | 3000.000000 |
| KING   | PRESIDENT | 5000.000000 |
+--------+-----------+-------------+

//多个字段分组查询:先根据deptno部门编号分组,再根据工种job在部门分组基础上分组,最后从具体分好的组中查询平均薪资
mysql> select deptno,job,avg(sal) from emp group by deptno,job;
+--------+-----------+-------------+
| deptno | job       | avg(sal)    |
+--------+-----------+-------------+
|     10 | CLERK     | 1300.000000 |
|     10 | MANAGER   | 2450.000000 |
|     10 | PRESIDENT | 5000.000000 |
|     20 | ANALYST   | 3000.000000 |
|     20 | CLERK     |  950.000000 |
|     20 | MANAGER   | 2975.000000 |
|     30 | CLERK     |  950.000000 |
|     30 | MANAGER   | 2850.000000 |
|     30 | SALESMAN  | 1400.000000 |
+--------+-----------+-------------+

1.5.1 where 与 having

  1. 执行顺序
  • where:where子句在整个sql语句的第二步开始执行,是整个sql中最先进行条件过滤的子句;
  • having:having在对所有数据进行group by分组之后再执行,是在分组的基础上对分组的条件过滤,而group by在where之后执行。
  1. 执行特点
  • where:对于求某单个数据,可以使用where进行提前过滤,再执行group by分组,效率较高;
  • having: 对于求某个平均数据且涉及分组后的平均数,可以先进行group by分组再采用having过滤,因为使用where时会在分组前过滤掉一些数据(导致求平均值时不是最终的平均数据)。
  1. 代码示例
//找出每个部门的 最高薪资,要求显示薪资大于2900的数据
//第一步:找出每个部门的最高薪资,将部门分组,求每组部门最高
select max(sal),deptno from emp group by deptno;
//第二步:从每组部门最高,求大于2900的
//select max(sal),deptno from emp group by deptno having max(sal) > 2900;   //分组后再过滤
select max(sal),deptno from emp where sal > 2900 group by deptno;   //过滤小于2900后再分组

//找出每个部门的 平均薪资,要求显示薪资大于2000的数据
//第一步:找出每个部门的平均薪资,分组部分,后求平均工资
select deptno,avg(sal) from emp group by deptno;
//第二步:分组求平均数后,求大于2000的平均数(不能使用where,where在分组已过滤数据)
select deptno,avg(sal) from emp group by deptno having avg(sal) > 2000;

1.5.2 distinct关键字(去重查询)

  1. 说明
    distinct解释为去重复,在DQL查询中属于条件过滤的一种方式,是用来过滤去除一些重复的数据。distinct属于最后的过滤(distinct关键字在select后面出现,select是最后执行的条件过滤)
  2. 使用格式
select distinct 字段1,字段2,...
from 表名
where 条件子句
...
  1. 特点
  • distinct只能用于select子句,不能用于其他子句;
  • distinct在select子句中只能出现在所有字段的最前面(表示distinct后面的字段全部去重);
  • 一次过滤去重多个字段,但不能使用括号(),错误:select distinct(字段1,字段2)
  • 一个select子句只能使用一个distinct关键字,错误:select distinct 字段1,distinct 字段2
  • 用于统计总类型的个数(一个类型可能有多个数据值,只求类型<种类>数)。
  1. 代码示例
// 去重:找出emp表中的工种(工种的个数不变,但每个工种有多个职员)
mysql> select distinct(job) from emp;
+-----------+
| job       |
+-----------+
| CLERK     |
| SALESMAN  |
| MANAGER   |
| ANALYST   |
| PRESIDENT |
+-----------+

//mysql> select ename,distinct(job) from emp;  //ERROR: distinct只能出现select子句的首位,所有字段的前面
mysql> select distinct(job),ename from emp;
//mysql> select distinct(job,ename) from emp;  //ERROR: distinct每次只能去重一个字段
//mysql> select ename,job form emp where distinct(job);  //ERROR: distinct只能出现在select子句,不能出现其他子句
//mysql> select distinct job,distinct deptno from emp;  //ERROR :distinct一次只能出现一个
mysql> select distinct job,deptno from emp; //表示distinct后面的字段全部去重
// 统计岗位的数量:先去除重复的岗位,再统计岗位数量
select count(distinct job) from emp;

1.6 子查询

  1. 说明
    子查询是指在一个DQL查询语句当中插入另外一个查询语句,具体是在本体的查询子句中 插入查询作为该子句的查询条件。子查询 即查询嵌套使用。
  2. 子查询关键字
  • ()括号:将一个查询语句封装在括号中,将括号内查询返回的结果作为外部查询的条件;
  1. 语法格式
  • select 子句子查询(极少使用,可读性差)
    select  
        (select 字段 from 表1 where 条件)as 新字段  // 括号内子查询的返回结果可作为外部查询的字段  
    from
        表2
    where
        条件子句;
  • from子句子查询(实际开发最常使用
    select  
        别名2.字段
    from
        (select 字段 from 表1 where 条件)别名2  //括号内 子查询的返回结果作为新表,且另起别名  
    where
        条件子句;
  • where子句子查询
    select  
        别名2.字段
    from
        表2 别名2
    where
        条件子句 字段1 >=<(select 字段 from 表1 where 条件)  //括号内 子查询的返回结果作为条件子句的一部分条件
  1. 执行原理
  • 先执行子查询中的语句
  • 再回到外部查询的from 语句开始
  1. 特点
    先执行子查询,并将子查询的返回结果作为外部查询的字段、临时表、条件等。
  2. 代码示例

1.6.1 表别名

  1. 概念
    在DQL查询时,通过给每个数据表另起别名,可以让查询结构更加清晰易读,也避免多表查询时表名过多过长造成的冗余(可读性差)。
  2. 起名格式
    select 
        a.字段,b.字段,c.字段
    from 
        表1 别名a,表2 别名b,表3 别名c
    where 
        条件子句(过滤条件)
  1. 使用特点
  • 表别名必须在from子句中进行起名(因为所有的DQL查询语句第一步执行的就是from子句)
  • 同一张表可以同时起两个别名,起两个别名后该两张表不是"同一张表"(自连接);
  1. 代码示例
// 原始查询
    select emp.ename, dept.dname   //"表名.字段"表达清晰,但字段太长易混乱  
    from emp, dept 
    where emp.deptno=dept.deptno;

// 使用别名查询
    select e.ename, d.dname 
    from emp e, dept d   //使用表别名,方便在其他字段使用
    where e.deptno=d.deptno;

1.7 连接查询

  1. 说明
    连接查询又叫跨表查询,需要关联多个表进行查询。在日常开发中极少要求进行单表查询,一般都是多个表联合进行查询(表与表之间存在联系<主键,外键>),不仅为了数据的独立性,也为了数据库的可维护性更好。

  2. 连接查询版本

  • SQL92:着重于使用where条件的连接查询,表连接过滤 和 查询过滤都在同一个where中使用多个 and进行拼接,可读性差,过滤条件冗余;
  • SQL99:着重于使用join on表连接条件 + where数据查询条件 分离的查询,表连接过滤 和 查询过滤分离,层次更加清晰。
  1. 连接查询分类
  • 内连接:包括等值连接(等号=)、非等值连接(between...and...)、自连接;
  • 外连接:包括左外连接、右外连接;
  • 全连接:
  1. 连接查询原理
  • 多个数据表联合查询,区别于单表查询;
  • 拿单表的一条数据(记录)和另外一张表的数据进行匹配,匹配的上则返回匹配的记录(有效数据)
  • 连接查询实际原理:多表连接查询会产生笛卡尔积现象,通过条件筛选,过滤掉无效数据得到有效记录,就是多表查询。

1.7.1 笛卡尔积

  1. 概念
    笛卡尔积又称笛卡尔乘积现象,指的是在数据库查询当中进行多表查询时,若未对多表联查进行条件过滤,则会出现多个重复且无效的数据,并且最终的查询结果集等于多个表的数据的个数乘积。
  2. 实际表示:笛卡尔积 = A表m条记录 X B表n条记录
  3. 处理方式
    在查询中加条件进行过滤可以避免笛卡尔积现象(不会减少记录的匹配次数,只是显示有效记录)

1.7.2 内连接(inner join)

  1. 概念
    内连接即多表查询中的单表内嵌,通过在一条查询语句中进行单表查询内嵌而形成多表查询的方式,成为内连接。假设A表和B表进行连接,凡是A表和B表能够匹配上的记录都查询出来--就是内连接。AB两张表没有主副之分,两张表是平等的。
  2. 实现方式
    将一个查询拆分"粒度",将一个多表查询拆分成多个单表查询,尽量做到每一个字段出自于对应的表,然后使用inner join将单表查询连接,从而完成多表查询。
  3. 实现关键字:inner joinon
  4. 最大特点:只查询相等的数据(连接条件相等的数据)
  5. on关键字
    on相当于where关键字,属于对查询的条件过滤,但是on着重于表的连接过滤,where是着重于对查询的条件过滤。
    on经常与inner join同时搭配出现,表示在内连接过程中的条件过滤或筛选,实现表的连接条件和后来的where查询条件分离。
  6. 语法格式
// 两张表
    select 
        a.字段1,b.字段2 
    from
        表1 别名a
   (inner)join
        表2 别名b
    on 
        a.字段 = b.字段;   //表1和表2 连接的过滤条件 

// 三张或以上多表
    select 
        a.字段1,b.字段2 ,c.字段3
    from
        表1 别名a
   (inner)join
        表2 别名b
    on 
        a.字段 = b.字段;   //表1和表2 连接的过滤条件 
   (inner)join
        表3 别名c
    on 
        a.字段 = c.字段;   //表1和表3 连接的过滤条件 
    //....下面可以继续 join on 或 left/right join on
    where
        a.字段 = b.字段;   //查询的过滤条件
1.7.2.1 等值连接
  1. 概念
    等值连接是内连接中,连接条件过滤的子句使用 等式= 作为过滤条件的连接。
  2. 最大特点
    表的连接条件是等量关系(on连接部分是等量关系),A表的主键字段的值 = B表的外键字段的值,A表的主键必须作为B表的外键。
  3. 语法格式
// 等值连接--SQL92版
    select  
        a.字段1,b.字段2  
    from
        表1 别名a , 表2 别名b
    where
        a.字段 = b.字段;   //查询的过滤条件

// 等值连接--SQL99版
    select 
        a.字段1,b.字段2 
    from
        表1 别名a
   (inner)join
        表2 别名b
    on 
        a.字段 = b.字段;   // 表连接的 过滤条件  
    where
        a.字段 = b.字段;   // 查询的 过滤条件
  1. 执行顺序/原理
1.7.2.2 非等值连接
  1. 概念
    非等值连接是内连接中,连接条件过滤的子句使用 beetween and 等作为过滤条件的连接。
  2. 最大特点
    表的连接条件是非等量关系(on连接部分是非等量关系)。
  3. 语法格式
// 非等值连接--SQL92版
    select  
        a.字段1,b.字段2  
    from
        表1 别名a , 表2 别名b
    where
        a.字段 between b.字段 and b.字段; 

// 非等值连接--SQL99版
    select 
        a.字段1,b.字段2 
    from
        表1 别名a 
   (inner)join    //inner可以省略  
        表2 别名b
    on 
         a.字段 between b.字段 and b.字段;  // 表连接的 过滤条件
    where
        a.字段 = b.字段;   // 查询的 过滤条件    
  1. 执行顺序/原理
1.7.2.3 自连接
  1. 概念
    自连接指的是对于只有一张表,进行自己连接自己的查询,将一张表使用两个"别名"来区分成两张表,进而可以筛选过滤。
  2. 最大特点
    一张表看做两张表,自己连接自己,自己查自己。
  3. 语法格式
// 自连接:本身是同一张表,使用不同别名作为两张表
    select 
      a.字段1 as '新字段名',b.字段2 as '新字段名'
    from
      表1 别名a
   (inner)join  // 表1 连接 表1
      表1 别名b
    on
      a.字段1 = b.字段2;    //"两张表"的字段采用等值连接
  1. 执行顺序/原理
  • 先对原表起别名

1.7.3 外连接

  1. 概念
    假设A表和B表进行连接,外连接时A、B两张表中有一张表是主表,一张表是副表,主要查询主表中的数据,捎带着查询副表。当副表中的数据没有和主表中的数据匹配上,副表自动模拟出NULL与之匹配。
  2. 最大特点
  • 主表的数据无条件的全部查询出来,内连接(等值连接)则指查找出字段值相等的数据,当字段值为空或者不相等则不查出;
  • 外连接查询出来的数据会更加完整,内连接会丢失数据
  • outer关键字可以省略;
  • 笔试最后一题一般是外连接查询。
  1. 分类
  • 左外连接:以左边的表为主,无条件查询出左边表的所有数据记录;
  • 右外连接:以右边的表为主,无条件查询出右边表的所有数据记录;
  1. 左外连接与右外连接的转换
  • 每一个左外连接都必定有一个右外连接的写法;
// 左外连接
    from
      表1 a
    left outer join  // outer可以省略
      表2 b
    on
    a.字段 = b.字段;  // 表连接的 过滤条件

// 右外连接
1.7.3.1 左外连接(left join)
  1. 概念
    以左边的表为主,连接右边的表一起查询,连接查询的实际原理就是以一张表的数据记录 去匹配另一张表的数据记录。但左外连接使表的连接顺序拥有左边优先级。
  2. 最大特点
    左边的表是主表,获取左表所有记录,即使右表没有对应匹配的记录。
  3. 语法格式
// 左外连接:以左表为主
    select 
      a.字段1 as '新字段1', b.字段2 as  '新字段2'    //as可以省略    
    from
      表1 a
    left outer join  // outer可以省略
      表2 b
    on
    a.字段 = b.字段;  // 表连接的 过滤条件
    where
        a.字段 = b.字段;   // 数据查询的 过滤条件
  1. 执行顺序/原理
1.7.3.2 右外连接(right join)
  1. 概念
    以右边的表为主,连接左边的表一起查询,连接查询的实际原理就是以一张表的数据记录 去匹配另一张表的数据记录。但右外连接使表的连接顺序拥有右边优先级。
  2. 最大特点
    右边的表是主表,用于获取右表所有记录,即使左表没有对应匹配的记录。
  3. 语法格式
// 右外连接:以右表为主
    select 
      a.字段1 as '新字段1', b.字段2 as  '新字段2'    //as可以省略    
    from
      表1 a
    right outer join  // outer是可以省略
      表2 b
    on
    a.字段 = b.字段;
  1. 执行顺序/原理

1.7.4 全连接(full join)

  1. 概念
    假设A表和B表进行连接,外连接时A、B两张表都是主表,没有副表。查询时将A、B表的数据都无差别查询出来。
  2. 最大特点
    每一张表都是主表,没有副表。
  3. 语法格式
  1. 执行顺序/原理

1.8 union关键字

  1. 说明
    对于多表查询或者多个字段查询,union关键字是将查询拆分为多个单一的字段查询,然后将多个单一查询的结果集进行相加,返回一个查询结果的合集。
  2. 最大特点
  • 将两张或多张毫无相关的表的查询结果连接输出;
  • 作用可以取代orin 关键字的部分用法;
  • union相加只能是每个查询是查询相同的列数或字段数,列数不同或查询字段数不同的多个查询不能想加;
  • 查询结果输出有序(union实则为分步查询,有先后)。
  1. 语法格式
// 同表查询
select 字段1,字段2 from 表1 where 字段 = '数据值1'
union
select 字段1,字段2 from 表1 where 字段 = '数据值2'

// 多表查询--可以将不同表的查询结果 相加结合输出
select 字段1,字段2 from 表1 where 字段1 = '数据值'
union
select 字段3,字段4 from 表2 where 字段3 = '数据值'
  1. 执行原理 /顺序
    将一个总的查询分为多个查询小分支,每一个小分支都可以查询不同的表,最后使用union关键字将每一个小分支的查询结果返回作为整个总-查询的结果。
  2. 代码示例
  • 单表 union相加字段
// 要求:找出工作岗位是SALESMAN和MANAGER的员工
// 使用 or关键字
select ename,job from emp where job = 'MANAGER' or job = 'SALESMAN';
// 使用 in关键字
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 |
+--------+----------+
// 使用 union关键字
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 |
+--------+----------+
  • 多表 uinion相加
// 查询所有员工和部门名称
mysql> select ename from emp  // 第一步:从emp表查询所有员工
    -> union  // 第三步:将两个查询结果相加
    -> select dname from dept;  //第二步:从dept表查询所有部门
  +------------+
  | ename      |
  +------------+
  | SMITH      |
  | ALLEN      |
  | WARD       |
  | JONES      |
  | MARTIN     |
  | BLAKE      |
  | CLARK      |
  | SCOTT      |
  | KING       |
  | TURNER     |
  | ADAMS      |
  | JAMES      |
  | FORD       |
  | MILLER     |
  | ACCOUNTING |
  | RESEARCH   |
  | SALES      |
  | OPERATIONS |
  +------------+

1.9 limit关键字

  1. 说明
    limit关键字是Mysql中特有的关键字,其他数据库中没有,不能通用(Oracle中有一个相同的机制--rownum)。
  2. 最大特点
  • limit可以实现分页查询;
  • limit是取出查询结果集中的一部分数据;
  • limit是整个SQL语句中最后执行的一步。
  1. 语法格式
    // startIndex表示起始位置,从下标0开始表示第一条数据
    // length表示取出结果集中的 几个
    limit startIndex, length

    // 省略startIndex起始位置 时 ,默认从下标0开始取length个数据
    limit  length;

执行顺序
5       select      
            字段1,字段2,...
1       from            
            表1 别名a...
         /*(inner/left/right join
                    表2 别名b
            on 
                    表连接条件) // 表连接查询可有可无,看具体业务   
         */         
2       where           
            查询过滤条件  
3       group by        
            分组字段
4       having      
            分组的过滤字段
6       order by        
            排序
7       limit           
            起始位置,获取长度/个数;

  1. 执行原理
    在其他所有SQL子句执行结束之后,limit才会执行。limit是整个SQL中最后执行的一步,在select子句执行之后获得了查询结果在执行,是对查询结果的过滤。
  2. 代码示例
// emp表中的员工与薪资数据--按照降序输出
mysql> select ename,sal from emp order by sal desc;
+--------+---------+
| ename  | sal     |
+--------+---------+
| KING   | 5000.00 |
| SCOTT  | 3000.00 |
| FORD   | 3000.00 |
| JONES  | 2975.00 |
| BLAKE  | 2850.00 |
| CLARK  | 2450.00 |
| ALLEN  | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| MARTIN | 1250.00 |
| WARD   | 1250.00 |
| ADAMS  | 1100.00 |
| JAMES  |  950.00 |
| SMITH  |  800.00 |
+--------+---------+

// 取出工资排前5名的员工--先对薪资排序
select ename,sal from emp order by sal desc;
// 从排序的薪资中取前5个
select ename,sal from emp order by sal desc limit 0, 5;  // 从起始下标0开始,取5个
select ename,sal from emp order by sal desc limit 5;  //  只有一个数字表示取得长度,默认从下标0开始

// 找出工资排名在第4到第9名的员工
select ename,sal from emp order by sal desc limit 3,6;  //下标从0开始

1.9.1 通用分页SQL

  1. 分页原理
    每页显示3条记录:起始页,每页显示的数据条数
    第1页:0, 3
    第2页:3, 3
    第3页:6, 3
    第4页:9, 3
    第5页:12, 3
  2. 分页实现关键
    每页显示pageSize条记录;
    pageNo页:页码(pageNo - 1) * pageSize,数据条数pageSize
  • pageSize:每页显示的多少条记录
  • pageNo:显示的第几页
  1. java实现分页
java分页代码 {
    int pageNo = 2; // 第几页:页码是2
    int pageSize = 10; // 每页显示的数据:10条   
    String sql = limit (pageNo - 1) * pageSize, pageSize;// 分页显示的页码 和当前页码显示的数据条数
}

常见面试题

提供的参考表

             dept表
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
                                   emp表
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800.00 |    NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600.00 |  300.00 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250.00 |  500.00 |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975.00 |    NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250.00 | 1400.00 |     30 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850.00 |    NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |    NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000.00 |    NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000.00 |    NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500.00 |    0.00 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100.00 |    NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950.00 |    NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000.00 |    NULL |     20 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300.00 |    NULL |     10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
        salgrade表
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
|     1 |   700 |  1200 |
|     2 |  1201 |  1400 |
|     3 |  1401 |  2000 |
|     4 |  2001 |  3000 |
|     5 |  3001 |  9999 |
+-------+-------+-------+

你可能感兴趣的:(Mysql之数据查询DQL)