Mysql_7 SQL 语句——DQL

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 学习自b站骆昊jackfrued 老师的网课以及黑马网课。

学习自b站骆昊jackfrued 老师的网课以及黑马网课。

查询语句。

本节中使用到的例子:主要包含 tb_student 学生表(学号 stu_id,姓名 stu_name,地址 stu_address,所属学院号 col_id)

tb_record 记录表,连接学生和所选的课 id 及课程成绩(学号 stu_id,课程号)

编写顺序、执行顺序

编写顺序如下:select from where group by having order by limit;

执行顺序:

  1. from 表名
  2. where 条件(where 可以用表别名,但是不能用 select 中的字段别名)
  3. group by 分组
  4. having 分组条件
  5. select 投影
  6. order by 排序
  7. limit 分页

Select

查询所有学生的所有信息

select * from `表名`;-- * 号表示所有字段

但是这样有一点影响效率,会先查出学生表中有哪些列,再查询这些列的数据。

实际使用一般都是手动写上所有要查询的字段。(投影 Projection,只查询某几列)

select `stu_id`,`stu_sex`,`stu_name`,`stu_address` from `tb_student`;

如果只查询部分列,就只写那几列就行。

别名

给字段或表起别名—— alias,简写为 as。

select `stu_id` as `学号` from `tb_student`;

as 可以省略,不过还是写上可读性高一些。一般字段不省略,表省略。具体还得看公司编程规范的要求,没有就看个人喜好了。

条件

限制查询记录的条件——where(选择 Selection,只查询某几行)

select * from table where `stu_sex`='M' or `stu_name`='Jingqing';

多个条件之间用 or 连接就是或者的关系,满足一个即可;用 and 连接就是和的关系,同时满足。

性能问题,一般不用 or 而使用 union,结果取并集。

select * from table where `stu_sex`='M' 
union
select * from table where `stu_name`='Jingqing';

如果在 union 后面加 all,意思是并集不会去掉重复的部分,相交的部分会显示两遍。

类似 10<x<30 的形式不可以直接写两个等式,要拆成 x>10 and x<30 。

这里的字段如果是数字类型的,也可以进行 + - * / % mod(也是取余)以及 < > = >= <= <> 等形式的运算。

还有一种条件写法是 between …… and ……

select * from table where `stu_age` between 10 and 30;-相当于 <=30 and >=10

分支结构

如果 sex 是布尔值,1代表男,0代表女,怎么把0和1处理成对应的性别?

select if(`stu_sex`,'男','女') as '性别' from `tb_student`;-- 有点类似三目运算符 ?:

if 中第一项可以是表达式,如 age > 10.

这个是 Mysql 数据库的方言,只能在 Mysql 数据库中生效。比如 Oracle 数据库中对应的函数是 decode,不能通用。

通用的分支结构:

select case `sex` when 1 then '男' else '女' end as '性别' from `tb_student`;-- end 表示条件判断结束

模糊查询

如:查询所有姓王的学生。

select * from `student` where `stu_name` like '王%';-- % 代表零个或多个任意字符,表示查询姓的且名字只有2个字的学生
select * from `student` where `stu_name` like '王_';-- _ 代表一个任意字符,表示查询姓王的且名字只有2个字的学生

这里和正则表达式有一定联系,之后会单独学习。

事实上 Mysql 语句也支持正则表达式的,正则表达式也比这两种模糊查询的通配符功能强大很多。

select * from `student` where `字段名` regexp '正则表达式';

模糊查询,特别是 % 在左侧的时候,性能还是比较差的,尽量避免。

空值处理,以及三值逻辑

下面两种写法是错误的!

select * from `student` where `stu_address` = null;
select * from `student` where `stu_address` <> null;

因为表达式产生的值有三种(三值逻辑),true, false, unknown。和空值做运算的时候,就会得到 unknown 的结果。

正确做法:

select * from `student` where `stu_address` is null;
select * from `student` where `stu_address` is not null;

去重

select distinct `字段名` from `表名`;

排序

 select `字段名` from `表名` order by `字段名1` asc, `字段名2` desc; -- asc: 默认,ascending,升序;desc:descending,降序

