好的,我们来详细解析一下您提供的图片中关于 MySQL 基础的增删改查(CRUD)操作。我将严格按照图片中的大纲结构,对每一个知识点进行详尽的解释,并为所有SQL代码提供逐行注释,同时进行深入的扩展说明,以确保内容详实、易于理解,并达到您要求的篇幅。
引言:什么是CRUD?
在正式开始之前,我们首先要理解 CRUD 这个核心概念。正如第一张图片所示,CRUD 是四个英文单词的首字母缩写,它们构成了数据库操作最核心、最基础的四个功能:
-
C: Create(创建/新增):在数据库的表中创建新的记录。对应 SQL 中的
INSERT
语句。 -
R: Retrieve(读取/查询):从数据库的表中读取一条或多条记录。对应 SQL 中的
SELECT
语句,这是最复杂、最常用的一部分。 -
U: Update(更新/修改):修改数据库表中已存在的记录。对应 SQL 中的
UPDATE
语句。 -
D: Delete(删除):从数据库表中删除一条或多条记录。对应 SQL 中的
DELETE
语句。
这四个操作是我们与数据库进行交互的基石。无论是开发一个复杂的企业级应用,还是一个简单的个人网站,其后台数据处理都离不开对数据的增、删、改、查。掌握了 CRUD,就等于掌握了与数据库对话的基本语言。
准备工作:创建示例数据表
为了让后续的示例代码能够实际运行并更具象化,我们首先需要创建一个用于演示的数据库和表。假设我们正在为一个学校管理系统设计数据库,我们来创建一个 students
表。
SQL
-- 如果名为 school 的数据库不存在,则创建它
CREATE DATABASE IF NOT EXISTS school;
-- 切换到 school 数据库上下文
USE school;
-- 如果名为 students 的表已存在,则先删除它,方便我们重新创建
DROP TABLE IF EXISTS students;
-- 创建一个名为 students 的表,用于存储学生信息
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT, -- 学生ID,整数类型,主键,并且自增长
student_no VARCHAR(20) NOT NULL UNIQUE, -- 学号,字符串类型,不允许为空,且必须唯一
name VARCHAR(50) NOT NULL, -- 姓名,字符串类型,不允许为空
gender VARCHAR(2) DEFAULT '未知', -- 性别,字符串类型,默认为 '未知'
age INT, -- 年龄,整数类型
score DECIMAL(5, 2), -- 成绩,十进制数,总共5位,小数点后2位
enrollment_date DATE -- 入学日期,日期类型
);
知识点解析与扩展:
-
CREATE DATABASE IF NOT EXISTS school;
: 这是一个健壮的写法,IF NOT EXISTS
可以防止在数据库已经存在时执行CREATE DATABASE
导致的错误。 -
USE school;
: 这个命令用于将当前的会话环境切换到指定的数据库,后续的所有表操作都将默认在该数据库下进行。 -
CREATE TABLE students (...)
: 定义表的结构。-
INT
: 整数类型。 -
VARCHAR(N)
: 可变长度的字符串,N
是最大字符数。 -
DECIMAL(P, S)
: 精确的十进制数类型,P
是总位数,S
是小数位数。非常适合存储金额、分数等需要精确计算的数值,可以避免浮点数(FLOAT
,DOUBLE
)的精度问题。 -
DATE
: 只存储日期(年-月-日)。 -
PRIMARY KEY
: 主键。表中每一行数据的唯一标识符。一个表只能有一个主键。主键列的值必须是唯一的(UNIQUE)且不能为空(NOT NULL)。 -
AUTO_INCREMENT
: 自增长。通常用于主键列,当我们插入新数据时,如果未指定该列的值,数据库会自动为其分配一个比当前最大值大1的唯一数字。 -
NOT NULL
: 非空约束。规定该列在插入或更新时必须有一个值。 -
UNIQUE
: 唯一约束。规定该列的所有值必须是唯一的,不能有重复。 -
DEFAULT '未知'
: 默认值约束。如果在插入新数据时没有为该列提供值,数据库会自动使用这个默认值。
-
现在,我们有了一个空的 students
表,可以开始学习 CRUD 操作了。
二、 新增数据 (Create)
新增数据就是向数据表中插入一行或多行新的记录。我们使用 INSERT INTO
语句。
2.1 单行数据 + 全列插入
这是最基础的插入方式,需要为表中的每一列都提供一个值,并且值的顺序必须与表中列的定义顺序完全一致。
语法:
INSERT INTO 表名 VALUES (值1, 值2, ..., 值N);
示例:
SQL
-- 向 students 表中插入一条完整的学生记录
INSERT INTO students VALUES (
NULL, -- 对应 id 列。因为它是 AUTO_INCREMENT,所以可以填 NULL,系统会自动生成
'SN2025001', -- 对应 student_no 列
'张三', -- 对应 name 列
'男', -- 对应 gender 列
18, -- 对应 age 列
95.50, -- 对应 score 列
'2025-09-01' -- 对应 enrollment_date 列
);
逐行注释与解析:
-
INSERT INTO students VALUES (...)
:INSERT INTO
是SQL中用于插入数据的关键字,students
是目标表名,VALUES
后面跟着包含具体值的括号。 -
NULL
: 我们为id
列提供了NULL
。因为id
被定义为PRIMARY KEY AUTO_INCREMENT
,数据库会自动忽略这个NULL
,并生成一个唯一的、自增的ID(在这里会是1)。我们也可以完全不写id
列,但这需要使用“指定列插入”的方式。 -
'SN2025001', '张三', '男'
: 这些是字符串类型的值,在SQL中必须用单引号'
或双引号"
包围。 -
18, 95.50
: 这些是数值类型,可以直接写入,无需引号。 -
'2025-09-01'
: 日期类型在SQL中通常也以字符串的形式提供,格式为'YYYY-MM-DD'
。
深入扩展与注意事项:
-
风险:全列插入非常不健壮。如果未来数据库表的结构发生了改变(例如,增加了一个新列、删除了一个列或调整了列的顺序),那么这条
INSERT
语句就会立刻报错或插入错误的数据。因此,在实际项目开发中,强烈不推荐使用这种写法。 -
值的匹配:值的数量必须与表的列数完全匹配,值的类型也必须与对应列的数据类型兼容(例如,不能把一个字符串插入到
INT
类型的列中)。
2.2 多行数据 + 指定列插入
这是一种更常用、更安全、更灵活的插入方式。我们可以明确指定要为哪些列插入数据,并且可以一次性插入多条记录。
语法:
INSERT INTO 表名 (列1, 列2, ...) VALUES (值1A, 值2A, ...), (值1B, 值2B, ...), ...;
示例:
SQL
-- 向 students 表中一次性插入三条新的学生记录,并指定要插入的列
INSERT INTO students (student_no, name, age, score, enrollment_date, gender)
VALUES
('SN2025002', '李四', 19, 88.00, '2025-09-01', '男'), -- 第一条记录
('SN2025003', '王五', 18, 92.50, '2025-09-02', '女'), -- 第二条记录
('SN2025004', '赵六', 20, 76.00, '2025-09-01', '男'); -- 第三条记录
逐行注释与解析:
-
INSERT INTO students (student_no, name, ...)
: 在表名后面,我们用括号明确列出了要插入数据的列名。这样做的好处是,列的顺序可以任意,不一定非要和表定义的顺序一致。 -
VALUES (...)
:VALUES
关键字后面跟着每一行的数据。 -
('SN2025002', ...)
: 每一行的数据都用一对括号包围,里面的值的顺序必须与前面指定的列名顺序 (student_no
,name
, ...) 一一对应。 -
,
: 多行数据之间用逗号隔开。
示例2:插入时使用默认值
我们没有为 gender 列提供值,它将使用我们建表时设置的 DEFAULT '未知'。
SQL
-- 插入一条记录,但不指定 gender,让其使用默认值
INSERT INTO students (student_no, name, age, score, enrollment_date)
VALUES
('SN2025005', '孙七', 19, 85.00, '2025-09-03');
这条语句执行后,孙七
同学的 gender
字段会被自动设为 '未知'
。
深入扩展与注意事项:
-
健壮性:指定列插入是推荐的最佳实践。即使表结构未来增加了新的列(只要新列允许为NULL或有默认值),这条语句依然可以正常工作。
-
性能:一次性插入多行数据(如上例)比执行多次单行插入的
INSERT
语句效率要高得多。这是因为数据库只需要解析一次SQL,并进行一次事务提交,减少了网络往返和数据库的开销。 -
INSERT IGNORE
:如果插入的数据会导致唯一键(UNIQUE
或PRIMARY KEY
)冲突,普通的INSERT
语句会报错。如果使用INSERT IGNORE INTO ...
,数据库会忽略这些会导致冲突的行,不报错,并继续插入其他合法的行。 -
INSERT ... ON DUPLICATE KEY UPDATE ...
:这是一个非常有用的扩展,常被称为 "UPSERT" (Update or Insert)。当插入的数据导致唯一键冲突时,它不会报错,而是会执行UPDATE
子句来更新已存在的那一行。例如:INSERT INTO students (student_no, name) VALUES ('SN2025001', '张三丰') ON DUPLICATE KEY UPDATE name = '张三丰';
如果学号SN2025001
已存在,它会把该学生的姓名更新为“张三丰”。
三、 查询数据 (Retrieve)
查询是数据库操作中使用最频繁、功能最强大的部分。我们使用 SELECT
语句来从表中检索数据。
3.1 全列查询
查询出表中的所有列和所有行的数据。
语法:
SELECT * FROM 表名;
示例:
SQL
-- 从 students 表中查询出所有学生的所有信息
SELECT * FROM students;
逐行注释与解析:
-
SELECT *
:SELECT
是查询关键字。星号*
是一个通配符,代表“所有列”。 -
FROM students
:FROM
关键字用于指定要从哪个表中查询数据,这里是students
表。
深入扩展与注意事项:
-
性能问题:在生产环境中,应极力避免使用
SELECT *
。原因有:-
不必要的网络开销:它会查询出所有列的数据,即使你只关心其中几列。当表很大,或者有
TEXT
、BLOB
等大字段时,会传输大量无用数据,占用网络带宽。 -
可读性和维护性差:代码的阅读者无法立即知道这个查询到底需要哪些字段。
-
潜在的错误:如果应用程序依赖于列的固定顺序,而数据库表的列顺序被修改,
SELECT *
返回的列顺序也可能改变,导致程序出错。
-
-
适用场景:
SELECT *
主要用于临时的数据探查和调试,或者当表很小且确实需要所有列时。
3.2 指定列查询
只查询你所需要的特定列,这是推荐的做法。
语法:
SELECT 列1, 列2, ... FROM 表名;
示例:
SQL
-- 从 students 表中只查询所有学生的学号和姓名
SELECT student_no, name FROM students;
逐行注释与解析:
-
SELECT student_no, name
: 在SELECT
后面明确列出需要查询的列名,多个列名之间用逗号隔开。 -
FROM students
: 指定数据来源是students
表。
这种方式清晰、高效,是编写查询语句的标准实践。
3.3 查询字段为表达式
我们不仅可以查询原始的列数据,还可以对列数据进行计算和处理,将计算结果作为一个新的列返回。
语法:
SELECT 表达式1, 表达式2, ... FROM 表名;
示例:
SQL
-- 查询所有学生的姓名,以及他们当前分数提高10%后的理论分数
SELECT name, score * 1.1 FROM students;
逐行注释与解析:
-
SELECT name, score * 1.1
: 我们查询了name
列,同时查询了一个表达式score * 1.1
。MySQL会对每一行数据的score
值乘以1.1,并将结果作为第二列返回。
深入扩展与注意事项:
-
表达式类型:表达式可以是任何有效的计算,包括:
-
算术运算:
+
,-
,*
,/
(例如score + 5
) -
字符串函数:
CONCAT(name, '(', student_no, ')')
可以将姓名和学号拼接成一个字符串。 -
日期函数:
YEAR(enrollment_date)
可以提取入学年份。 -
逻辑运算:在
CASE
语句中使用。
-
-
不影响原数据:查询中的表达式不会修改表里存储的原始数据。它只是在查询结果集中动态计算出一个新值。
3.4 别名 (Alias)
当查询的列名很长、或者是一个复杂的表达式时,返回的结果集中的列名会不直观。我们可以使用别名来给结果集中的列重命名。
语法:
SELECT 列 [AS] 别名1, 表达式 [AS] 别名2, ... FROM 表名; (AS 关键字可以省略)
示例:
SQL
-- 查询学生的姓名和分数,并将结果集中的列名显示为中文
SELECT
name AS '姓名', -- 为 name 列指定别名 '姓名'
score AS '成绩' -- 为 score 列指定别名 '成绩'
FROM
students;
示例2:为表达式设置别名
SQL
-- 查询学生姓名和提高10%后的分数,并为表达式结果列指定一个有意义的别名
SELECT
name, -- 查询原始的姓名列
score * 1.1 AS bonus_score -- 为 score * 1.1 这个表达式的结果指定别名 bonus_score
FROM
students;
深入扩展与注意事项:
-
AS
关键字:在列别名中,AS
通常可以省略,如SELECT name '姓名' FROM students;
。但为了代码的可读性,强烈建议总是写上AS
。 -
表别名:别名不仅可以用于列,也可以用于表,这在多表连接查询(
JOIN
)中至关重要。例如:SELECT s.name FROM students AS s;
。
3.5 去重: DISTINCT
使用 DISTINCT
关键字可以从查询结果中移除重复的行。
语法:
SELECT DISTINCT 列1, 列2, ... FROM 表名;
示例:
SQL
-- 查询我们的学生都来自哪些性别
SELECT DISTINCT gender FROM students;
逐行注释与解析:
-
SELECT DISTINCT gender
:DISTINCT
关键字作用于其后的所有列。这条语句会返回students
表中gender
列的所有唯一值。如果表中有'男', '女', '男', '未知',结果将是 '男', '女', '未知' 三行。
深入扩展与注意事项:
-
作用于整行:
DISTINCT
作用于整个SELECT
的列列表,而不是单个列。例如,SELECT DISTINCT gender, age FROM students;
会返回唯一的(gender, age)
组合。如果存在('男', 18)
和('男', 19)
两条记录,它们都会被返回,因为它们的组合是不同的。
3.6 排序: ORDER BY
使用 ORDER BY
子句可以对查询结果进行排序。
语法:
SELECT ... FROM ... ORDER BY 列1 [ASC|DESC], 列2 [ASC|DESC], ...;
示例1:单列排序
SQL
-- 查询所有学生信息,并按照成绩从高到低进行排序
SELECT name, score
FROM students
ORDER BY score DESC;
示例2:多列排序
SQL
-- 查询所有学生信息,优先按照成绩从高到低排序,如果成绩相同,则按照年龄从小到大排序
SELECT name, score, age
FROM students
ORDER BY score DESC, age ASC;
逐行注释与解析:
-
ORDER BY score DESC
:ORDER BY
是排序子句。score
是排序依据的列。DESC
(Descending)表示降序(从大到小)。 -
ASC
(Ascending) 表示升序(从小到大),这是默认的排序方式,所以ORDER BY age ASC
和ORDER BY age
是等价的。 -
ORDER BY score DESC, age ASC
: 当进行多列排序时,数据库会首先按照第一个条件 (score DESC
) 排序。只有当第一列的值相同时,才会启用第二个排序条件 (age ASC
) 对这些成绩相同的行进行内部排序。
深入扩展与注意事项:
-
NULL
值的排序:在MySQL中,ORDER BY ... ASC
会将NULL
值排在最前面,ORDER BY ... DESC
会将NULL
值排在最后面。 -
性能:对大数据集进行排序是一项非常耗费资源的操作,特别是当排序的列没有索引时,可能会导致性能问题。应尽量为经常用于排序的列创建索引。
3.7 条件查询: WHERE
WHERE
子句用于从表中筛选出满足指定条件的记录。这是 SELECT
语句的精髓所在。
语法:
SELECT ... FROM ... WHERE 条件;
WHERE
子句中常用的运算符:
-
比较运算符:
SQL>
(大于),<
(小于),>=
(大于等于),<=
(小于等于),=
(等于),!=
或<>
(不等于)。-- 查询成绩大于90分的学生 SELECT name, score FROM students WHERE score > 90; -- 查询姓名不叫“张三”的学生 SELECT name, student_no FROM students WHERE name != '张三';
-
SQLBETWEEN ... AND ...
: 用于筛选某个范围内的值(包含边界)。-- 查询年龄在18到20岁之间的学生(包括18和20岁) SELECT name, age FROM students WHERE age BETWEEN 18 AND 20; -- 上一句等价于: SELECT name, age FROM students WHERE age >= 18 AND age <= 20;
-
SQLIN (...)
: 筛选出列的值在指定列表中的记录。-- 查询姓名为“张三”或“李四”的学生 SELECT * FROM students WHERE name IN ('张三', '李四'); -- 上一句等价于: SELECT * FROM students WHERE name = '张三' OR name = '李四'; -- 当列表很长时,IN 的写法更简洁。
-
SQLIS NULL
/IS NOT NULL
: 判断列的值是否为NULL
。-- 假设有些学生没有录入年龄,查询这些学生 -- INSERT INTO students (student_no, name) VALUES ('SN2025006', '钱八'); -- 先插入一条年龄为NULL的数据 SELECT name FROM students WHERE age IS NULL; -- 查询所有已经录入了年龄的学生 SELECT name, age FROM students WHERE age IS NOT NULL;
特别注意:不能使用
= NULL
或!= NULL
来判断NULL
值。NULL
是一个特殊的值,代表“未知”或“不存在”,它不等于任何值,包括它自己。因此必须使用IS NULL
或IS NOT NULL
。 -
LIKE
: 用于模糊查询,通常与通配符一起使用。-
%
: 代表零个、一个或多个任意字符。 -
_
: 代表一个任意字符。
-- 查询所有姓“张”的学生 SELECT name FROM students WHERE name LIKE '张%'; -- '张'开头,后面可以是任意字符 -- 查询名字中包含“五”的学生 SELECT name FROM students WHERE name LIKE '%五%'; -- 前后都可以是任意字符 -- 查询名字是两个字且第二个字是“六”的学生 SELECT name FROM students WHERE name LIKE '_六'; -- 第一个字符是任意单个字符,第二个是'六'
-
-
逻辑运算符:
SQLAND
(与),OR
(或),NOT
(非),用于连接多个条件。-- 查询年龄大于18岁 并且 成绩大于90分的学生 SELECT name, age, score FROM students WHERE age > 18 AND score > 90; -- 查询年龄大于19岁 或者 性别为“女”的学生 SELECT name, age, gender FROM students WHERE age > 19 OR gender = '女'; -- 查询学号不是以 'SN2025001' 开头的学生 SELECT name, student_no FROM students WHERE NOT (student_no LIKE 'SN2025001%');
深入扩展与注意事项:
-
运算符优先级:
NOT
的优先级最高,然后是AND
,最后是OR
。当一个WHERE
子句中同时包含AND
和OR
时,为避免歧义和逻辑错误,强烈建议使用括号()
来明确指定条件的组合顺序。例如:WHERE (age > 19 AND gender = '男') OR score > 95;
-
索引对
WHERE
的影响:WHERE
子句是数据库查询优化的核心。如果WHERE
条件中涉及的列上有索引(特别是B-Tree索引),数据库可以极大地缩小搜索范围,查询速度会快几个数量级。反之,如果列上没有索引(称为“全表扫描”),数据库需要逐行检查表中的每一条记录,效率极低。
3.8 分页查询: LIMIT
当查询结果集非常大时,一次性返回所有数据是不现实的。LIMIT
子句用于限制返回的记录数量,通常用于实现分页功能。
语法:
SELECT ... FROM ... [WHERE ...] [ORDER BY ...] LIMIT [offset,] count;
-
count
: 指定最多返回多少条记录。 -
offset
: 可选参数,指定从第几条记录开始返回(偏移量,第一条记录的偏移量是0)。
示例1:获取前N条记录
SQL
-- 查询成绩最高的前3名学生
SELECT name, score
FROM students
ORDER BY score DESC
LIMIT 3;
示例2:实现分页(例如,每页显示2条,查询第2页)
第二页的数据应该从第 (2-1) * 2 = 2
条记录(偏移量为2)开始,取2条。
SQL
-- 查询学生列表,每页2条,这是第2页的数据
SELECT id, name, score
FROM students
ORDER BY id ASC -- 分页查询通常需要一个确定的排序顺序,以保证每次查询的页面内容稳定
LIMIT 2, 2; -- 从偏移量为2的记录开始,取2条记录 (即第3条和第4条)
或者使用 OFFSET
关键字,更清晰:
SQL
-- 使用 OFFSET 关键字实现同样的效果
SELECT id, name, score
FROM students
ORDER BY id ASC
LIMIT 2 OFFSET 2;
深入扩展与注意事项:
-
LIMIT
的位置:LIMIT
子句必须放在SELECT
语句的最后面。 -
深度分页问题:当
OFFSET
值非常大时(例如LIMIT 1000000, 10
),查询性能会急剧下降。因为MySQL需要先扫描并跳过前面的100万条记录,然后才返回你需要的10条。对于需要高性能深度分页的场景,通常会采用“基于游标”或“基于键集”的分页策略,例如WHERE id > [上一页最后一条记录的ID] ORDER BY id ASC LIMIT 10
。 -
SQL执行顺序:理解
SELECT
语句的逻辑执行顺序对写出正确的SQL至关重要:-
FROM
:确定数据来源表。 -
WHERE
:根据条件过滤行。 -
GROUP BY
:对结果进行分组(高级主题)。 -
HAVING
:对分组后的结果进行过滤(高级主题)。 -
SELECT
:选择要显示的列或表达式。 -
DISTINCT
:对结果去重。 -
ORDER BY
:对最终结果进行排序。 -
LIMIT
:截取最终结果的指定部分。
-
四、 修改数据 (Update)
使用 UPDATE
语句来修改表中已存在的一条或多条记录。
语法:
UPDATE 表名 SET 列1=新值1, 列2=新值2, ... WHERE 条件;
示例:
SQL
-- 将学号为 'SN2025001' 的学生的成绩修改为 98.00,姓名修改为“张三丰”
UPDATE students
SET
score = 98.00,
name = '张三丰'
WHERE
student_no = 'SN2025001';
逐行注释与解析:
-
UPDATE students
:UPDATE
是修改数据的关键字,students
是目标表。 -
SET score = 98.00, name = '张三丰'
:SET
关键字后面跟着要修改的列和它们的新值,多个“列=值”对之间用逗号隔开。 -
WHERE student_no = 'SN2025001'
:WHERE
子句指定了要修改哪些行。这里是学号为'SN2025001'
的那一行。
深入扩展与注意事项:
-
!!!极度危险:忘记WHERE子句!!!
如果执行 UPDATE 语句时忘记写 WHERE 子句,例如:UPDATE students SET score = 60.00;,这条语句将会把表中所有行的 score 列都更新为 60.00。这是一个非常严重且常见的误操作,可能导致灾难性的数据丢失。在执行 UPDATE 操作前,务必再三检查 WHERE 条件是否正确。
-
安全实践:在执行一个不确定的
UPDATE
或DELETE
语句前,可以先用相同的WHERE
条件写一个SELECT
语句,看看选中的是否是自己想要操作的数据。例如,先执行SELECT * FROM students WHERE student_no = 'SN2025001';
,确认查出来的是且仅是张三的数据后,再执行UPDATE
。
五、 删除数据 (Delete)
使用 DELETE
语句从表中删除一条或多条记录。
语法:
DELETE FROM 表名 WHERE 条件;
示例:
SQL
-- 删除学号为 'SN2025005' 的学生记录
DELETE FROM students WHERE student_no = 'SN2025005';
逐行注释与解析:
-
DELETE FROM students
:DELETE FROM
是删除数据的关键字,students
是目标表。 -
WHERE student_no = 'SN2025005'
:WHERE
子句指定了要删除哪些行。
深入扩展与注意事项:
-
!!!同样极度危险:忘记WHERE子句!!!
如果执行 DELETE FROM students; 且没有 WHERE 子句,它将删除表中所有的行。这个操作同样是不可逆的(在没有备份或事务回滚的情况下),必须极度小心。
-
DELETE vs TRUNCATE vs DROP
这是面试和实践中非常重要的一个区别:
-
DELETE FROM students;
:-
属于 DML (数据操作语言)。
-
逐行删除,并且每删除一行都会记录日志。
-
如果在一个事务中执行,可以被回滚 (ROLLBACK)。
-
删除时会触发为该表定义的触发器 (Trigger)。
-
不会重置
AUTO_INCREMENT
的值。如果删除了所有数据,新插入的数据ID会接着之前的最大ID继续增长。 -
对于大表来说,速度很慢。
-
-
TRUNCATE TABLE students;
:-
属于 DDL (数据定义语言)。
-
它不是逐行删除,而是通过释放存储表数据的数据页来一次性清空表,速度极快。
-
通常不能被回滚(在某些数据库系统中可能可以,但行为不统一)。
-
不会触发删除触发器。
-
会重置
AUTO_INCREMENT
的值回到初始状态(通常是1)。
-
-
DROP TABLE students;
:-
属于 DDL (数据定义语言)。
-
彻底删除整个表,包括表的结构定义和所有数据。
-
执行后,
students
这张表将不复存在。
-
-
六、 内容重点总结
至此,我们已经详细学习了 MySQL 最基础的增、删、改、查操作。我们来回顾一下核心要点:
-
新增 (Create): 使用
INSERT INTO
。推荐使用指定列插入的方式,并可一次性插入多行以提高效率。-
INSERT INTO table (col1, col2) VALUES (val1, val2);
-
-
查询 (Retrieve): 使用
SELECT
,功能最丰富。-
避免使用
SELECT *
,明确指定所需列。 -
可以使用表达式进行计算,用别名 (
AS
) 提高可读性。 -
DISTINCT
用于结果去重。 -
ORDER BY
用于结果排序 (ASC
/DESC
)。 -
WHERE
是查询的灵魂,通过各种条件(比较、范围、列表、模糊、逻辑)过滤数据。 -
LIMIT
用于分页,限制返回的行数。
-
-
修改 (Update): 使用
UPDATE ... SET ...
。核心是WHERE
子句,绝对不能省略,否则将更新整张表。-
UPDATE table SET col1=val1 WHERE condition;
-
-
删除 (Delete): 使用
DELETE FROM ...
。核心也是WHERE
子句,绝对不能省略,否则将删除整张表。-
DELETE FROM table WHERE condition;
-
-
安全第一: 对于
UPDATE
和DELETE
操作,永远要先用SELECT
搭配相同的WHERE
条件来验证你将要影响的数据行是否正确。
七、 课后作业 (实践练习建议)
学习数据库最好的方式就是不断练习。基于我们创建的 students
表,你可以尝试完成以下任务来巩固所学知识:
-
新增:
-
再插入3名新的学生信息,其中一名学生的
score
留空(即NULL
)。 -
尝试使用
INSERT IGNORE
插入一条与现有student_no
冲突的记录,并观察结果。
-
-
查询:
-
查询所有成绩在80分到90分之间的女同学的姓名和学号。
-
查询所有在2025年9月1日入学的,且不姓“张”的学生信息。
-
查询所有学生信息,按年龄降序排列,如果年龄相同,则按入学日期升序排列。
-
查询成绩为空(
NULL
)的学生。 -
查询出所有学生姓名的第一个字(提示:可以使用字符串函数
SUBSTRING()
)。 -
查询学生列表,每页显示3条,请写出查询第3页数据的SQL语句。
-
-
修改:
-
将所有年龄为空的学生,年龄更新为18岁。
-
将总分排名第一的学生的成绩加1分(提示:需要结合
ORDER BY
和LIMIT
)。
-
-
删除:
-
删除所有年龄大于20岁的学生记录。
-
通过完成这些练习,你将能更深刻地理解和记忆这些基础但至关重要的SQL操作。