MySQL基础图解

Posted Guarding and trust

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL基础图解相关的知识,希望对你有一定的参考价值。

不为失败找理由,只为成功找方法。所有的不甘,因为还心存梦想,所以在你放弃之前,好好拼一把,只怕心老,不怕路长。

文章目录


一、学习目标

  • 本章要熟练掌握SQL语言里的DQL语句。
  • 重点为DQL的复杂多表查询

二、本章内容

本章主要内容是SQL语言里的重中之重–DQL语句,也叫数据查询,数据查询可以根据用户提供的限定条件,从已存在的数据表中检索用户需要的数据。mysql使用SELECT语句从数据库中检索数据并将结果集以表格的形式返回给用户。在学习之前,先准备几张表,这几张表属于mydb数据库。后面的内容都是围绕这几张表来做示例:


1. SELECT语句基础操作

使用SELECT不但可以从数据库中精确地查询信息,而且可以模糊地查找带有某项特征的多条数据。基本语法如下所示:

SELECT [ALL|DISTINCT] 要查询的内容
FROM 表名列表
[WHERE 条件表达式]
[GROUP BY 字段名列表 [HAVING 逻辑表达式] ]
[ORDER BY 字段名[ASC|DESC] ]
[LIMIT [OFFSET,] n];

其中。关键字的说明如下:
(1)要查询的内容:可以是字段、表达式或者函数。若是要查询部分字段,需要将各字段名用英文逗号分隔开,各字段名在SELECT子句中的顺序决定了它们在结果中显示的顺序。用"*"代表返回所有字段。
(2)ALL|DISTINCT:用来标识在查询结果集中对相同行的处理方式。默认值是ALL(不去重)。
        ① 关键字ALL代表返回查询结果集中的所有行,包括重复行。
        ② 关键字DISTINCT代表若查询结果集中有相同的行,则显示一行
(3)FROM表名列表:指定用于查询的数据表的名称。
(4)WHRER条件表达式:用于指定数据查询的条件。
(5)GROUP BY字段名列表:用来指定查询结果根据说明字段分组。
(6)HAVING逻辑表达式:用来指定对分组的过滤条件,选择出满足查询条件的分组记录集。
(7)ORDER BY 字段名[ASC|DESC]:结果集的排序方式。ASC表示升序,DESC表示降序。默认为升序ASC。
(8)LIMIT[OFFSET,] n:用于限制查询结果的数量。LIMIT后面可以跟两个参数,第一个参数“OFFSET”表示偏移量,可选的,默认值为0。这个表示从哪个位置开始查询,比如为偏移量为1,则从查询结果的第二条记录开始显示。第二个参数“n”表示返回的查询记录的条数。

1.1 基本查询

        基本查询只包括两部分,也是SELECT查询语句中必选的子句。

SSELECT [ALL|DISTINCT] 要查询的内容
FROM 表名列表;

【说明】① SELECT子句指定查询结果要输出的字段名。② FROM子句指定提供数据的表的名称。
示例1:查询mydb数据库中的studentinfo表,输出所有学生的详细信息。

# SQL语句 *:代表所有字段,每个字段用英文的逗号隔开
SELECT * FROM studentinfo;

执行结果图:

示例2:查询mydb数据库中的studentinfo表,输出所有班级,不可重复。

# 使用DISTINCT关键字可以消除查询结果集中重复的行
SELECT DISTINCT sclass FROM studentinfo;

执行结果图:

1.2 引用别名

使用SELECT语句进行查询时,查询结果集中字段的名称与SELECT子句字段的名称相同。也可以在SELECT语句中,让查询结果集显示新的字段名,而这称为 字段的别名。 指定返回字段的别名有两种方法:

1. 字段名 AS 别名
2. 字段名 别名

示例3:查询mydb数据库中studentinfo表,输出所有学生的学号、姓名、性别,并分别使用“学生学号”、“学生姓名”和“学生性别”作为别名。