order by 后面跟多个字段,就是先按字段1排序,字段1相等时再按字段2排序。

当前日期

curdate()获取当前日期,使用 datediff() 函数可以和出生日期做差获取年龄。

now()获取当前年月日时分秒(datetime)。

取整

floor() 函数是下取整。floor(3.99) = 3.

ceil() 函数是向上取整,ceil(3.1) = 4.

round() 函数是四舍五入,第二个参数是保留几位小数的意思,round(3.5,0)=4

select floor(datediff(curdate(),`date`)/365) from `staff`;

可以通过? functions 查看函数一览。还会有相应的例子提示~

聚合函数

描述性统计信息:包括集中趋势和离散趋势。

集中趋势:平均值,中位数等。

离散趋势:方差,标准差等。

聚合函数属于 SQL 语句,所有 DBMS 都能用。

  • min(字段名)
  • max(字段名)
  • avg(字段名) 做计算的时候会忽略 null 值
  • sum(字段名)
  • count(字段名) 做计算的时候会忽略 null 值

    如果利用 sum()和count() 做除法求平均值,要考虑空值对结果的影响。

    比如有10个学生,但有一个学生的成绩为空,如果忽略掉成绩为空的学生, sum(score) / count(stu_id) 就是错误的,因为是9个人的成绩 / 10.

    如果成绩为空的学生视为 = 0,就要用 sum(score) / count(stu_id),或者对 avg() 函数做如下处理:

    select avg(ifnull(`score`,0)) from student;

    ifnull() 函数也是 mysql 的方言,类似 if。在 Oracle 中就是 nvl。

    coalesce() 也可以处理空值,是标准数据库的函数,它会取第一个非空值。如:coalesce(score, 0)。

  • std(字段名),计算标准差,越小说明越稳定。

    • std(), stddev() 和 stddev_pop():所有数据总体的标准差
    • stddev_samp():样本标准差,抽样计算。
  • variance(字段名),计算方差,标准差的平方。

    • variance(), var_pop()
    • var_samp()

分组

聚合函数通常和分组一起使用。分组是非常重要的操作。

select * from `student` group by `sex`;

PS: Excel 的数据透视表有同样功能:

插入-数据透视表-选择所有数据范围(选中左上角的单元格,Ctrl + Shift + →,Ctrl + Shift + ↓选中所有有数据的单元格)-选择放置数据表的位置(选择某一列的第一行的单元格,如 J1 或 K1 )-确认

行里选择要分组的列(如:销售区域)值选择要分组运算的对应值(如:销售额),值默认做的就是求和运算。

select * from `student` group by `sex` with rollup; -- with rollup: 在最后一列求个总和

group by 后面也可以跟多个字段,先按第一个分组,然后在每个组里再按第二个分组。

如果进行了条件查询,用到了 group by 得到的结果,不能直接用 where,要使用 having.

select `stu_id`,avg(score) from `Score` where avg(score)>90 group by `stu_id`; -- 错误
select `stu_id`,avg(score) from `Score` group by `stu_id` having avg(score)>90; -- 正确

分组以前的筛选: where, 写在分组后

分组以后的筛选: having, 写在分组后。

其实这里个人有一个小误区:select 不用非得查出 avg() 才能做 having 条件判断。比如要查询平均成绩大于90分的学生学号,就可以改成:

select `stu_id` from `tb_record` group by `stu_id` having avg(score)>90;

也是没有问题的。

查询 1111,2222,3333三门课程平均成绩大于90分的学生的平均成绩:

select `stu_id`,avg(score) from `Score` where `cou_id` in (1111,2222,3333) group by `stu_id` having avg(score)>90;

子查询

子查询 (subquery) 的用途:

  • 集合成员资格,判断某一元素是否是某一个集合的成员
  • 集合之间的比较,某一个集合是否包含另一个集合等
  • 集合基数的测试,测试集合是否为空,测试集合是否存在重复元组。

查询年龄最大的学生的姓名。

可以先查询出最大年龄,再查询学生表中年龄等于这个值的学生姓名。

一种方法是嵌套子查询:

