06.MySQL数据库操作详解
06.MySQL数据库操作详解:CRUD与查询优化
📚 文章目录
1️⃣ MySQL表的增删查改
- CRUD操作的核心地位
2️⃣ Create - 数据新增
- 单行全列插入
- 多行指定列插入
- 插入否则更新
- 替换数据
3️⃣ Retrieve - 数据查询
- 全列查询
- 指定列查询
- 表达式查询
- 结果去重
4️⃣ WHERE条件筛选
- 英语不及格同学查询
- 语文成绩区间筛选
- 数学成绩特定值查询
- 模糊匹配查询
- NULL值处理
5️⃣ 结果排序
- 基础升序/降序
- 多字段组合排序
6️⃣ 分页查询
- LIMIT分页实现
7️⃣ Update - 数据更新
- 单记录字段更新
- 批量条件更新
8️⃣ Delete - 数据删除
- 条件删除
- 整表清空对比
- TRUNCATE优化
9️⃣ 插入查询结果
- 去重数据迁移
🔟 聚合函数
- COUNT统计
- SUM/AVG计算
- MAX/MIN极值
🔟① 分组查询
- GROUP BY基础
- HAVING过滤
1. MySQL表的增删查改
表的增删查改简称CRUD:Create(新增)、Retrieve(查找)、Update(修改)、Delete(删除)。这四类操作构成了数据库操作的核心,也是我们日常使用MySQL进行数据管理时最常用的功能。这些操作的对象是对表当中的数据,它们属于典型的DML(Data Manipulation Language)数据操作语言。
CRUD操作贯穿了数据库开发与维护的全过程。无论是业务系统上线初期的数据初始化,还是后续的数据维护、分析与统计,CRUD都是不可或缺的基础。Create操作用于向表中添加新记录,是构建数据仓库的第一步;Retrieve操作则是从数据库中提取数据,是查询和数据分析的核心;Update操作用于调整已有数据的状态,保证数据的准确性;而Delete操作则用于清理无效或冗余的数据,维护数据库的整洁性。
在实际应用中,CRUD操作不仅需要熟练掌握SQL语法,还需要理解其背后的执行逻辑。例如,在插入数据时,如何避免主键或唯一键冲突?在查询数据时,如何高效地筛选出目标记录?在更新或删除数据时,如何精准定位目标记录?这些问题都涉及数据库操作的细节,需要我们在实践中不断积累经验。
此外,CRUD操作的优化也是数据库性能调优的重要方向。例如,频繁的插入操作可能导致数据库性能下降,而高效的查询优化可以显著提升响应速度。因此,深入理解CRUD操作的原理,并结合实际场景进行优化,是提升数据库性能的关键。
接下来,我们将详细介绍CRUD操作的具体实现方式,包括数据插入、查询、修改和删除的SQL语法及其使用场景。通过这些内容的学习,你将掌握如何高效地管理数据库中的数据,并能够根据实际需求灵活运用这些操作。
2. Create
新增数据是数据库操作中最基础的一环,它允许我们向表中添加新的记录。在MySQL中,新增数据主要通过INSERT
语句来完成,该语句支持多种不同的插入方式,以满足不同的业务需求。
单行数据 + 全列插入
最基本的插入方式是单行数据全列插入。在这种模式下,我们不需要指定具体的列名,而是按照表中列的默认顺序依次提供所有列的值。例如,假设我们有一个学生表students
,其中包含id
、name
、age
三个字段,那么插入一条完整记录的方式如下:
INSERT INTO students VALUES (1, '张三', 20);
这里需要注意的是,如果我们没有显式指定列名,那么VALUES
后面的值必须严格按照表中列的顺序填写,并且不能遗漏任何一列的值。如果某列允许NULL
值或具有默认值,也可以省略不写,但如果不满足这些条件,就会导致插入失败。
多行数据 + 指定列插入
除了单行插入,我们还可以一次性插入多条记录,这样可以减少数据库的交互次数,提高插入效率。此外,在插入数据时,我们也可以选择只插入部分列的数据,而不是所有列。例如,如果我们只想插入name
和age
两个字段的值,可以使用如下语句:
INSERT INTO students (name, age) VALUES
('李四', 22),
('王五', 21);
这种方式不仅提高了插入效率,还增强了SQL语句的可读性。在实际开发中,我们通常会根据业务需求选择是否插入所有列或部分列。
插入否则更新
在某些情况下,我们可能会遇到主键或唯一键冲突的问题。例如,当我们尝试插入一条已经存在的记录时,数据库会抛出错误。为了避免这种情况,我们可以使用INSERT ... ON DUPLICATE KEY UPDATE
语句。该语句的作用是,如果插入的记录不存在冲突,则直接插入;如果存在冲突,则自动执行更新操作。例如:
INSERT INTO students (id, name, age) VALUES (1, '张三', 20)
ON DUPLICATE KEY UPDATE name = '张三', age = 20;
如果表中已经存在id=1
的记录,那么这条SQL语句会自动执行UPDATE
部分,更新name
和age
字段的值。
替换数据
除了插入否则更新,我们还可以使用REPLACE
语句来实现类似的效果。REPLACE
语句的作用是,如果插入的数据存在主键或唯一键冲突,则先删除冲突的记录,然后再插入新的记录。例如:
REPLACE INTO students (id, name, age) VALUES (1, '张三', 20);
与INSERT ... ON DUPLICATE KEY UPDATE
不同,REPLACE
语句不会直接更新冲突记录的值,而是先删除旧记录,再插入新记录。这意味着,如果表中存在外键约束或其他依赖关系,使用REPLACE
可能会带来额外的风险。因此,在实际开发中,我们需要根据具体业务场景选择合适的插入方式。
3. Retrieve
查询数据是数据库操作中最常用的功能之一,它允许我们从表中提取符合特定条件的记录。在MySQL中,查询数据主要通过SELECT
语句来完成。该语句支持多种不同的查询方式,以满足不同的业务需求。
全列查询
最基本的查询方式是全列查询,即使用SELECT *
语句获取表中的所有列数据。例如,假设我们有一个成绩表scores
,其中包含id
、name
、chinese
、math
、english
五个字段,那么查询所有数据的方式如下:
SELECT * FROM scores;
这种方式的优点是可以一次性获取表中的所有数据,适用于需要查看完整数据的情况。然而,在实际开发中,我们通常不会使用SELECT *
进行查询,因为这种方式会返回表中的所有列,增加了网络传输的负担。此外,如果表中存在大量数据,使用SELECT *
可能会导致性能下降。因此,在实际开发中,我们通常会选择只查询所需的列。
指定列查询
除了全列查询,我们还可以选择只查询部分列的数据。例如,如果我们只想查询name
和math
两个字段的值,可以使用如下语句:
SELECT name, math FROM scores;
这种方式不仅减少了网络传输的数据量,还提高了查询效率。在实际开发中,我们通常会根据业务需求选择是否查询所有列或部分列。
查询字段为表达式
除了直接查询表中的列,我们还可以在SELECT
语句中使用表达式来计算新的字段值。例如,如果我们想查询每位同学的总成绩,可以使用如下语句:
SELECT name, chinese + math + english AS total_score FROM scores;
这里,chinese + math + english
是一个表达式,它计算每位同学的三门成绩之和,并将结果命名为total_score
。这种方式适用于需要动态计算新字段的场景。
为查询结果指定别名
在使用表达式查询时,我们通常会给计算出的新字段指定一个别名,以提高查询结果的可读性。例如,在上面的例子中,我们使用AS
关键字为总成绩字段指定了别名total_score
。除了表达式查询,我们也可以为普通的列指定别名,例如:
SELECT name AS student_name, math AS math_score FROM scores;
这种方式可以让查询结果更加直观,特别是在编写复杂的SQL语句时,合理的别名可以大大提高代码的可读性。
结果去重
在查询数据时,我们可能会遇到重复的记录。例如,如果我们只想查询所有不同的数学成绩,可以使用DISTINCT
关键字来去除重复值:
SELECT DISTINCT math FROM scores;
这种方式适用于需要统计不同值的场景。需要注意的是,DISTINCT
关键字会对查询结果进行去重,因此在查询大数据量时可能会导致性能下降。
通过上述几种查询方式,我们可以灵活地从表中提取所需的数据,并根据业务需求进行适当的优化。在实际开发中,我们通常会结合使用这些查询方式,以满足不同的数据查询需求。
4. WHERE 条件
在查询数据时,我们通常不会直接查询整个表的所有数据,而是希望筛选出符合特定条件的记录。这时就需要使用WHERE
子句来指定查询条件。WHERE
子句允许我们根据一个或多个条件来过滤数据,从而得到我们需要的结果。
查询英语不及格的同学及其英语成绩
假设我们想查询英语成绩不及格的同学,即英语成绩小于60分的同学。我们可以使用如下SQL语句:
SELECT name, english FROM scores WHERE english < 60;
这里的WHERE
子句指定了筛选条件为english < 60
,即英语成绩小于60分。该查询会返回所有符合条件的同学的姓名和英语成绩。
查询语文成绩在80到90分的同学及其语文成绩
如果我们想查询语文成绩在80到90分之间的同学,可以使用WHERE
子句结合比较运算符来实现。例如:
SELECT name, chinese FROM scores WHERE chinese >= 80 AND chinese <= 90;
这里我们使用了>=
和<=
运算符来限定语文成绩的范围,并使用AND
逻辑运算符来确保同时满足两个条件。
此外,我们还可以使用BETWEEN
关键字来简化这个查询:
SELECT name, chinese FROM scores WHERE chinese BETWEEN 80 AND 90;
BETWEEN
关键字的作用是匹配某个范围内的值,包括边界值。因此,chinese BETWEEN 80 AND 90
等价于chinese >= 80 AND chinese <= 90
。
查询数学成绩是58或59或98或99分的同学及其数学成绩
如果我们想查询数学成绩是58、59、98或99分的同学,可以使用IN
关键字来简化查询。例如:
SELECT name, math FROM scores WHERE math IN (58, 59, 98, 99);
IN
关键字的作用是判断某个字段是否在给定的集合中。因此,math IN (58, 59, 98, 99)
等价于math = 58 OR math = 59 OR math = 98 OR math = 99
。
分别查询姓孙的同学和孙某同学
如果我们想查询所有姓孙的同学,可以使用LIKE
关键字配合通配符来实现。例如:
SELECT name FROM scores WHERE name LIKE '孙%';
这里的LIKE
关键字用于模糊匹配,%
是通配符,表示任意数量的字符。因此,name LIKE '孙%'
表示匹配所有以“孙”开头的名字。
如果我们想查询名字为“孙某”的同学,即姓孙且名字只有一个字的同学,可以使用如下语句:
SELECT name FROM scores WHERE name LIKE '孙_';
这里的_
是通配符,表示任意一个字符。因此,name LIKE '孙_'
表示匹配所有以“孙”开头且总长度为2的姓名。
查询语文成绩好于英语成绩的同学
如果我们想查询语文成绩优于英语成绩的同学,可以使用比较运算符来实现。例如:
SELECT name, chinese, english FROM scores WHERE chinese > english;
这里的WHERE
子句指定了筛选条件为chinese > english
,即语文成绩大于英语成绩。该查询会返回所有符合条件的同学的姓名、语文成绩和英语成绩。
查询总成绩在200分以下的同学
如果我们想查询总成绩低于200分的同学,可以使用表达式查询来计算总成绩,并在WHERE
子句中指定筛选条件。例如:
SELECT name, chinese + math + english AS total_score FROM scores WHERE chinese + math + english < 200;
这里的WHERE
子句指定了筛选条件为chinese + math + english < 200
,即三门成绩之和小于200分。
需要注意的是,在WHERE
子句中不能直接使用SELECT
中定义的别名,因为WHERE
子句的执行顺序早于SELECT
语句。因此,我们不能使用如下方式:
SELECT name, chinese + math + english AS total_score FROM scores WHERE total_score < 200; -- 错误
这种写法会导致SQL报错,因为WHERE
子句无法识别total_score
这个别名。
查询语文成绩大于80分并且不姓孙的同学
如果我们想查询语文成绩大于80分且不姓孙的同学,可以使用NOT
关键字来排除姓孙的同学。例如:
SELECT name, chinese FROM scores WHERE chinese > 80 AND name NOT LIKE '孙%';
这里的NOT LIKE '孙%'
表示排除所有以“孙”开头的姓名。
查询孙某同学,否则要求总成绩大于200分并且语文成绩小于数学成绩并且英语成绩大于80分
如果我们想查询“孙某”同学,或者总成绩大于200分、语文成绩小于数学成绩、英语成绩大于80分的同学,可以使用逻辑运算符OR
来组合多个条件。例如:
SELECT name, chinese, math, english, chinese + math + english AS total_score
FROM scores
WHERE name LIKE '孙_' OR (chinese + math + english > 200 AND chinese < math AND english > 80);
这里的WHERE
子句使用了OR
逻辑运算符,表示满足任一条件即可。第一个条件是name LIKE '孙_'
,即名字为“孙某”的同学;第二个条件是chinese + math + english > 200 AND chinese < math AND english > 80
,即总成绩大于200分、语文成绩小于数学成绩、英语成绩大于80分的同学。
NULL 的查询
在数据库中,NULL
表示未知或缺失的值。在查询数据时,我们可能需要筛选出NULL
值或非NULL
值。例如,如果我们想查询QQ号已知的同学,可以使用如下语句:
SELECT name, qq FROM students WHERE qq IS NOT NULL;
这里的IS NOT NULL
表示筛选出QQ号不为NULL
的同学。
如果我们想查询QQ号未知的同学,可以使用如下语句:
SELECT name, qq FROM students WHERE qq IS NULL;
需要注意的是,在判断NULL
值时,不能使用=
或!=
运算符,而应该使用IS NULL
或IS NOT NULL
。例如,如下写法是错误的:
SELECT name, qq FROM students WHERE qq = NULL; -- 错误
这是因为NULL
表示未知值,使用=
运算符无法正确判断NULL
值。因此,正确的写法应该是使用IS NULL
或IS NOT NULL
。
5. 结果排序
在查询数据时,我们通常希望结果按照某种顺序排列,以便更直观地查看数据。MySQL 提供了 ORDER BY
子句,用于对查询结果进行排序。排序可以是升序(ASC
)或降序(DESC
),默认情况下为升序。
查询同学及其数学成绩,按数学成绩升序显示
如果我们想查询所有同学的姓名及其数学成绩,并按数学成绩升序排列,可以使用如下 SQL 语句:
SELECT name, math FROM scores ORDER BY math ASC;
这里的 ORDER BY math ASC
表示按照数学成绩升序排序。如果省略 ASC
或 DESC
,默认会按照升序排序。
查询同学及其 QQ 号,按 QQ 号排序显示
如果我们想查询同学的姓名及其 QQ 号,并按 QQ 号排序显示,可以使用如下 SQL 语句:
SELECT name, qq FROM students ORDER BY qq;
默认情况下,ORDER BY
会按升序排列。如果想按降序排列,可以使用 DESC
关键字,例如:
SELECT name, qq FROM students ORDER BY qq DESC;
需要注意的是,NULL
值在排序时会被视为比任何值都小。因此,在升序排序时,NULL
值会出现在最前面;在降序排序时,NULL
值会出现在最后面。
查询同学的各门成绩,依次按数学降序、英语升序、语文升序显示
如果我们想查询同学的各门成绩,并按数学成绩降序、英语成绩升序、语文成绩升序排列,可以使用如下 SQL 语句:
SELECT name, math, english, chinese FROM scores
ORDER BY math DESC, english ASC, chinese ASC;
这里的 ORDER BY
子句指定了多个排序字段,排序优先级与书写顺序相同。也就是说,首先按照数学成绩降序排列,如果数学成绩相同,再按照英语成绩升序排列,如果英语成绩也相同,再按照语文成绩升序排列。
查询同学及其总分,按总分降序显示
如果我们想查询同学的姓名及其总分,并按总分降序排列,可以使用如下 SQL 语句:
SELECT name, chinese + math + english AS total_score FROM scores
ORDER BY total_score DESC;
这里我们使用了表达式查询来计算每位同学的总分,并为该表达式指定了别名 total_score
。在 ORDER BY
子句中,我们可以直接使用该别名进行排序,因为 ORDER BY
的执行顺序在 SELECT
之后。
查询姓孙的同学或姓曹的同学及其数学成绩,按数学成绩降序显示
如果我们想查询姓孙或姓曹的同学,并按数学成绩降序排列,可以使用如下 SQL 语句:
SELECT name, math FROM scores
WHERE name LIKE '孙%' OR name LIKE '曹%'
ORDER BY math DESC;
这里的 WHERE
子句用于筛选出姓孙或姓曹的同学,ORDER BY math DESC
表示按数学成绩降序排列。
通过 ORDER BY
子句,我们可以灵活地对查询结果进行排序,使数据更加有序、直观。在实际开发中,我们通常会结合 SELECT
、WHERE
和 ORDER BY
来实现更复杂的查询需求。
6. 筛选分页结果
在查询数据时,如果数据量较大,我们通常不会一次性返回所有数据,而是采用分页的方式,每次只返回一部分数据。MySQL 提供了 LIMIT
子句,用于控制查询结果的分页显示。
按 id 进行分页,每页 3 条记录,分别显示第 1、2、3 页
假设我们有一个成绩表 scores
,其中包含 id
、name
、chinese
、math
、english
五个字段。如果我们想按 id
进行分页,每页显示 3 条记录,可以使用 LIMIT
子句来实现。
查询第 1 页记录
第一页的记录是从第 0 条开始,取 3 条记录:
SELECT * FROM scores ORDER BY id LIMIT 0, 3;
这里的 LIMIT 0, 3
表示从索引为 0 的记录开始,取 3 条记录。
查询第 2 页记录
第二页的记录是从第 3 条开始,取 3 条记录:
SELECT * FROM scores ORDER BY id LIMIT 3, 3;
这里的 LIMIT 3, 3
表示从索引为 3 的记录开始,取 3 条记录。
查询第 3 页记录
第三页的记录是从第 6 条开始,取 3 条记录:
SELECT * FROM scores ORDER BY id LIMIT 6, 3;
这里的 LIMIT 6, 3
表示从索引为 6 的记录开始,取 3 条记录。
需要注意的是,LIMIT
子句的索引是从 0 开始的,因此第一页的起始索引为 0,第二页的起始索引为 3,第三页的起始索引为 6,依此类推。
此外,LIMIT
子句还可以使用另一种写法:
SELECT * FROM scores ORDER BY id LIMIT 3 OFFSET 0; -- 第一页
SELECT * FROM scores ORDER BY id LIMIT 3 OFFSET 3; -- 第二页
SELECT * FROM scores ORDER BY id LIMIT 3 OFFSET 6; -- 第三页
这里的 LIMIT 3 OFFSET s
表示从索引为 s
的记录开始,取 3 条记录。
通过 LIMIT
子句,我们可以灵活地控制查询结果的分页显示,使数据更加有序、直观。在实际开发中,我们通常会结合 ORDER BY
和 LIMIT
来实现分页查询功能。
7. Update
修改数据是数据库操作中的重要环节,它允许我们对已有的记录进行更新,以确保数据的准确性和时效性。在 MySQL 中,修改数据主要通过 UPDATE
语句来完成。该语句允许我们根据特定条件修改表中的数据,并支持多种不同的修改方式。
将孙悟空同学的数学成绩修改为 80 分
假设我们有一个成绩表 scores
,其中包含 name
、math
等字段。如果我们想将孙悟空的数学成绩修改为 80 分,可以使用如下 SQL 语句:
UPDATE scores SET math = 80 WHERE name = '孙悟空';
这里的 UPDATE
语句指定了要修改的表名 scores
,SET
子句指定了要修改的列和新值,WHERE
子句用于定位需要修改的记录。
在执行修改操作之前,我们通常会先查询目标记录的当前值,以确保修改的准确性。例如:
SELECT * FROM scores WHERE name = '孙悟空';
执行上述查询后,我们可以确认孙悟空的数学成绩是否确实需要修改。如果确认无误,再执行 UPDATE
语句进行修改。修改完成后,我们还可以再次执行查询语句,以验证修改是否成功。
将曹孟德同学的数学成绩修改为 60 分,语文成绩修改为 70 分
如果我们想同时修改多个字段的值,可以在 SET
子句中指定多个列的修改。例如,如果我们想将曹孟德的数学成绩修改为 60 分,语文成绩修改为 70 分,可以使用如下 SQL 语句:
UPDATE scores SET math = 60, chinese = 70 WHERE name = '曹孟德';
这里的 SET
子句指定了两个字段的修改,分别是 math
和 chinese
。同样,我们可以在修改前后执行查询语句,以确保修改的准确性。
将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
如果我们想修改多个记录的值,可以结合 ORDER BY
和 LIMIT
子句来实现。例如,如果我们想将总成绩倒数前三的同学的数学成绩加上 30 分,可以使用如下 SQL 语句:
UPDATE scores
SET math = math + 30
ORDER BY (chinese + math + english) ASC
LIMIT 3;
这里的 ORDER BY (chinese + math + english) ASC
表示按照总成绩升序排列,LIMIT 3
表示取前 3 条记录。SET math = math + 30
表示将数学成绩增加 30 分。
需要注意的是,在执行此类操作之前,我们通常会先查询目标记录的当前值,以确保修改的准确性。例如:
SELECT name, chinese + math + english AS total_score
FROM scores
ORDER BY total_score ASC
LIMIT 3;
执行上述查询后,我们可以确认哪些同学的总成绩排名倒数前三。如果确认无误,再执行 UPDATE
语句进行修改。修改完成后,我们还可以再次执行查询语句,以验证修改是否成功。
将所有同学的语文成绩修改为原来的 2 倍
如果我们想修改整张表的某些字段的值,可以省略 WHERE
子句。例如,如果我们想将所有同学的语文成绩修改为原来的 2 倍,可以使用如下 SQL 语句:
UPDATE scores SET chinese = chinese * 2;
这里的 UPDATE
语句没有 WHERE
子句,表示修改整张表的所有记录。SET chinese = chinese * 2
表示将语文成绩乘以 2。
需要注意的是,在执行此类操作之前,我们通常会先查询所有记录的当前值,以确保修改的准确性。例如:
SELECT name, chinese FROM scores;
执行上述查询后,我们可以确认所有同学的语文成绩是否确实需要修改。如果确认无误,再执行 UPDATE
语句进行修改。修改完成后,我们还可以再次执行查询语句,以验证修改是否成功。
通过 UPDATE
语句,我们可以灵活地修改数据库中的数据,确保数据的准确性和时效性。在实际开发中,我们通常会结合 WHERE
、ORDER BY
和 LIMIT
来实现更复杂的修改需求。
8. Delete
删除数据是数据库操作中的重要环节,它允许我们从表中移除不再需要的记录。在 MySQL 中,删除数据主要通过 DELETE
语句来完成。该语句支持多种不同的删除方式,以满足不同的业务需求。
删除孙悟空同学的考试成绩
如果我们想删除某位特定同学的记录,可以在 DELETE
语句中使用 WHERE
子句来指定删除条件。例如,如果我们想删除孙悟空的考试成绩,可以使用如下 SQL 语句:
DELETE FROM scores WHERE name = '孙悟空';
这里的 DELETE FROM
语句指定了要删除的表名 scores
,WHERE
子句用于定位需要删除的记录。在执行删除操作之前,我们通常会先查询目标记录的当前值,以确保删除的准确性。例如:
SELECT * FROM scores WHERE name = '孙悟空';
执行上述查询后,我们可以确认孙悟空的考试成绩是否确实需要删除。如果确认无误,再执行 DELETE
语句进行删除。删除完成后,我们还可以再次执行查询语句,以验证删除是否成功。
删除整张表数据
如果我们想删除整张表的所有数据,可以省略 WHERE
子句。例如,如果我们想删除成绩表 scores
中的所有记录,可以使用如下 SQL 语句:
DELETE FROM scores;
这里的 DELETE FROM
语句没有 WHERE
子句,表示删除整张表的所有记录。需要注意的是,这种删除方式不会重置自增长字段的计数器。例如,如果我们删除整张表的数据后再次插入数据,自增长字段的值会继续从删除前的最大值开始递增。
截断表
如果我们想删除整张表的所有数据,并且希望重置自增长字段的计数器,可以使用 TRUNCATE
语句。例如,如果我们想清空成绩表 scores
并重置自增长字段,可以使用如下 SQL 语句:
TRUNCATE TABLE scores;
这里的 TRUNCATE
语句的作用是快速删除整张表的所有数据,并重置自增长字段的计数器。与 DELETE
语句不同,TRUNCATE
不会记录每条删除的记录,因此它的执行速度更快。此外,TRUNCATE
是不可回滚的操作,因此在执行前需要谨慎确认。
通过 DELETE
和 TRUNCATE
语句,我们可以灵活地管理数据库中的数据,确保数据的整洁性和准确性。在实际开发中,我们通常会根据具体需求选择合适的删除方式。
9. 插入查询结果
在数据库操作中,除了直接插入数据,我们还可以将查询结果插入到另一张表中。这种方式在数据迁移、数据备份、数据归档等场景中非常有用。MySQL 提供了 INSERT INTO ... SELECT
语句,允许我们将查询结果插入到指定的表中。
删除表中重复的记录,重复的数据只能有一份
在实际应用中,我们可能会遇到表中存在重复记录的问题。例如,假设我们有一个学生表 students
,其中包含 id
和 name
两个字段,表中可能存在多个相同姓名的学生记录。如果我们希望删除表中的重复记录,只保留一份数据,可以采取如下步骤:
1. 创建一张临时表
首先,我们需要创建一张临时表,该表的结构与原表相同。可以使用 CREATE TABLE ... LIKE
语句来创建临时表。例如:
CREATE TABLE temp_students LIKE students;
这里的 CREATE TABLE ... LIKE
语句会复制原表的结构,包括列定义、索引等,但不会复制数据。
2. 将去重后的数据插入临时表
接下来,我们可以使用 INSERT INTO ... SELECT DISTINCT
语句,将去重后的数据插入到临时表中。例如:
INSERT INTO temp_students SELECT DISTINCT * FROM students;
这里的 SELECT DISTINCT *
会从原表中查询所有不重复的记录,并将其插入到临时表中。
3. 将原表重命名为其他名字
为了保留原始数据,我们可以将原表重命名为其他名字。例如:
RENAME TABLE students TO old_students;
这里的 RENAME TABLE
语句会将原表重命名为 old_students
,以便后续备份或恢复。
4. 将临时表重命名为原表的名字
最后,我们将临时表重命名为原表的名字,以完成去重操作。例如:
RENAME TABLE temp_students TO students;
执行上述操作后,原表 students
中的重复记录已经被删除,只保留了一份数据。临时表 temp_students
被重命名为 students
,而原表 students
被重命名为 old_students
,以便后续备份或恢复。
通过这种方式,我们可以高效地删除表中的重复记录,确保数据的唯一性和准确性。在实际开发中,我们通常会结合 CREATE TABLE ... LIKE
、INSERT INTO ... SELECT DISTINCT
和 RENAME TABLE
来实现去重操作。
10. 聚合函数
聚合函数是 SQL 中用于对一组值进行计算并返回单一结果的函数。它们在数据分析和统计中非常有用,例如计算平均值、总和、最大值、最小值等。MySQL 提供了多种常用的聚合函数,包括 COUNT
、SUM
、AVG
、MAX
和 MIN
。
COUNT 函数
COUNT
函数用于统计表中记录的数量。它可以用于统计所有记录的数量,也可以用于统计某一列中非 NULL
值的数量。
统计班级共有多少同学
假设我们有一个学生表 students
,其中包含 id
、name
、age
等字段。如果我们想统计班级中共有多少同学,可以使用如下 SQL 语句:
SELECT COUNT(*) FROM students;
这里的 COUNT(*)
表示统计表中的所有记录数量。
统计班级收集的 QQ 号有多少个
如果我们想统计班级中收集了多少个 QQ 号,可以使用如下 SQL 语句:
SELECT COUNT(qq) FROM students;
这里的 COUNT(qq)
表示统计 qq
列中非 NULL
值的数量。
SUM 函数
SUM
函数用于计算某一列的总和。它通常用于数值类型的列,例如成绩、工资等。
统计本次考试数学成绩的总分
假设我们有一个成绩表 scores
,其中包含 id
、name
、chinese
、math
、english
等字段。如果我们想统计本次考试的数学总分,可以使用如下 SQL 语句:
SELECT SUM(math) FROM scores;
这里的 SUM(math)
表示计算 math
列的总和。
统计不及格的数学成绩总分
如果我们想统计数学成绩不及格的同学的总分,可以结合 WHERE
子句来实现。例如:
SELECT SUM(math) FROM scores WHERE math < 60;
这里的 WHERE math < 60
表示筛选出数学成绩不及格的同学,然后计算这些同学的数学总分。
AVG 函数
AVG
函数用于计算某一列的平均值。它通常用于数值类型的列,例如成绩、工资等。
统计平均总分
如果我们想统计所有同学的平均总分,可以使用如下 SQL 语句:
SELECT AVG(chinese + math + english) FROM scores;
这里的 AVG(chinese + math + english)
表示计算每位同学的三门成绩之和的平均值。
MAX 函数
MAX
函数用于返回某一列的最大值。它通常用于数值类型的列,例如成绩、工资等。
返回英语最高分
如果我们想查询英语成绩的最高分,可以使用如下 SQL 语句:
SELECT MAX(english) FROM scores;
这里的 MAX(english)
表示返回 english
列的最大值。
MIN 函数
MIN
函数用于返回某一列的最小值。它通常用于数值类型的列,例如成绩、工资等。
返回 70 分以上的英语最低分
如果我们想查询英语成绩在 70 分以上的最低分,可以结合 WHERE
子句来实现。例如:
SELECT MIN(english) FROM scores WHERE english > 70;
这里的 WHERE english > 70
表示筛选出英语成绩大于 70 分的同学,然后返回这些同学的英语最低分。
通过上述聚合函数,我们可以高效地进行数据统计和分析,帮助我们更好地理解和处理数据。在实际开发中,我们通常会结合 SELECT
、WHERE
和聚合函数来实现各种统计需求。
11. 分组查询
分组查询是 SQL 中用于对数据进行分类统计的重要功能。通过 GROUP BY
子句,我们可以将数据按照指定的列进行分组,并结合聚合函数对每个分组进行统计。分组查询通常用于分析数据的分布情况,例如统计每个部门的平均工资、每个岗位的最低工资等。
显示每个部门的平均工资和最高工资
假设我们有一个员工表 emp
,其中包含 deptno
(部门编号)、sal
(工资)等字段。如果我们想统计每个部门的平均工资和最高工资,可以使用如下 SQL 语句:
SELECT deptno, AVG(sal) AS avg_salary, MAX(sal) AS max_salary
FROM emp
GROUP BY deptno;
这里的 GROUP BY deptno
表示按照部门编号进行分组,AVG(sal)
计算每个部门的平均工资,MAX(sal)
计算每个部门的最高工资。
显示每个部门的每种岗位的平均工资和最低工资
如果我们想进一步细化统计,例如统计每个部门的每种岗位的平均工资和最低工资,可以使用如下 SQL 语句:
SELECT deptno, job, AVG(sal) AS avg_salary, MIN(sal) AS min_salary
FROM emp
GROUP BY deptno, job;
这里的 GROUP BY deptno, job
表示先按照部门编号分组,然后在每个部门内再按照岗位进行分组。AVG(sal)
计算每个分组的平均工资,MIN(sal)
计算每个分组的最低工资。
HAVING 条件
在分组查询中,我们还可以使用 HAVING
子句对分组后的数据进行筛选。与 WHERE
子句不同,HAVING
子句用于筛选分组后的聚合结果,而不是原始数据。
显示平均工资低于 2000 的部门和它的平均工资
如果我们想筛选出平均工资低于 2000 的部门,可以使用如下 SQL 语句:
SELECT deptno, AVG(sal) AS avg_salary
FROM emp
GROUP BY deptno
HAVING avg_salary < 2000;
这里的 HAVING avg_salary < 2000
表示筛选出平均工资小于 2000 的部门。
分组查询的执行顺序
在 SQL 查询中,各个子句的执行顺序如下:
- WHERE:先根据
WHERE
子句筛选出符合条件的原始数据。 - GROUP BY:根据
GROUP BY
子句对筛选后的数据进行分组。 - SELECT:对每个分组执行
SELECT
语句,计算聚合函数的值。 - HAVING:根据
HAVING
子句对分组后的结果进行筛选。 - ORDER BY:对最终的查询结果进行排序。
通过 GROUP BY
子句和聚合函数的结合使用,我们可以高效地进行数据分类统计,帮助我们更好地理解和分析数据。在实际开发中,我们通常会结合 SELECT
、GROUP BY
、HAVING
和 ORDER BY
来实现复杂的分组查询需求。