# MySQL对于大小写不敏感
SELECT sid 学生学号, sname AS 学生姓名, sgender as 学生性别 
FROM studentinfo;

执行结果图:

1.2 条件 ----- WHERE子句

WHERE子句可以指定查询条件,用于从数据表中筛选出满足条件的数据行。其语法格式如下:

SELECT [ALL|DISTINCT] 要查询的内容 FROM 表名列表 WHERE 条件表达式;

其中WHERE子句的条件表达式可以使用的运算符如下所示:

运算符分类运算符说明
比较运算符>、>=、=、<、<=、<>、!=、!>、!<比较字段值的大小
范围运算符BETWEEN … ADN、NOT BETWEEN … AND判断字段值是否在指定的范围内
列表运算符IN、NOT IN判断字段值是否在指定的列表中
模式匹配运算符LIKE、NOT LIKE判断字段值是否和指定的模式字符串匹配
空值判断运算符IS NULL、IS NNOT NULL判断字段值是否为空
逻辑运算符AND、OR、NOT用于多个条件表达式的逻辑连接

下面我们就一一详解。
        ① 比较运算符的使用
示例4:查询mydb数据库中studentinfo表,输出“大数据1班”学生的详细信息。

# 使用 = 运算符来就可以实现
SELECT * FROM studentinfo WHERE sclass = "大数据1班";

执行结果图:

        ② 范围运算符的使用
示例5:查询mydb数据库中studentinfo表,输出1999~2000年出生的学生的详细信息。

# 使用BETWEEN ... AND
SELECT * FROM studentinfo WHERE sbirth BETWEEN '1999-01-01' AND '2000-12-12';
# 由于日期和时间类型是一个特殊的数据类型,所以还可以使用加、减以及比较大小操作
SELECT * FROM studentinfo WHERE sbirth >= '1999-01-01' AND sbirth <= '2000-12-12';

执行结果图:

        ③ 列表运算符的使用
示例6:查询mydb数据库中studentinfo表,输出学号为1001、1002、101的学生的详情信息。

# 使用IN运算符可以完成此操作
SELECT * FROM studentinfo WHERE sid IN('1001','1002','101');

执行结果图:


        ④ 模式匹配运算符的使用
在指定的条件不是很明确的情况下,可以使用LIKE运算符与字符串进行匹配运算。语法如下:

字段名 [NOT] LIKE '字符串';

【参数说明:】
(1)字段名:指明要进行匹配的字段。字段的数据类型可以是字符串类型或者日期和时间类型。
(2)字符串:可以是普通字符串,也可以是包含通配符的字符串。通配符类型如下:

通配符含义
%匹配任意长度(0个或多个)的字符串。
_匹配任意单个字符

【注意】需要转义的使用 “\\”。
示例7:查询数据库mydb中studentinfo表,输出姓“张”的学生的详细信息。

SELECT * FROM studentinfo WHERE sname  LIKE '张%';

执行结果图:

        ⑤ 空值判断运算符的使用
IS[NOT]NULL运算符用于判断指定字段的值是否为空值。对于空值判断,不能使用比较运算符或者模式运算符。
示例8:查询mydb数据库中elective表,输出没有成绩的学生的信息

SELECT * FROM elective WHERE score IS NULL;

执行结果图:

        ⑥ 逻辑运算符的使用
查询条件可以是一个条件表达式,也可以是多个条件表达式的组合。逻辑运算符能够连接多个条件表达式,构成一个复杂的查询条件。逻辑运算符有一下几种:

运算符含义
AND(逻辑与)当且仅当两个条件表达式都成立,组合起来的条件就成立
OR(逻辑或)两个条件表达式之一成立,组合起来的条件就成立
NOT(逻辑非)对给定条件取反

示例9:查询mydb数据库中studentinfo表,输出不是1999年出生的学生信息。

# 这里可以使用函数YEAR() 获取指定的年份
SELECT * FROM studentinfo WHERE NOT(YEAR(sbirth)=1999);