select `stu_name` from `tb_student` 
where `stu_birth` = (
    select min(`stu_birth`) from `tb_student`
);

另一种方法是定义变量:mysql 定义变量,需要加@(但是不能把多个值赋给一个变量!)

set @a =(select min(`stu_birth`) from `tb_student`);
select @a; -- 可以查看一下 @a 的值。

如果子查询有很多结果,满足其中一个即可:不能用等号,要用 in

select `name` from `tb_student` 
where `stu_id` in (
    select `stu_id` from `tb_record` group by `stu_id` where count(*)>=2
); -- 查询出所有至少选了2门课的学生姓名

如果用了等号,报错: subquery returns more than 1 row.

多表连接

笛卡尔积

select `stu_name`,`stu_id`,`col_name`,`tb_college`.`col_id` from `tb_student`,`tb_college`;

如果不加条件的从两个表中投影出数据,就会获得两个表中所有记录的笛卡尔积,即排列组合。

本例中,学生表和学员表中都有学院号 col_id 字段,因此投影该字段的时候需要指明是从那个表中得到的,用 表名.字段 指定。

自然连接

  1. 有外键约束:利用外键连接,不用加条件,自动连接。
select `stu_name`,`stu_id`,`col_name`,`tb_college`.`col_id` 
from `tb_student` natural join `tb_college`;
  1. 没有外键,但是两个表中有同名的列(如本例中两个表中都有 col_id 列)也可以进行自然连接。注意:不管有几个同名的列,所有列都会作为连接的条件!
  2. 如果没有外键也没有同名列,就只会得到笛卡尔积的结果。

内 / 外连接

另一种连接方式是 inner join / outer join

select `stu_name`,`stu_id`,`col_name`,`tb_college`.`col_id` 
from `tb_student` inner join `tb_college` 
on `tb_student`.`col_id`=`tb_college`.`col_id`; -- 查询所有学生的姓名、学号、对应的学院名、学院号

inner join:只有左表中有的记录,而且在右表中能找到对应的记录才会呈现出来。

left outer join:左表中所有内容都会呈现出来,右表中如果没有对应的内容补 null。

right outer join:右表中所有内容都会呈现出来,左表中如果没有对应的内容补 null。

full outer join:左右表数据全拿出来,没有对应的内容都补 null。但是 mysql 并不支持全外连接,可以用左外连接 union 右外连接代替。

θ 连接

添加条件使得两个表中的数据相互对应:

select `stu_name`,`stu_id`,`col_name`,`tb_college`.`col_id` from `tb_student`,`tb_college` 
where `tb_student`.`col_id`=`tb_college`.`col_id`; -- 查询所有学生的姓名、学号、对应的学院名、学院号

三表连接

链接条件用多个条件筛选。

select `stu_name`,`tb_student`.`stu_id`,`tb_course`.`cou_name`,`tb_course`.`cou_id` from `tb_student`,`tb_course`, `tb_record`
where `tb_course`.`cou_id`=`tb_record`.`cou_id` 
and `tb_student`.`stu_id`=`tb_record`.`stu_id`;

select `stu_name`,`tb_student`.`stu_id`,`tb_course`.`cou_name`,`tb_course`.`cou_id` from `tb_student`
inner join `tb_record`
on `tb_student`.`stu_id`=`tb_record`.`stu_id`
inner join `tb_course`
on `tb_course`.`cou_id`=`tb_record`.`cou_id`
where `tb_course`.`cou_name` is not null; -- where 写在最后

select `stu_name`,`tb_student`.`stu_id`,`tb_course`.`cou_name`,`tb_course`.`cou_id` from `tb_student`
natural join `tb_record`
natural join `tb_course`;

查询小技巧

百度搜索:filetype:pdf python 搜索带 python 名的 pdf 文件

python -推广链接 不想看到广告推送

site:zhihu.com python 只搜索知乎里的 python 内容

分页查询

limit 是 mysql 的方言

select * from `tb_student` order by `stu_id` desc limit 5;-- 只显示前五条数据.如果不足5条,就有几条显示几条。
select * from `tb_student` order by `stu_id` desc limit 5 offset 3;-- 只显示4-8条数据(跳过前3条数据)
select * from `tb_student` order by `stu_id` desc limit (3,5);-- 只显示4-8条数据(跳过前3条数据)

