🔥个人主页: 中草药
🔥专栏:【MySQL】探秘:数据库世界的瑞士军刀
目录
⚗️一.CRUD
🧪二.新增(Create)
🧫1.基本操作
🧬2.使用SELECT插入
🔬3.总结
🔭三.查询(Retrieve) (重点)*
📡1.基本查询
🍇2.别名
🍈3.条件查询
3.1.比较运算符
3.2逻辑运算符
3.3案例
🍉4.排序查询
🍊5.去重查询
🍋6.分页查询
🍌 7.聚合查询*
7.1聚合函数
7.3 GROUP BY子句
7.4 HAVING子句
7.5 WITH ROLLUP
🥭 8.关联查询
8.1 关联条件与笛卡尔积
8.2 内连接(INNER JOIN)
8.3 外连接
🍍9.合并查询
9.1. UNION
9.2. UNION ALL
🍎10.子查询(了解)
🍒四. 修改(Update)
🍓1.基本操作
🫐2. 修改表结构(ALTER TABLE)
🥝3.注意事项
🍅五. 删除(Delete)
💐1.基本操作
🌸2.快速清空表(TRUNCATE)
🍀3. 删除表或数据库对象(DROP)
🧬4.注意事项
🪥六.约束条件
🧽1.非空约束 (NOT NULL)
🧻2.唯一约束 (UNIQUE)
🪣3.主键约束 (PRIMARY KEY)
🫧4.外键约束 (FOREIGN KEY)
🛒5.检查约束 (CHECK - MySQL 8.0.16及以上版本支持)--了解
🪤七.总结与反思
⚗️一.CRUD
MySQL的CRUD操作指的是数据库操作中的四个基本动作:Create(创建)、Read(读取)、Update(更新)和Delete(删除)。这些操作构成了数据库管理系统中最核心的数据操作集合,用于管理关系型数据库中的记录。
CRUD操作是数据库管理的基础,它们共同构成了数据生命周期管理的闭环,从数据的产生到数据的最终废弃,每一步都离不开这四个操作。它们的重要性在于:
- 灵活性:使得数据库能够适应不断变化的数据需求,支持动态数据管理。
- 数据完整性:通过精确的增删改查操作,维护数据库数据的准确性与一致性。
- 性能优化:合理的CRUD操作策略可以提升查询速度,减少资源消耗,优化数据库性能。
- 数据安全:通过权限控制CRUD操作,确保数据的访问和修改符合安全策略。
在MySQL中,通过优化CRUD操作的执行效率和安全性,可以极大地提升数据库应用的性能和用户体验。
注释:在SQL中可以使用“--空格+描述”来表示注释说明
🧪二.新增(Create)
在MySQL中,"新增操作"通常指的是向数据库中插入新的记录,这主要通过INSERT
语句来完成。新增操作是数据库管理中的基本操作之一,对于维护和更新数据库内容至关重要。以下是关于MySQL中新增操作的一些关键点和示例:
🧫1.基本操作
--插入单行数据
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);--插入多行数据
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...),(value4, value5, value6, ...),(...);
table_name
是要插入数据的表的名称。(column1, column2, column3, ...)
是表中的列名列表,列出你要插入数据的列。这可以省略,如果你插入所有列的值,并且顺序与表定义一致。(value1, value2, value3, ...)
是你希望插入的具体值,与列名一一对应。
举例:
-- 创建一张学生表
drop table if exist student;
create table student (id int,sn int comment '学号',name varchar(20) comment '姓名',qq_mail varchar(20) comment 'QQ邮箱'
);-- 单行数据+全列插入 插入两条记录,value_list 数量必须和定义表的列的数量及顺序一致
insert into student values (100, 10000, '唐三藏', NULL);
insert into student values (101, 10001, '孙悟空', '11111');-- 多行数据+指定列插入 插入两条记录,value_list 数量必须和指定列数量及顺序一致
insert into student (id, sn, name) values(102, 20001, '曹孟德'),(103, 20002, '孙仲谋');
🧬2.使用SELECT插入
你还可以从另一个查询的结果插入数据,这在复制表数据或更新表结构时特别有用:
INSERT INTO table_name (column1, column2, column3, ...)
SELECT columnA, columnB, columnC, ...
FROM source_table
WHERE some_condition;
🔬3.总结
新增操作在MySQL中是数据录入和数据库内容管理的核心部分,它支持数据库的动态增长和数据的实时更新。通过灵活运用INSERT
语句的各种形式,开发者可以高效地实现数据的批量插入、条件插入和冲突处理,满足不同场景下的数据管理需求。
🔭三.查询(Retrieve) (重点)*
MySQL中的查询操作主要通过SQL语言中的SELECT
语句来实现,这是数据查询语言(DQL)的一部分,用于从数据库中检索数据。查询操作是数据库管理中最频繁使用的功能之一,它支持从简单的数据检索到复杂的分析和数据汇总。以下是MySQL中查询操作的几个关键方面和示例:
📡1.基本查询
--单表查询
SELECT column1, column2
FROM table_name;--全列查询
SELECT *
FROM table_name;
column1, column2
是要选择的列名。table_name
是查询的表名。*
表示选择所有列。 通常情况下不建议使用 * 进行全列查询-- 1. 查询的列越多,意味着需要传输的数据量越大;-- 2. 可能会影响到索引的使用。(索引待后面博客讲解)
举例
-- 创建考试成绩表
DROP TABLE IF EXISTS exam_result;
CREATE TABLE exam_result (id INT,name VARCHAR(20),chinese DECIMAL(3,1),math DECIMAL(3,1),english DECIMAL(3,1)
);-- 插入测试数据
INSERT INTO exam_result (id,name, chinese, math, english) VALUES(1,'唐三藏', 67, 98, 56),(2,'孙悟空', 87.5, 78, 77),(3,'猪悟能', 88, 98.5, 90),(4,'曹孟德', 82, 84, 67),(5,'刘玄德', 55.5, 85, 45),(6,'孙权', 70, 73, 78.5),(7,'宋公明', 75, 65, 30);
-- 表达式不包含字段
SELECT id, name, 10 FROM exam_result;
-- 表达式包含一个字段
SELECT id, name, english + 10 FROM exam_result;
-- 表达式包含多个字段
SELECT id, name, chinese + math + english FROM exam_resul
🍇2.别名
SELECT column [AS] alias_name [...] FROM table_name
🍈3.条件查询
使用WHERE
子句根据条件筛选数据:
SELECT column1, column2
FROM table_name
WHERE condition;
condition
是筛选条件,如column1 = 'value'
。
3.1.比较运算符
运算符 | 说明 |
>, >=, <, <= | 大于,大于等于,小于,小于等于 |
= | 等于,NULL 不安全,例如 NULL = NULL 的结果是 NULL |
<=> | 等于,NULL 安全,例如 NULL <=> NULL 的结果是 TRUE(1) |
!=, <> | 不等于 |
BETWEEN a0 AND a1 | 范围匹配,[a0, a1],如果 a0 <= value <= a1,返回 TRUE(1) |
IN (option, ...) | 如果是 option 中的任意一个,返回 TRUE(1) |
IS NULL | 是 NULL |
IS NOT NULL | 不是 NULL |
LIKE | 模糊匹配。 % 表示任意多个(包括 0 个)任意字符; _ 表示任意一个字符 |
3.2逻辑运算符
运算符 | 说明 |
AND | 多个条件必须都为 TRUE(1),结果才是 TRUE(1) |
OR | 任意一个条件为 TRUE(1), 结果为 TRUE(1) |
NOT | 条件为 TRUE(1),结果为 FALSE(0) |
3.3案例
-- 查询语文成绩大于80分,且英语成绩大于80分的同学
SELECT * FROM exam_result WHERE chinese > 80 and english > 80;-- 查询语文成绩大于80分,或英语成绩大于80分的同学
SELECT * FROM exam_result WHERE chinese > 80 or english > 80;-- 观察AND 和 OR 的优先级:
SELECT * FROM exam_result WHERE chinese > 80 or math>70 and english > 70;
SELECT * FROM exam_result WHERE (chinese > 80 or math>70) and english > 70;
-- 查询语文成绩在 [80, 90] 分的同学及语文成绩
SELECT name, chinese FROM exam_result WHERE chinese BETWEEN 80 AND 90;-- 使用 AND 也可以实现
SELECT name, chinese FROM exam_result WHERE chinese >= 80 AND chinese
<= 90;
IN :
-- 查询数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
SELECT name, math FROM exam_result WHERE math IN (58, 59, 98, 99);-- 使用 OR 也可以实现
SELECT name, math FROM exam_result WHERE math = 58 OR math = 59 OR math
= 98 OR math = 99;
-- % 匹配任意多个(包括 0 个)字符
SELECT name FROM exam_result WHERE name LIKE '孙%';-- 匹配到孙悟空、孙权-- _ 匹配严格的一个任意字符
SELECT name FROM exam_result WHERE name LIKE '孙_';-- 匹配到孙权
-- 查询 qq_mail 已知的同学姓名
SELECT name, qq_mail FROM student WHERE qq_mail IS NOT NULL;-- 查询 qq_mail 未知的同学姓名
SELECT name, qq_mail FROM student WHERE qq_mail IS NULL;
🍉4.排序查询
使用ORDER BY
子句对结果排序:
SELECT column1, column2
FROM table_name
ORDER BY column1 ASC|DESC;
ASC
升序,DESC
降序,且默认为升序。NULL 数据排序,视为比任何值都小,升序出现在最上面,降序出现在最下面
使用表达式及别名排序
-- 查询同学及总分,由高到低
SELECT name, chinese + english + math FROM exam_result ORDER BY chinese + english + math DESC;
SELECT name, chinese + english + math total FROM exam_result ORDER BY total DESC;
可以对多个字段进行排序,排序优先级随书写顺序
-- 查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示
SELECT name, math, english, chinese FROM exam_result ORDER BY math DESC, english, chinese;
🍊5.去重查询
使用DISTINCT关键字对某列数据进行去重
-- 98 分重复了
SELECT math FROM exam_result;
+--------+
| math |
+--------+
| 98 |
| 78 |
| 98 |
| 84 |
| 85 |
| 73 |
| 65 |
+--------+
7 rows in set (0.00 sec)-- 去重结果
SELECT DISTINCT math FROM exam_result;
+--------+
| math |
+--------+
| 98 |
| 78 |
| 84 |
| 85 |
| 73 |
| 65 |
+--------+
6 rows in set (0.00 sec)
🍋6.分页查询
使用 LIMIT 关键字对某列数据进行去重
语法:
-- 起始下标为 0-- 从 0 开始,筛选 n 条结果
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n;-- 从 s 开始,筛选 n 条结果
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT s, n;-- 从 s 开始,筛选 n 条结果,比第二种用法更明确,建议使用
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n OFFSET s;
案例:按 id 进行分页,每页 3 条记录,分别显示 第 1、2、3 页
-- 第 1 页
SELECT id, name, math, english, chinese FROM exam_result ORDER BY id LIMIT 3
OFFSET 0;-- 第 2 页
SELECT id, name, math, english, chinese FROM exam_result ORDER BY id LIMIT 3
OFFSET 3;-- 第 3 页,如果结果不足 3 个,不会有影响
SELECT id, name, math, english, chinese FROM exam_result ORDER BY id LIMIT 3
OFFSET 6
🍌 7.聚合查询*
7.1聚合函数
函数 | 说明 |
COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的 总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的 平均值,不是数字没有意义 |
MAX([DISTINCT] expr) | 返回查询到的数据的 最大值,不是数字没有意义 |
MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,不是数字没有意义 |
举例
count
-- 统计班级共有多少同学
SELECT COUNT(*) FROM student;-- 统计班级收集的 qq_mail 有多少个,qq_mail 为 NULL 的数据不会计入结果
SELECT COUNT(qq_mail) FROM student;
sum
-- 统计数学成绩总分
SELECT SUM(math) FROM exam_result;-- 不及格 < 60 的总分,没有结果,返回 NULL
SELECT SUM(math) FROM exam_result WHERE math < 60;
avg
-- 统计平均总分
SELECT AVG(chinese + math + english) 平均总分 FROM exam_result;
max
-- 返回英语最高分
SELECT MAX(english) FROM exam_result;
min
-- 返回 > 70 分以上的数学最低分
SELECT MIN(math) FROM exam_result WHERE math > 70;
7.3 GROUP BY子句
- 作用:将结果集按照一个或多个列进行分组,每个组内可以应用聚合函数进行统计计算。
- 语法:
GROUP BY column1, column2,...
举例
-- 准备测试表及数据:职员表,有id(主键)、name(姓名)、role(角色)、salary(薪水)
create table emp(id int primary key auto_increment,name varchar(20) not null,role varchar(20) not null,salary numeric(11,2)
);insert into emp(name, role, salary) values
('马云','服务员', 1000.20),
('马化腾','游戏陪玩', 2000.99),
('孙悟空','游戏角色', 999.11),
('猪无能','游戏角色', 333.5),
('沙和尚','游戏角色', 700.33),
('隔壁老王','董事长', 12000.66);-- 查询每个角色的最高工资、最低工资和平均工资
select role,max(salary),min(salary),avg(salary) from emp group by role;
7.4 HAVING子句
- 作用:对GROUP BY产生的结果进行过滤,类似于WHERE子句,但HAVING作用于分组后的数据。
- 语法:
HAVING condition
举例
select role,max(salary),min(salary),avg(salary) from emp group by role
having avg(salary)<1500;
7.5 WITH ROLLUP
- 作用:在聚合查询的结果集中额外添加一行,显示所有分组的汇总信息。
- 语法:在GROUP BY子句末尾加上
WITH ROLLUP
。
举例
mysql> select role, sum(salary) from emp group by role with rollup;+--------------+-------------+
| role | sum(salary) |
+--------------+-------------+
| 服务员 | 1000.20 |
| 游戏角色 | 2032.94 |
| 游戏陪玩 | 2000.99 |
| 董事长 | 12000.66 |
| NULL | 17034.79 |
+--------------+-------------+
5 rows in set (0.00 sec)
🥭 8.关联查询
关联查询是MySQL中一种重要的查询技术,它允许用户从两个或多个表中同时检索数据,基于这些表之间的某种关联关系。关联查询通常使用 JOIN
语句来完成,通过指定关联条件来确保从不同表中取出的数据行是相互匹配的。下面是关联查询的一些关键概念和类型:
8.1 关联条件与笛卡尔积
在进行关联查询之前,了解笛卡尔积是很重要的。如果在关联查询中没有指定正确的关联条件,MySQL会执行一个笛卡尔积操作,即将第一个表的每一行与第二个表的每一行进行配对,生成的结果集大小将是两个表行数的乘积。在大多数情况下,这样的结果是没有意义的,因此我们需要通过关联条件来限制结果集,使其只包含有意义的匹配行。
8.2 内连接(INNER JOIN)
只返回两个表中匹配的行。如果在一个表中的某行在另一个表中找不到匹配,那么这行不会出现在结果集中。
举例
insert into classes(name, descri) values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');insert into student(sn, name, qq_mail, classes_id, id) values
('09982','黑旋风李逵','xuanfeng@qq.com',1,1),
('00835','菩提老祖',null,1,2),
('00391','白素贞',null,1,3),
('00031','许仙','xuxian@qq.com',1,4),
('00054','不想毕业',null,1,5),
('51234','好好说话','say@qq.com',2,6),
('83223','tellme',null,2,7);insert into course values
('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');insert into score(score, student_id, course_id) values
-- 黑旋风李逵
(70.5, 1, 1),(98.5, 1, 3),(33, 1, 5),(98, 1, 6),
-- 菩提老祖
(60, 2, 1),(59.5, 2, 5),
-- 白素贞
(33, 3, 1),(68, 3, 3),(99, 3, 5),
-- 许仙
(67, 4, 1),(23, 4, 3),(56, 4, 5),(72, 4, 6),
-- 不想毕业
(81, 5, 1),(37, 5, 5),
-- 好好说话
(56, 6, 2),(43, 6, 4),(79, 6, 6),
-- tellme
(80, 7, 2),(92, 7, 6);
-- 查询许仙同学的成绩select sco.course_id,sco.score from student stu inner join score sco on stu.id=sco.student_id and stu.name='许仙';
+-----------+-------+
| course_id | score |
+-----------+-------+
| 1 | 67.0 |
| 3 | 23.0 |
| 5 | 56.0 |
| 6 | 72.0 |
+----------+-------+
-- 成绩表对学生表是多对1关系,查询总成绩是根据成绩表的同学id来进行分组的
SELECT stu.sn, stu.NAME, stu.qq_mail, sum( sco.score )FROM student stu join score sco
ON stu.id = sco.student_id GROUP BY sco.student_id;
+-------+-----------------+-----------------+------------------+
| sn | NAME | qq_mail | sum( sco.score ) |
+-------+-----------------+-----------------+------------------+
| 9982 | 黑旋风李逵 | xuanfeng@qq.com | 300.0 |
| 835 | 菩提老祖 | NULL | 119.5 |
| 391 | 白素贞 | NULL | 200.0 |
| 31 | 许仙 | xuxian@qq.com | 218.0 |
| 54 | 不想毕业 | NULL | 118.0 |
| 51234 | 好好说话 | say@qq.com | 178.0 |
| 83223 | tellme | NULL | 172.0 |
+-------+-----------------+-----------------+------------------+
8.3 外连接
- 左连接 (LEFT JOIN) / 左外连接: 返回左表的所有行,即使在右表中没有匹配。如果右表中没有匹配,则结果集中右表的部分将包含NULL值。
- 右连接 (RIGHT JOIN) / 右外连接: 与左连接相反,返回右表的所有行,即使在左表中没有匹配。左表中没有匹配的行将以NULL值填充。
- 全连接 (FULL JOIN) / 全外连接: 返回左表和右表中的所有行。如果某一边没有匹配,则另一边的对应值为NULL。需要注意的是,MySQL本身不直接支持 FULL JOIN,但可以通过 LEFT JOIN 和 UNION 或其他技巧来模拟。
-- 左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;-- 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件;
举例
-- “老外学中文”同学 没有考试成绩,也显示出来了
select * from student stu left join score sco on stu.id=sco.student_id;-- 对应的右外连接为:
select * from score sco right join student stu on stu.id=sco.student_id;+-------+-----------------+-----------------+------------+------+-------+------------+----------+
| sn | name | qq_mail | classes_id | id | score | student_id | couse_id |
+-------+-----------------+-----------------+------------+------+-------+------------+----------+
| 9982 | 黑旋风李逵 | xuanfeng@qq.com | 1 | 1 | 70.5 | 1 | 1 |
| 9982 | 黑旋风李逵 | xuanfeng@qq.com | 1 | 1 | 98.5 | 1 | 3 |
| 9982 | 黑旋风李逵 | xuanfeng@qq.com | 1 | 1 | 33.0 | 1 | 5 |
| 9982 | 黑旋风李逵 | xuanfeng@qq.com | 1 | 1 | 98.0 | 1 | 6 |
| 835 | 菩提老祖 | NULL | 1 | 2 | 60.0 | 2 | 1 |
| 835 | 菩提老祖 | NULL | 1 | 2 | 59.5 | 2 | 5 |
| 391 | 白素贞 | NULL | 1 | 3 | 33.0 | 3 | 1 |
| 391 | 白素贞 | NULL | 1 | 3 | 68.0 | 3 | 3 |
| 391 | 白素贞 | NULL | 1 | 3 | 99.0 | 3 | 5 |
| 31 | 许仙 | xuxian@qq.com | 1 | 4 | 67.0 | 4 | 1 |
| 31 | 许仙 | xuxian@qq.com | 1 | 4 | 23.0 | 4 | 3 |
| 31 | 许仙 | xuxian@qq.com | 1 | 4 | 56.0 | 4 | 5 |
| 31 | 许仙 | xuxian@qq.com | 1 | 4 | 72.0 | 4 | 6 |
| 54 | 不想毕业 | NULL | 1 | 5 | 81.0 | 5 | 1 |
| 54 | 不想毕业 | NULL | 1 | 5 | 37.0 | 5 | 5 |
| 51234 | 好好说话 | say@qq.com | 2 | 6 | 56.0 | 6 | 2 |
| 51234 | 好好说话 | say@qq.com | 2 | 6 | 43.0 | 6 | 4 |
| 51234 | 好好说话 | say@qq.com | 2 | 6 | 79.0 | 6 | 6 |
| 83223 | tellme | NULL | 2 | 7 | 80.0 | 7 | 2 |
| 83223 | tellme | NULL | 2 | 7 | 92.0 | 7 | 6 |
+-------+-----------------+-----------------+------------+------+-------+------------+----------+
🍍9.合并查询
在MySQL中,合并查询通常指的是使用 UNION
或 UNION ALL
操作符来组合多个 SELECT
语句的结果,从而生成一个统一的结果集。这两种操作提供了灵活的方式来整合不同查询的数据,适用于多种场景,比如报表生成、数据分析等。下面是对这两种合并查询方式的详细说明:
9.1. UNION
UNION
操作符用于合并两个或多个 SELECT
语句的结果集,同时自动去除结果中的重复行。使用 UNION
时,需注意以下几点:
- 列数相同:所有参与合并的
SELECT
语句必须返回相同数量的列。 - 列类型兼容:虽然列不需要严格相同类型,但它们之间应能进行类型转换,以便比较和去重。
- 列顺序一致:各
SELECT
语句中的列顺序需要保持一致。 - 结果排序与去除重复:MySQL 自动对最终结果进行排序并去除完全相同的行。
- 列名继承:结果集的列名通常取自第一个
SELECT
语句中指定的列名。
select * from course where id<3
union
select * from course where name='英文';-- 或者使用or来实现
select * from course where id<3 or name='英文';
9.2. UNION ALL
与 UNION
类似,UNION ALL
也是用来合并多个 SELECT
语句的结果集,但不同之处在于,UNION ALL
不会去除重复的行,也不会对结果集进行排序,因此它通常比 UNION
执行得更快,尤其是在处理大量数据时。
- 保留所有行:包括重复行,不进行去重。
- 效率更高:因为省去了去重和排序的过程,所以性能通常优于
UNION
。
-- 可以看到结果集中出现重复数据
select * from course where id<3
union all
select * from course where name='英文';
注意事项
- 性能考量:当确知结果集中不会有重复行或不需要去重时,使用
UNION ALL
可以提高查询性能。 - 排序与限制:如果需要对最终结果进行排序或限制返回的行数,可以使用
ORDER BY
和LIMIT
子句,但它们必须放在所有UNION
/UNION ALL
子句之后。 - 索引与优化:对于大型查询,考虑对涉及的列添加索引,以及合理安排
JOIN
和WHERE
条件,以进一步优化性能。
通过灵活运用 UNION
和 UNION ALL
,你可以有效地整合数据,满足复杂的数据分析和报告需求。
🍎10.子查询(了解)
--查询与“李青” 同学的同班同学
select * from student where
class_id=(select class_id from student where name ='李青');
多行子查询:返回多行记录的子查询
-- 查询'语文'或'英语'的成绩-- 使用 IN
select * from score where course_id in (select id from course where
name='语文' or name='英文');-- 使用 NOT IN
select * from score where course_id not in (select id from course where
name!='语文' and name!='英文');
尽管子查询在MySQL中提供了一种强大的方式来处理复杂的数据检索和分析,但它们也伴随着一些弊端,主要体现在性能和可读性方面:
-
性能问题:
- 资源消耗:执行子查询时,MySQL可能需要创建临时表来存储子查询的结果,这涉及到内存和磁盘I/O的消耗。一旦查询完成,这些临时表会被销毁,这个过程会增加额外的时间成本。
- 相关子查询的低效:对于相关子查询(即子查询的结果依赖于外部查询的每一行),MySQL可能需要对外层表的每一行都执行一次子查询,这在数据量大时会极度影响性能。
- 索引利用不足:在某些情况下,子查询可能妨碍优化器使用有效的索引策略,导致全表扫描,特别是在子查询的条件复杂或不明确时。
-
可读性和维护困难:
- 复杂性:子查询嵌套过多会使SQL语句变得冗长且难以理解,尤其是对于复杂的逻辑,这会影响代码的可读性和后续的维护工作。
- 调试困难:子查询可能导致的性能瓶颈较难定位,因为问题可能隐藏在多层嵌套中,调试和优化变得更加困难。
-
优化局限性:
- MySQL的查询优化器在处理子查询方面可能不如处理JOIN操作高效,尤其是在处理大数据集时。优化器可能无法有效地重写或优化复杂的子查询结构。
-
替代方案:
- 在很多情况下,使用JOIN操作可能提供更好的性能和可读性,尤其是在处理多表关联查询时。JOIN直接在数据行级别进行匹配,减少了临时表的创建和销毁过程,对于大数据量的处理更加高效。
- 对于简单的子查询,直接在应用程序层面进行数据处理也是一种可行的替代方案,例如先执行子查询获取数据,再用结果去执行主查询,但这增加了应用程序的复杂度。
综上所述,虽然子查询在灵活性和功能上非常强大,但在设计查询时应权衡其优缺点,根据实际需求和数据规模选择最合适的方法。在数据量较大或性能要求较高的场景下,考虑使用JOIN或直接在应用程序中处理数据可能是更优的选择。
🍒四. 修改(Update)
🍓1.基本操作
UPDATE
命令用于更新表中的现有记录。你可以更新单行或多行,具体取决于WHERE
子句的条件。
UPDATE table_name
SET column1 = new_value1, column2 = new_value2, ...
WHERE condition;
table_name
是你要修改的表的名称。
column1 = new_value1, column2 = new_value2, ...
指定了要修改的列名及其新值。
WHERE condition
是可选的,用于指定哪些行需要更新。如果省略,将更新表中的所有行。
举例:
-- 将孙悟空同学的数学成绩变更为 80 分
UPDATE exam_result SET math = 80 WHERE name = '孙悟空';-- 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分
UPDATE exam_result SET math = 60, chinese = 70 WHERE name = '曹孟德';-- 将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
UPDATE exam_result SET math = math + 30 ORDER BY chinese + math + english LIMIT
3;-- 将所有同学的语文成绩更新为原来的 2 倍
UPDATE exam_result SET chinese = chinese * 2;
🫐2. 修改表结构(ALTER TABLE)
ALTER TABLE
命令用于修改表的结构,包括添加/删除列、修改列属性、添加约束、重命名表等。
- 添加列:
ALTER TABLE table_name
ADD column_name column_definition [FIRST|AFTER column_name];
column_definition
定义新列的类型和属性,如INT(110)
。
FIRST
在表开头添加,AFTER column_name
在指定列之后添加。
- 删除列:
ALTER TABLE table_name
DROP COLUMN column_name;
- 修改列
ALTER TABLE table_name
MODIFY column_name column_definition;
- 重命名表
ALTER TABLE old_table_name RENAME TO new_table_name;
🥝3.注意事项
- 在进行修改操作之前,建议备份数据,以防误操作导致数据丢失。
- 对于生产数据库的修改操作,最好在低峰期进行,避免影响服务。
- 修改表结构可能会影响依赖于该表的应用程序,需要进行相应的代码调整和测试。
综上所述,MySQL中的修改操作覆盖了数据记录的更新以及表结构的调整,是数据库管理与开发中不可或缺的一部分。正确理解和应用这些命令,可以有效管理数据库的持续发展和维护。
🍅五. 删除(Delete)
在MySQL中,删除操作主要涉及从数据库中移除数据或数据库对象,如数据表、记录、视图、存储过程等。主要通过DELETE
、TRUNCATE
和DROP
命令来实现。以下是这些操作的详细说明:
💐1.基本操作
DELETE FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...]
如果省略
WHERE
子句,将会删除表中的所有记录。
condition
用于指定要删除的行的条件。
举例:
-- 删除孙悟空同学的考试成绩
DELETE FROM exam_result WHERE name = '孙悟空';-- 删除整张表数据
-- 准备测试表
DROP TABLE IF EXISTS for_delete;
CREATE TABLE for_delete (id INT,name VARCHAR(20)
);-- 插入测试数据
INSERT INTO for_delete (name) VALUES ('A'), ('B'), ('C');-- 删除整表数据
DELETE FROM for_delete;
🌸2.快速清空表(TRUNCATE)
TRUNCATE
语句用于快速删除表中的所有数据,它比DELETE
更快,因为它不记录每个删除行的日志,也不会触发触发器,且不可回滚。
TRUNCATE TABLE table_name;
这个操作会清空表,但保留表结构。
🍀3. 删除表或数据库对象(DROP)
删除表:
DROP TABLE table_name;
删除数据库:
DROP DATABASE database_name;
🧬4.注意事项
- 数据安全性:
DROP
操作是永久性的,执行前应确保已备份重要数据。 - 性能差异:
TRUNCATE
比DELETE
更快,因为它不记录日志,也不需要逐行处理。 - 事务与触发器:
DELETE
支持事务处理和触发器,而TRUNCATE
和DROP
不支持。 - 权限要求:执行
DROP
操作通常需要更高的权限。 - 索引和约束:
DROP TABLE
会移除表及其所有索引和约束;TRUNCATE
和DELETE
不影响表结构。
综上,MySQL中的删除操作根据不同的需求和场景提供了不同的命令,使用时需谨慎考虑其对数据的影响和是否可逆性,确保数据安全和操作的正确性。
🪥六.约束条件
MySQL中的约束条件是用来确保数据库表中数据的准确性和一致性的规则。约束条件可以防止不符合业务逻辑或数据完整性的数据被插入到表中。以下是MySQL中常见的几种约束条件
🧽1.非空约束 (NOT NULL
)
- 定义:要求该列的每一行都必须有值,不允许为空(NULL)。
- 用途:保证表中的某些字段总是有值,适用于必填信息。
-- 重新设置学生表结构
DROP TABLE IF EXISTS student;
CREATE TABLE student (id INT NOT NULL,sn INT,name VARCHAR(20),qq_mail VARCHAR(20)
);
🧻2.唯一约束 (UNIQUE
)
- 定义:确保该列中的所有值都是唯一的,可以有一个NULL值。
- 用途:适合用于需要唯一标识但不作为主键的字段,如邮箱地址。
-- 重新设置学生表结构
DROP TABLE IF EXISTS student;
CREATE TABLE student (id INT NOT NULL,sn INT UNIQUE,name VARCHAR(20),qq_mail VARCHAR(20)
);
🪣3.主键约束 (PRIMARY KEY
)
- 定义:一个或多个字段的组合,用于唯一标识表中的每一行记录,且不能有NULL值。
- 用途:是数据库表中最重要的约束之一,用于快速定位记录。
-- 重新设置学生表结构
DROP TABLE IF EXISTS student;
CREATE TABLE student (id INT NOT NULL PRIMARY KEY,sn INT UNIQUE,name VARCHAR(20) DEFAULT 'unkown',qq_mail VARCHAR(20)
);
自增约束 (AUTO_INCREMENT
)
- 定义:主要用于整数类型的列,每当插入新记录时,该列的值自动增加。
- 用途:简化主键的生成和管理。
-- 重新设置学生表结构
DROP TABLE IF EXISTS student;
CREATE TABLE student (id INT PRIMARY KEY auto_increment,sn INT UNIQUE,name VARCHAR(20) DEFAULT 'unkown',qq_mail VARCHAR(20)
);
🫧4.外键约束 (FOREIGN KEY
)
- 定义:建立两个表之间的关联,确保一个表中的值必须参考另一个表中已经存在的值。
- 用途:维护数据间的引用完整性,常用于实现一对一或一对多的关系。
-- 创建班级表,有使用MySQL关键字作为字段时,需要使用``来标识
DROP TABLE IF EXISTS classes;
CREATE TABLE classes (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20),
`desc` VARCHAR(100)
);-- 重新设置学生表结构
DROP TABLE IF EXISTS student;
CREATE TABLE student (id INT PRIMARY KEY auto_increment,sn INT UNIQUE,name VARCHAR(20) DEFAULT 'unkown',qq_mail VARCHAR(20),classes_id int,FOREIGN KEY (classes_id) REFERENCES classes(id)
);
🛒5.检查约束 (CHECK
- MySQL 8.0.16及以上版本支持)--了解
- 定义:限制列中的值必须满足特定条件。
- 用途:对数据的取值范围进行更细致的控制。
drop table if exists test_user;
create table test_user (id int,name varchar(20),sex varchar(1),check (sex ='男' or sex='女')
);
🧯6.默认值约束 (DEFAULT
)
- 定义:如果在插入数据时没有指定该列的值,则使用默认值。
- 用途:简化数据插入,为可选字段提供默认选项。
-- 重新设置学生表结构
DROP TABLE IF EXISTS student;
CREATE TABLE student (
id INT NOT NULL,
sn INT UNIQUE,
name VARCHAR(20) DEFAULT 'unkown',
qq_mail VARCHAR(20)
);
这些约束条件可以在创建表时通过CREATE TABLE
语句指定,也可以在表创建后通过ALTER TABLE
语句添加或修改。合理使用约束条件能够极大地提高数据库的数据质量、维护数据的一致性和准确性。
🪤七.总结与反思
只要下定决心克服恐惧,便几乎能克服任何恐惧。因为,请记住,除了在脑海中,恐惧无处藏身。--戴尔.卡耐基
经过一段时间对MySQL增删查改(Insert, Delete, Select, Update)四大核心操作的学习与实践,我深刻体会到了数据库管理的复杂性和艺术性。以下是对这一学习过程的深入反思,旨在总结经验,明确改进方向,不断提升数据库操作的效率与安全性。
增(Insert)
- 数据验证的重要性:在执行插入操作时,我意识到前端或应用层的数据验证虽是第一道防线,但数据库层面的数据约束(如非空检查、唯一性约束)同样至关重要。忽视这一点可能导致数据不一致性,因此,设置合理的数据库约束并确保其有效执行是不可或缺的。
- 性能考量:对于大批量数据的插入,原生的单条插入方式效率低下。未来应探索使用
LOAD DATA INFILE
命令或批量插入语句来提升效率,减少数据库的I/O压力。
删(Delete)
- 安全第一:删除操作的不可逆性让我深刻认识到,在执行前应三思而后行,特别是在生产环境。采用
DELETE FROM
时务必附加精确的WHERE
子句,避免误删整表数据。同时,考虑在执行此类操作前采取备份措施。 - 事务的妙用:在涉及多步骤的删除操作中,事务的使用可以确保数据的一致性。我需要加强对事务特性的掌握,特别是在并发操作场景下,确保数据的完整性和一致性。
查(Select)
- SQL优化的艺术:虽然
SELECT
是最基础的操作,但其背后的优化空间巨大。我认识到,合理利用索引、避免全表扫描、精简查询字段、优化JOIN
操作等,对于提升查询效率至关重要。此外,学习如何解读并利用EXPLAIN
分析查询计划,对于理解MySQL如何执行SQL语句有着不可估量的价值。 - 复杂查询的挑战:面对多表联合查询、子查询等复杂情况,我发现自己在理解与编写高效查询语句方面还有很大提升空间。未来,我需要通过更多实践,加深对高级SQL特性的理解和应用,如窗口函数、分析函数等。
改(Update)
- 精准定位:更新操作同样需要谨慎处理,精确的
WHERE
子句是避免错误更新的关键。我需要培养在执行更新前进行数据预览的习惯,尤其是在处理影响大量数据的更新时。 - 性能与锁的影响:大规模更新操作可能引发性能问题,特别是表锁或行锁的应用可能阻塞其他读写操作。学习并掌握如何最小化锁定范围,以及在必要时使用乐观锁或悲观锁机制,是提升并发处理能力的关键。
结语
通过对MySQL增删查改操作的反思,我深刻认识到了理论知识与实践操作之间的差距,以及数据库管理中细节决定成败的道理。未来的路途中,我将致力于深化理论学习,加强实战演练,同时关注数据库最新技术和最佳实践,以期成为一名更为熟练且负责任的数据库管理员。
🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀
以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐
制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