执行结果图:

1.3 排序 ----- ORDER BY子句

    在查询结果集中,数据行是按照它们在表中的顺序进行排序的。我们可以使用ORDER BY子句对查询结果集中的数据行依照指定字段的值重新排序。语法如下:

# ORDER BY子句要写在WHERE子句的后面
SELECT [ALL|DISTINCT] 要查询的内容 FROM 表明列表 [WHERE 条件表达式] ORDER BY 字段名 [ASC|DESC];

示例10:查询mydb数据库中elective表,输出选修了101号课程的学生信息,并且将查询结果按成绩的降序排序。

SELECT sid 学号,cid 课程编号, score as 成绩 FROM elective WHERE cid = '101' ORDER BY score DESC;

执行结果图:

1.4 检索 ----- LIMIT子句

使用LIMIT子句可以指定查询结果从哪一条记录开始,一共查询多少条记录。一般开发场景于分页查询。语法如下:

SELECT [ALL|DISTINCT] 要查询的内容 
FROM 表名列表 
[WHERE 条表达式] 
[ORDER BY 字段名 [ASC|DESC] 
LIMIT [OFFFSET,  n;

示例11-1:查询mydb数据库的studentinfo表,输出前五条学生记录的信息。

SELECT * FROM studentinfo LIMIT 5;

执行结果图:

示例11-2:查询mydb数据库的studentinfo表,从第3行开始输出2条学生记录的信息。

# 索引默认为0
SELECT * FROM studentinfo LIMIT 3,2;

执行结果图:

2. 统计查询

    SELECT语句可以通过集合函数和GROUP BY子句、HAVING子句的组合对查询结果集进行求和、求平均值、求最大值、求最小值、分组等统计查询。

2.1 集合函数

    集合函数用于对查询结果集中的指定字段进行统计,并输出统计值。常用的集合函数如表所示:

集合函数功能描述
COUNT([DISTINCT 或 ALL]字段或 *)计算指定字段中值的个数。COUNT(*)返回满足条件的行数,包括含有空值的行,不能与DISTINCT一起使用。
SUM([DISTINCT 或 ALL]字段)计算指定字段中数据的总和(此字段为数值类型)
AVG([DISTINCT 或 ALL]字段)计算指定字段中数据的平均值(此字段为数值类型)
MAX([DISTINCT 或 ALL]字段)计算指定字段中数据的最大值
MIN([DISTINCT 或 ALL]字段)计算指定字段中数据的最小值

示例12:查询mydb数据库中的elective表,统计选修了101号课程的学生人数、总成绩、平均分、最高分和最低分。

SELECT COUNT(*) AS 学生人数,SUM(score) AS 总成绩, 
AVG(score) as 平均分, MAX(score) 最高分, MIN(score) 最低分 
FROM elective WHERE cid = '101';

执行结果图:

2.2 分组 ----- GROUD BY子句

    该子句用于对查询结果集按指定字段的值进行分组,字段值相同的放在一组。和集合函数配合使用,可以对查询结果集进行分组统计。语法如下:

SELECT [ALL| DISTINCT] 要查询的内容
FROM 表名列表 [WHERE 条件表达式] 
GROUP BY 字段名列表 [HAVING条件表达式];

【注意】使用GROUP BY子句进行分组统计时,SELECT子句要查询的字段只能是以下两种情况:

1. 字段应用了集合函数。
2. 未应用集合函数的字段必须包含在GROUP BY子句中。  

示例13-1:查询elective表,统计并输出每个学生所选课程数目及平均分。

SELECT sid,COUNT(cid) AS 选修课程数目, AVG(score) AS 平均分 FROM elective 
GROUP BY sid;

执行结果图:

示例13-2:查询至少选修了三门课程的学生的学号。

SELECT sid 学号,count(*) 选修课程数 FROM elective GROUP BY sid HAVING count(*) >= 3;

执行结果图:

2.3 WHERE子句和HAVING子句的区别与GROUP BY子句之间的执行顺序

(1)WHERE子句设置的查询筛选条件在GROUP BY子句之前发生作用,并且条件中不能使用集合函数是。
(2)HAVING子句设置的查询筛选条件在GROUP BY子句之后发生作用,并且条件中运行使用集合函数是。
(3)执行顺序如下:

  1. 执行WHERE子句,,从数据表中选取满足条件的数据行。
  2. 由GROUP BY子句对选取的数据行进行分组。
  3. 执行集合函数。
  4. 执行HAVING子句,选取满足条件的分组。

3. 连接查询

连接查询值在表与表之间建立关系,然后进行查询获取两表中预想的数据结果集。而连接方式以及运算符由以下几种:
(1)CROSS JOIN:交叉连接
(2)INNER JOIN或JOIN:内连接
(3)LEFT JOIN或LEFT OUTER JOIN:左外连接
(4)RIGHT JOIN或RIGHT OUTER JOIN:右外连接
(5)FULL JOIN或FULL OUTER JOIN:完全连接

3.1 交叉连接(了解)

    将要连接的两个表的所有行进行组合,也就是将第一个表的所有行分别与第二个表的每一行连接形成一个新的行。连接后生成的结果集(也称笛卡尔积)的行数等于两个表的行数的乘积,字段个数等于两个表的字段个数的和。语法格式如下:

SELECT 字段名列表 FROM 表名1 CROSS JOIN 表名2;

3.2 内连接(重点)

    内连接是指用比较运算符设置连接条件,只返回满足连接条件的数据行,是将交叉连接生成的结果集按照连接条件进行筛选后形成的。
内连接有以下两种语法格式:

SELECT 字段名列表 FROM 表名1 [INNER] JOIN 表名2 
ON 表名1.字段名 比较运算符 表名2.字段名;
# 或者
SELECT 字段名列表 FROM 表名1,表名2 
WHERE 表名1.字段名 比较运算符 表名2.字段名;

内连接包括3种类型:等值连接、非等值连接和自然连接。
(1)等值连接:在连接条件中使用等号(=) 比较运算符比较连接字段的值,其查询结果中包含被连接表的所有字段,包括重复字段。在等值连接中,两个表的连接条件通常采用“表1.主键字段=表2.外键字段的形式。(不建议使用外键,可以使用表2的主键)
(2)非等值连接:在连接条件中使用了除等号之外的比较运算符(>、<、>=、<=、!=)来比较连接字段的值。
(3)自然连接:与等值连接相同,都是在连接条件中使用比较运算符,但结果集中不包括重复字段。
表R和表S进行等值连接、非等值连接和自然连接的结果集如下表所示:

(等值连接)
R.ABCS.AD
12312
(非等值连接)
R.ABCS.AD
45612
45634
(自然连接)
R.ABCD
1232

    在上述表格中,如果要输出的字段是表1和表2都有的字段,则必须在输出的字段名前加上表名进行区别,用 “表名.字段名” 来表示。如果表名太长,可以表名定义一个简短的别名,以便后面的操作。
示例14:查询mydb数据库,输出考试成绩80分以上学生的学号、姓名、课程名、成绩。
【需求分析】完成本查询需要用到三个表:studentinfo表、course表、elective表。这三个表的连接查询是通过表的两两连接来实现的。elective表和studentinfo表有同样的字段“学号”,elective表和course表有同样字段 “课程号”,所以elective表作为逻辑中间表,可以先和studentinfo表连接,再和course表连接。(先后连接顺序不固定)SQL语句如下:

SELECT s.sid,sname,cname,score 
FROM studentinfo AS s JOIN elective AS e ON s.sid = e.sid 
JOIN course AS c ON c.cid = e.cid 
WHERE score > 80;
# 或者:
SELECT s.sid,sname,cname,score 
FROM studentinfo AS s, elective AS e, xourse AS c 
WHERE s.sid = e.sid AND e.cid = c.cid AND score > 80;

执行结果图:

3.3 外连接(重点)

    外连接与内连接不同,有主从表之分。使用外连接时,以主表中每行数据去匹配从表中的数据行,如果符合连接条件则返回到结果集中;如果没有找到匹配的数据行,则在结果集中仍然保留主表的数据行,对应的从表的字段则被填上NULL值。外连接查询只适用于两表。其语法如下:

SELECT 字段名列表 FROM 表名1 LEFT|RIGHT JOIN2 
ON 表名1.字段名 比较运算符 表名2.字段名;

外连接包括3中类型:左外连接、右外连接、全外连接。
(1)左外连接:即左表为主表,连接关键字为LEFT JOIN。将左表中的所有数据行与右表中的每行按连接条件进行匹配,结果集中包括左表中所有数据行。左表中与右表没有相关匹配记录的数据行,则用NULL值。BIT类型不允许为NULL,以0填充。
(2)右外连接:该连接与左外连接很类似,区别是主表为右表,连接关键字为RIGHT JOIN。其他条件大同小异。
(3)全外连接:连接关键字为FULL JOIN。查询结果集中包括两个连接表的所有的数据行,若左表中每一行在右表中有匹配数据,则结果集中对应的右表的字段填入相应数据,否则填充为NULL;若右表中某一行在左表中没有数据,则结果集对应的左表字段填充为NULL。
示例15:查询mydb数据库,输出所有教师任课的课程信息,没有任课课程的教师也要列出。

# 该查询需要teacher表和course表,而且主表为teacher
SELECT * FROM teacher AS t LEFT JOIN course AS c ON t.tcid = c.tid;

执行结果图:

3.4 自连接

    自连接就是一个表的两个副本之间的内连接,即同一个表名在FROM子句中出现,故为了区别,必须对表指定不同的别名,字段名前也要加上表的别名进行限定。
示例16:查询和学号为101的学生在同一个班级的学生的学号和姓名。

SELECT s2.sid,s2.sname FROM studentinfo AS s1 JOIN studentinfo AS s2 
ON s1.sclass = s2.sclass 
WHERE s1.sid = '101' AND s2.sid != '101';

执行结果图:

4. 子查询(嵌套查询)

    子查询是将一个SELECT语句嵌套在另一个SELECT语句的WHERE子句中的查询。包含子查询的SELECT语句称为父查询或外部查询。子查询可以多层嵌套,执行时由内到外,即每一个子查询在其上一级父查询之前被处理,其查询结果会返回给父查询。

4.1比较子查询

比较子查询是指在父查询与子查询之间用比较运算符进行连接查询,且子查询返回的值最多只能有一个。
示例17:查询mydb数据库,输出选修了“MySQL”这门课程的所有学生的学号和成绩

# 先用子查询查找出“MySQL”这门课程的课程号,
# 再用父查询查找出课程号使用比较运算符(=)等于子查询找到的课程号的那些数据行,
# 输出其学号和成绩
SELECT sid, score AS MySQL的成绩 
FROM elective 
WHERE cid = (SELECT cid FROM course WHERE cname = 'MySQL');

执行结果图:

4.2 IN子查询

    IN子查询是指父查询与子查询之间用IN或NOT IN进行连接并判断某个字段的值是否在子查询查到的集合中。
示例18:查询mydb数据库,输出考试80分以上的学生的姓名。

SELECT sname as 成绩80分以上的学生 
FROM studentinfo 
WHERE sid IN(SELECT sid FROM elective WHERE score >= 80);

执行结果图:

4.3 使用 ANY与ALL谓词

    ANY与ALL谓词可以批量比较子查询,但是它们又各有所长,异同点如下:
都是在子查询前面使用,使用指定的比较运算符将一个表达式的值或字段的值与每一个子查询返回值进行比较。ANY谓词只要又一次比较的结果为TRUE,则整个表达式的值为TRUE,否则为FALSE;而ALL谓词只有当所有比较的结果都为TRUE时,整个表达式的值才为TRUE,否则为FALSE。这里的情况就和逻辑与和逻辑或有些相似了。

4.4 EXISTS 子查询

    EXISTS子查询是指在子查询清明加上EXISTS运算符或NOT EXISTS运算符,构成EXISTS表达式。如果子查询查找到了满足条件的数据行,那么EXISTS表达式的返回值为TRUE,否则为FALES。
示例19:查询teacher表,若不存在具有教授职称的教师,则显示所有教师的姓名和职称。

SELECCT tname tpro FROM teacher 
WHERE NOT EXISTS(SELECT * FROM teacher WHERE tpro = '教授');

执行结果图:

4.5 在INSERT、UPDATE、DELETE语句使用子查(了解)

    子查询也可以嵌套在INSERT、UPDATE或DELETE语句中,但使用时需要注意如下几点:
(1)使用圆括号将子查询的SELECT语句括起来。
(2)当子查询的返回值为单个值时,子查询可以应用到任何表达式中。

4.5.1 在INSERT语句中使用子查询

# 语法格式:
INSERT1[(字段名列表1)] SELECT 字段名列表2 FROM2 [WHERE条件表达式];

【注意】使用本语句时,表1已经存在,且“字段名列表1”中字段的个数、字段的顺序、字段的数据类型必须和“字段名列表2”中对应的字段信息一样或者兼容。>

4.5.2 在UPDATE、DEKETE语句中使用子查询

这两种语句都是在WHERE子句中使用子查询。

5. 合并结果集

    合并结果集是指对多个SELECT语句查询的结果集进行合并操作,组合成一个结果集。其运算符是UNION,使用时需要注意如下几点:
(1)所有SELECT语句中的字段个数必须相同。
(2)所有SELECT语句中对应的字段的数据类型必须相同或者兼容。
(3)合并后的结果集中的字段名是第一个SELECT语句中各字段的字段名。如果要为返回的字段指定别名,则必须在第一个SELECT语句中指定。
(4)使用UNION运算符合并结果集时,每一个SELECT语句本身不能包含ORDER BY子句,只能在最后使用一共ORDER BY子句对整个结果集进行排序,且在该ORDER BY子句中必须使用第一个SELECT语句中的字段名。

示例20:对mydb数据库进行查询,输出所有学生和教师的编号和姓名

SELECT sid AS 编号, sname AS 姓名 FROM studentinfo 
UNION 
SELECT tid AS 编号, tname AS 姓名 FROM teacher;

执行结果图:

6. 多表查询的方式与一般应用场景

    多表查询是通过各个表之间的共同列的相关性来查询数据的。而前面学习的连接查询和子查询是实现多表查询的常用方式。而子查询和连接查询在很多情况下可以互换的,那么什么时候使用连接查询,什么时候使用子查询呢?可以参考以下几个原则:

1. 如果查询语句要输出的字段来自多个表时,用连接查询。
2. 如果查询语句要输出的字段来自一个表,但其WHERE子句涉及另一个表时,常用子查询。
3. 如果查询语句要输出的字段和WHERE子句都只涉及一个表,但是WHERE子句的查询条件涉及应用集合函数进行数值比较时,一般用子查询。

三、写在最后

本章全面讲解了MySQL中的DQL语句。查询是数据库最常用的操作,MySQL使用SELECT语句进行数据查询。最后如果本篇内容对你有所帮助,请给作者点个赞留下你的足迹。

作者功底有限,本篇内容中如有不妥或错误之处可进行相关技术交流。

以上是关于MySQL基础图解的主要内容,如果未能解决你的问题,请参考以下文章

图解冒泡排序,鸡尾酒排序

数据库查询分组排序

算法基础部分整理-《图解算法》

select语句对对查询结果排序时,用( )子句指定排序字段,使用( )指定升序,使用( )降序。

已有a,b两个链表,每个链表中的结点包括学号,成绩。要求把两个链表合并,按学号升序排列。

MySQL基础图解