派生表

select 的返回值也是一个关系。(关系运算的封闭性,关系的运算仍然是关系)

查询学生姓名和平均成绩。

查询学生学号和平均成绩的话,可以在 tb_record 表里根据学生学号分组,然后投影出来。但查询学生姓名有需要拿着对应的学号去学生表里连接,要怎么把学生姓名和学生平均成绩关联起来呢?

先通过一个查询,得到一个派生表:

select `stu_id`,avg(score) from `tb_record` group by `stu_id`;

然后把其结果作为一个新表,和学生表做关联。

select `stu_name`,`avg(score)`from `tb_student`
natural join (select `stu_id`,avg(score) from `tb_record` group by `stu_id`) `tb_derived`;-- 最后是起别名的意思

临时表必须要起别名!!!不然报错。

注意:查询学生姓名和选课数 和 查询每个学生姓名和选课数的区别!因为有的同学没有选课,如果用 natural join,inner join,就只能查询到选了课的学生,没选课的学生就不会查出来。

如果要查询每个学生,就要用到外连接。没选课的学生选课数显示 null。(当然可以用 ifnull(字段, 0) 把 null 替换成 0。记得 ifnull 是 mysql 方言)。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3天前
|
SQL 关系型数据库 MySQL
DQL操作MySql
DQL操作MySql
8 0
|
12天前
|
SQL 关系型数据库 MySQL
【MySQL】DQL-案例练习-DQL基本介绍&语法&执行顺序(代码演示)
【MySQL】DQL-案例练习-DQL基本介绍&语法&执行顺序(代码演示)
|
12天前
|
SQL 关系型数据库 MySQL
【MySQL】DQL-排序查询-语法&注意事项&可cv例题语句
【MySQL】DQL-排序查询-语法&注意事项&可cv例题语句
|
12天前
|
SQL 关系型数据库 MySQL
【MySQL】DQL-排序查询-语法&排序方式&注意事项&可cv例题语句
【MySQL】DQL-排序查询-语法&排序方式&注意事项&可cv例题语句
|
12天前
|
SQL 关系型数据库 MySQL
【MySQL】DQL-分组查询-语法&where与having的区别&注意事项&可cv例题语句
【MySQL】DQL-分组查询-语法&where与having的区别&注意事项&可cv例题语句
【MySQL】DQL-分组查询-语法&where与having的区别&注意事项&可cv例题语句
|
12天前
|
SQL 关系型数据库 MySQL
【MySQL-8】DQL-查询语句全解 [ 基础/条件/分组/排序/分页查询 ](附带代码演示&案例练习)
【MySQL-8】DQL-查询语句全解 [ 基础/条件/分组/排序/分页查询 ](附带代码演示&案例练习)
|
12天前
|
SQL 关系型数据库 MySQL
【MySQL】DQL-聚合函数介绍&常见聚合函数&语法&注意事项&可cv例题语句
【MySQL】DQL-聚合函数介绍&常见聚合函数&语法&注意事项&可cv例题语句
|
12天前
|
SQL 关系型数据库 MySQL
【MySQL】DQL-条件查询语句全解(附带代码演示&案例练习)
【MySQL】DQL-条件查询语句全解(附带代码演示&案例练习)
|
12天前
|
SQL 关系型数据库 MySQL
【MySQL】DQL-基础查询-语句&演示(查询多个字段 / 所有字段/并设置别名/去重)
【MySQL】DQL-基础查询-语句&演示(查询多个字段 / 所有字段/并设置别名/去重)
|
12天前
|
SQL 关系型数据库 MySQL
【MySQL系列笔记】常用SQL
常用SQL分为三种类型,分别为DDL,DML和DQL;这三种类型的SQL语句分别用于管理数据库结构、操作数据、以及查询数据,是数据库操作中最常用的语句类型。 在后面学习的多表联查中,SQL是分析业务后业务后能否实现的基础,以及后面如何书写动态SQL,以及完成级联查询的关键。
195 6