
表的增删改查
CRUD 是数据库操作的四种基本类型,分别对应:增删查改
-
Create(创建)
-
Retrieve(读取)
-
Update(更新)
-
Delete(删除)
1. Create(创建)
1.1 单行数据 + 全列插入
语法:
INSERT INTO table_name [(column [, column] ...)] VALUES (value_list);
案例:
-- 创建一张学生表
CREATE TABLE students (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
sn INT NOT NULL UNIQUE COMMENT '学号',
name VARCHAR(20) NOT NULL,
qq VARCHAR(20)
);
-- 插入单行数据
INSERT INTO students VALUES (101, 10001, '孙悟空', '11111');
Query OK, 1 row affected (0.02 sec)
-- 插入两条记录,value_list 数量必须和定义表的列的数量及顺序一致
INSERT INTO students VALUES (100, 10000, '唐三藏', NULL);
Query OK, 1 row affected (0.02 sec)
-- 查看插入结果
SELECT * FROM students;
+-----+-------+-----------+-------+
| id | sn | name | qq |
+-----+-------+-----------+-------+
| 100 | 10000 | 唐三藏 | NULL |
| 101 | 10001 | 孙悟空 | 11111 |
+-----+-------+-----------+-------+
2 rows in set (0.00 sec)
1.2 多行数据 + 指定列插入
语法:
INSERT INTO table_name (column [, column] ...) VALUES (value_list) [, (value_list)] ...;
案例:
-- 插入多行数据
INSERT INTO students (id, sn, name) VALUES
(102, 20001, '曹孟德'),
(103, 20002, '孙仲谋');
Query OK, 2 rows affected (0.02 sec)
Records: 2 Duplicates: 0 Warnings: 0
-- 查看插入结果
SELECT * FROM students;
+-----+-------+-----------+-------+
| id | sn | name | qq |
+-----+-------+-----------+-------+
| 100 | 10000 | 唐三藏 | NULL |
| 101 | 10001 | 孙悟空 | 11111 |
| 102 | 20001 | 曹孟德 | NULL |
| 103 | 20002 | 孙仲谋 | NULL |
+-----+-------+-----------+-------+
4 rows in set (0.00 sec)
1.3 插入否则更新
当主键或唯一键对应的值已经存在时,可以选择性地进行更新操作。
语法:
INSERT INTO table_name (column [, column] ...) VALUES (value_list)
ON DUPLICATE KEY UPDATE column = value [, column = value] ...;
案例:
-- 主键冲突
INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师');
ERROR 1062 (23000): Duplicate entry '100' for key 'PRIMARY'
-- 唯一键冲突
INSERT INTO students (sn, name) VALUES (20001, '曹阿瞒');
ERROR 1062 (23000): Duplicate entry '20001' for key 'sn'
-- 插入否则更新
INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师')
ON DUPLICATE KEY UPDATE sn = 10010, name = '唐大师';
Query OK, 2 rows affected (0.47 sec)
-- 获取受影响的行数
SELECT ROW_COUNT();
+-------------+
| ROW_COUNT() |
+-------------+
| 2 |
+-------------+
1.4 替换
语法:
REPLACE INTO table_name (column [, column] ...) VALUES (value_list) [, (value_list)] ...;
案例:
-- 替换数据
REPLACE INTO students (sn, name) VALUES (20001, '曹阿瞒');
Query OK, 2 rows affected (0.00 sec)
2. Retrieve(读取)
2.1 SELECT 列
语法:
SELECT [DISTINCT] {column [, column] ... | *} FROM table_name
[WHERE ...]
[ORDER BY column [ASC | DESC], ...]
[LIMIT ...];
案例:
-- 创建表结构
CREATE TABLE exam_result (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL COMMENT '同学姓名',
chinese FLOAT DEFAULT 0.0 COMMENT '语文成绩',
math FLOAT DEFAULT 0.0 COMMENT '数学成绩',
english FLOAT DEFAULT 0.0 COMMENT '英语成绩'
);
-- 插入测试数据
INSERT INTO exam_result (name, chinese, math, english) VALUES
('唐三藏', 67, 98, 56),
('孙悟空', 87, 78, 77),
('猪悟能', 88, 98, 90),
('曹孟德', 82, 84, 67),
('刘玄德', 55, 85, 45),
('孙权', 70, 73, 78),
('宋公明', 75, 65, 30);
Query OK, 7 rows affected (0.00 sec)
Records: 7 Duplicates: 0 Warnings: 0
-- 查询所有列
SELECT * FROM exam_result;
+----+-----------+-------+--------+--------+
| id | name | chinese | math | english |
+----+-----------+-------+--------+--------+
| 1 | 唐三藏 | 67 | 98 | 56 |
| 2 | 孙悟空 | 87 | 78 | 77 |
| 3 | 猪悟能 | 88 | 98 | 90 |
| 4 | 曹孟德 | 82 | 84 | 67 |
| 5 | 刘玄德 | 55 | 85 | 45 |
| 6 | 孙权 | 70 | 73 | 78 |
| 7 | 宋公明 | 75 | 65 | 30 |
+----+-----------+-------+--------+--------+
7 rows in set (0.00 sec)
2.2 全列查询
通常不建议使用 * 进行全列查询,因为:
-
查询的列越多,传输的数据量越大。
-
可能会影响索引的使用。
2.3 指定列查询
-- 指定列查询
SELECT id, name, english FROM exam_result;
+----+-----------+--------+
| id | name | english |
+----+-----------+--------+
| 1 | 唐三藏 | 56 |
| 2 | 孙悟空 | 77 |
| 3 | 猪悟能 | 90 |
| 4 | 曹孟德 | 67 |
| 5 | 刘玄德 | 45 |
| 6 | 孙权 | 78 |
| 7 | 宋公明 | 30 |
+----+-----------+--------+
7 rows in set (0.00 sec)
2.4 查询字段为表达式
-- 表达式不包含字段
SELECT id, name, 10 FROM exam_result;
+----+-----------+----+
| id | name | 10 |
+----+-----------+----+
| 1 | 唐三藏 | 10 |
| 2 | 孙悟空 | 10 |
| 3 | 猪悟能 | 10 |
| 4 | 曹孟德 | 10 |
| 5 | 刘玄德 | 10 |
| 6 | 孙权 | 10 |
| 7 | 宋公明 | 10 |
+----+-----------+----+
7 rows in set (0.00 sec)
-- 表达式包含一个字段
SELECT id, name, english + 10 FROM exam_result;
+----+-----------+-------------+
| id | name | english + 10 |
+----+-----------+-------------+
| 1 | 唐三藏 | 66 |
| 2 | 孙悟空 | 87 |
| 3 | 猪悟能 | 100 |
| 4 | 曹孟德 | 77 |
| 5 | 刘玄德 | 55 |
| 6 | 孙权 | 88 |
| 7 | 宋公明 | 40 |
+----+-----------+-------------+
7 rows in set (0.00 sec)
-- 表达式包含多个字段
SELECT id, name, chinese + math + english FROM exam_result;
+----+-----------+-------------------------+
| id | name | chinese + math + english |
+----+-----------+-------------------------+
| 1 | 唐三藏 | 221 |
| 2 | 孙悟空 | 242 |
| 3 | 猪悟能 | 276 |
| 4 | 曹孟德 | 233 |
| 5 | 刘玄德 | 185 |
| 6 | 孙权 | 221 |
| 7 | 宋公明 | 170 |
+----+-----------+-------------------------+
7 rows in set (0.00 sec)
2.5 为查询结果指定别名
语法:
SELECT column [AS] alias_name [...] FROM table_name;
案例:
-- 为查询结果指定别名
SELECT id, name, chinese + math + english AS 总分 FROM exam_result;
+----+-----------+--------+
| id | name | 总分 |
+----+-----------+--------+
| 1 | 唐三藏 | 221 |
| 2 | 孙悟空 | 242 |
| 3 | 猪悟能 | 276 |
| 4 | 曹孟德 | 233 |
| 5 | 刘玄德 | 185 |
| 6 | 孙权 | 221 |
| 7 | 宋公明 | 170 |
+----+-----------+--------+
7 rows in set (0.00 sec)
2.6 结果去重
-- 查询数学成绩
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)
2.7 WHERE 条件
比较运算符:
| 运算符 | 说明 |
|---|---|
| >, >=, <, <= | 大于、大于等于、小于、小于等于 |
| = | 等于,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 个)任意字符;_ 表示任意一个字符 |
逻辑运算符:
| 运算符 | 说明 |
|---|---|
| AND | 多个条件必须都为 TRUE(1),结果才是 TRUE(1) |
| OR | 任意一个条件为 TRUE(1),结果为 TRUE(1) |
| NOT | 条件为 TRUE(1),结果为 FALSE(0) |
案例:
-- 英语不及格的同学及英语成绩 (< 60)
SELECT name, english FROM exam_result WHERE english < 60;
+-----------+--------+
| name | english |
+-----------+--------+
| 唐三藏 | 56 |
| 刘玄德 | 45 |
| 宋公明 | 30 |
+-----------+--------+
3 rows in set (0.01 sec)
-- 语文成绩在 [80, 90] 分的同学及语文成绩
SELECT name, chinese FROM exam_result WHERE chinese >= 80 AND chinese <= 90;
+-----------+-------+
| name | chinese |
+-----------+-------+
| 孙悟空 | 87 |
| 猪悟能 | 88 |
| 曹孟德 | 82 |
+-----------+-------+
3 rows in set (0.00 sec)
-- 使用 BETWEEN ... AND ... 条件
SELECT name, chinese FROM exam_result WHERE chinese BETWEEN 80 AND 90;
+-----------+-------+
| name | chinese |
+-----------+-------+
| 孙悟空 | 87 |
| 猪悟能 | 88 |
| 曹孟德 | 82 |
+-----------+-------+
3 rows in set (0.00 sec)
-- 数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
SELECT name, math FROM exam_result
WHERE math = 58
OR math = 59
OR math = 98
OR math = 99;
+-----------+--------+
| name | math |
+-----------+--------+
| 唐三藏 | 98 |
| 猪悟能 | 98 |
+-----------+--------+
2 rows in set (0.01 sec)
-- 使用 IN 条件
SELECT name, math FROM exam_result WHERE math IN (58, 59, 98, 99);
+-----------+--------+
| name | math |
+-----------+--------+
| 唐三藏 | 98 |
| 猪悟能 | 98 |
+-----------+--------+
2 rows in set (0.00 sec)
-- 姓孙的同学及孙某同学
SELECT name FROM exam_result WHERE name LIKE '孙%';
+-----------+
| name |
+-----------+
| 孙悟空 |
| 孙权 |
+-----------+
2 rows in set (0.00 sec)
-- 匹配严格的一个任意字符
SELECT name FROM exam_result WHERE name LIKE '孙_';
+--------+
| name |
+--------+
| 孙权 |
+--------+
1 row in set (0.00 sec)
-- 语文成绩好于英语成绩的同学
SELECT name, chinese, english FROM exam_result WHERE chinese > english;
+-----------+-------+--------+
| name | chinese | english |
+-----------+-------+--------+
| 唐三藏 | 67 | 56 |
| 孙悟空 | 87 | 77 |
| 曹孟德 | 82 | 67 |
| 刘玄德 | 55 | 45 |
| 宋公明 | 75 | 30 |
+-----------+-------+--------+
5 rows in set (0.00 sec)
-- 总分在 200 分以下的同学
SELECT name, chinese + math + english AS 总分 FROM exam_result
WHERE chinese + math + english < 200;
+-----------+--------+
| name | 总分 |
+-----------+--------+
| 刘玄德 | 185 |
| 宋公明 | 170 |
+-----------+--------+
2 rows in set (0.00 sec)
-- 语文成绩 > 80 并且不姓孙的同学
SELECT name, chinese FROM exam_result
WHERE chinese > 80 AND name NOT LIKE '孙%';
+-----------+-------+
| name | chinese |
+-----------+-------+
| 猪悟能 | 88 |
| 曹孟德 | 82 |
+-----------+-------+
2 rows in set (0.00 sec)
-- 孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
SELECT name, chinese, math, english, chinese + math + english AS 总分
FROM exam_result
WHERE name LIKE '孙_' OR (
chinese + math + english > 200 AND chinese < math AND english > 80
);
+-----------+-------+--------+--------+--------+
| name | chinese | math | english | 总分 |
+-----------+-------+--------+--------+--------+
| 猪悟能 | 88 | 98 | 90 | 276 |
| 孙权 | 70 | 73 | 78 | 221 |
+-----------+-------+--------+--------+--------+
2 rows in set (0.00 sec)
-- 查询 qq 号已知的同学姓名
SELECT name, qq FROM students WHERE qq IS NOT NULL;
+-----------+-------+
| name | qq |
+-----------+-------+
| 孙悟空 | 11111 |
+-----------+-------+
1 row in set (0.00 sec)
-- NULL 和 NULL 的比较,= 和 <=> 的区别
SELECT NULL = NULL, NULL = 1, NULL = 0;
+-------------+----------+----------+
| NULL = NULL | NULL = 1 | NULL = 0 |
+-------------+----------+----------+
| NULL | NULL | NULL |
+-------------+----------+----------+
1 row in set (0.00 sec)
SELECT NULL <=> NULL, NULL <=> 1, NULL <=> 0;
+---------------+------------+------------+
| NULL <=> NULL | NULL <=> 1 | NULL <=> 0 |
+---------------+------------+------------+
| 1 | 0 | 0 |
+---------------+------------+------------+
1 row in set (0.00 sec)
2.8 结果排序
语法:
SELECT ... FROM table_name [WHERE ...]
ORDER BY column [ASC|DESC], [...];
案例:
-- 同学及数学成绩,按数学成绩升序显示
SELECT name, math FROM exam_result ORDER BY math;
+-----------+--------+
| name | math |
+-----------+--------+
| 宋公明 | 65 |
| 孙权 | 73 |
| 孙悟空 | 78 |
| 曹孟德 | 84 |
| 刘玄德 | 85 |
| 唐三藏 | 98 |
| 猪悟能 | 98 |
+-----------+--------+
7 rows in set (0.00 sec)
-- 同学及 qq 号,按 qq 号排序显示
SELECT name, qq FROM students ORDER BY qq;
+-----------+-------+
| name | qq |
+-----------+-------+
| 唐大师 | NULL |
| 孙仲谋 | NULL |
| 曹阿瞒 | NULL |
| 孙悟空 | 11111 |
+-----------+-------+
4 rows in set (0.00 sec)
-- NULL 视为比任何值都小,降序出现在最下面
SELECT name, qq FROM students ORDER BY qq DESC;
+-----------+-------+
| name | qq |
+-----------+-------+
| 孙悟空 | 11111 |
| 唐大师 | NULL |
| 孙仲谋 | NULL |
| 曹阿瞒 | NULL |
+-----------+-------+
4 rows in set (0.00 sec)
-- 查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示
SELECT name, math, english, chinese FROM exam_result
ORDER BY math DESC, english, chinese;
+-----------+--------+--------+-------+
| name | math | english | chinese |
+-----------+--------+--------+-------+
| 唐三藏 | 98 | 56 | 67 |
| 猪悟能 | 98 | 90 | 88 |
| 刘玄德 | 85 | 45 | 55 |
| 曹孟德 | 84 | 67 | 82 |
| 孙悟空 | 78 | 77 | 87 |
| 孙权 | 73 | 78 | 70 |
| 宋公明 | 65 | 30 | 75 |
+-----------+--------+--------+-------+
7 rows in set (0.00 sec)
-- 查询同学及总分,由高到低
SELECT name, chinese + english + math AS 总分 FROM exam_result
ORDER BY 总分 DESC;
+-----------+--------+
| name | 总分 |
+-----------+--------+
| 猪悟能 | 276 |
| 孙悟空 | 242 |
| 曹孟德 | 233 |
| 唐三藏 | 221 |
| 孙权 | 221 |
| 刘玄德 | 185 |
| 宋公明 | 170 |
+-----------+--------+
7 rows in set (0.00 sec)
-- 查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示
SELECT name, math FROM exam_result
WHERE name LIKE '孙%' OR name LIKE '曹%'
ORDER BY math DESC;
+-----------+--------+
| name | math |
+-----------+--------+
| 曹孟德 | 84 |
| 孙悟空 | 78 |
| 孙权 | 73 |
+-----------+--------+
3 rows in set (0.00 sec)
6.2.4 筛选分页结果
语法:
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT s, n;
SELECT ...:指定要查询的列(* 表示所有列)。
FROM table_name:指定要查询的表名。
[WHERE ...](可选):筛选符合条件的行([] 表示可选)。
[ORDER BY ...](可选):对查询结果按指定列排序(需注意:如果使用 LIMIT 限制结果,通常建议配合 ORDER BY 确保结果顺序固定)。
LIMIT s, n:限制返回的行数,其中:
s表示偏移量(从第s行开始,行数从 0 开始计数)。n表示要返回的行数。
例如:
SELECT * FROM users LIMIT 5, 10;表示从 users 表中,跳过前 5 行,返回接下来的 10 行数据(即第 6 到第 15 行,以 0 为起始计数)。
这个语法在 MySQL、PostgreSQL 等数据库中常用,用于实现分页查询(如 “第 2 页,每页 10 条” 可表示为 LIMIT 10, 10)。
需要注意的是,LIMIT 还可以与 OFFSET 结合使用,语法为 LIMIT n OFFSET s,其作用与 LIMIT s, n 完全一致:s 是偏移量,n 是返回的行数。例如 LIMIT 10 OFFSET 5 与 LIMIT 5, 10 效果相同,都是跳过前 5 行,返回接下来的 10 行。两种写法功能等价,只是 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;
+----+-----------+--------+--------+-------+
| id | name | math | english | chinese |
+----+-----------+--------+--------+-------+
| 1 | 唐三藏 | 98 | 56 | 67 |
| 2 | 孙悟空 | 78 | 77 | 87 |
| 3 | 猪悟能 | 98 | 90 | 88 |
+----+-----------+--------+--------+-------+
3 rows in set (0.02 sec)
-- 第 2 页
SELECT id, name, math, english, chinese FROM exam_result
ORDER BY id LIMIT 3 OFFSET 3;
+----+-----------+--------+--------+-------+
| id | name | math | english | chinese |
+----+-----------+--------+--------+-------+
| 4 | 曹孟德 | 84 | 67 | 82 |
| 5 | 刘玄德 | 85 | 45 | 55 |
| 6 | 孙权 | 73 | 78 | 70 |
+----+-----------+--------+--------+-------+
3 rows in set (0.00 sec)
-- 第 3 页,如果结果不足 3 个,不会有影响
SELECT id, name, math, english, chinese FROM exam_result
ORDER BY id LIMIT 3 OFFSET 6;
+----+-----------+--------+--------+-------+
| id | name | math | english | chinese |
+----+-----------+--------+--------+-------+
| 7 | 宋公明 | 65 | 30 | 75 |
+----+-----------+--------+--------+-------+
1 row in set (0.00 sec)
3. Update(更新)
语法:
UPDATE table_name SET column = expr [, column = expr ...]
[WHERE ...] [ORDER BY ...] [LIMIT ...];
案例:
-- 将孙悟空同学的数学成绩变更为 80 分
SELECT name, math FROM exam_result WHERE name = '孙悟空';
+-----------+--------+
| name | math |
+-----------+--------+
| 孙悟空 | 78 |
+-----------+--------+
1 row in set (0.00 sec)
UPDATE exam_result SET math = 80 WHERE name = '孙悟空';
Query OK, 1 row affected (0.04 sec)
Rows matched: 1 Changed: 1 Warnings: 0
SELECT name, math FROM exam_result WHERE name = '孙悟空';
+-----------+--------+
| name | math |
+-----------+--------+
| 孙悟空 | 80 |
+-----------+--------+
1 row in set (0.00 sec)
-- 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分
SELECT name, math, chinese FROM exam_result WHERE name = '曹孟德';
+-----------+--------+-------+
| name | math | chinese |
+-----------+--------+-------+
| 曹孟德 | 84 | 82 |
+-----------+--------+-------+
1 row in set (0.00 sec)
UPDATE exam_result SET math = 60, chinese = 70 WHERE name = '曹孟德';
Query OK, 1 row affected (0.14 sec)
Rows matched: 1 Changed: 1 Warnings: 0
SELECT name, math, chinese FROM exam_result WHERE name = '曹孟德';
+-----------+--------+-------+
| name | math | chinese |
+-----------+--------+-------+
| 曹孟德 | 60 | 70 |
+-----------+--------+-------+
1 row in set (0.00 sec)
-- 将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
SELECT name, math, chinese + math + english AS 总分 FROM exam_result
ORDER BY 总分 LIMIT 3;
+-----------+--------+--------+
| name | math | 总分 |
+-----------+--------+--------+
| 宋公明 | 65 | 170 |
| 刘玄德 | 85 | 185 |
| 曹孟德 | 60 | 197 |
+-----------+--------+--------+
3 rows in set (0.00 sec)
UPDATE exam_result SET math = math + 30
ORDER BY chinese + math + english LIMIT 3;
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0
SELECT name, math, chinese + math + english AS 总分 FROM exam_result
WHERE name IN ('宋公明', '刘玄德', '曹孟德');
+-----------+--------+--------+
| name | math | 总分 |
+-----------+--------+--------+
| 曹孟德 | 90 | 227 |
| 刘玄德 | 115 | 215 |
| 宋公明 | 95 | 200 |
+-----------+--------+--------+
3 rows in set (0.00 sec)
SELECT name, math, chinese + math + english AS 总分 FROM exam_result
ORDER BY 总分 LIMIT 3;
+-----------+--------+--------+
| name | math | 总分 |
+-----------+--------+--------+
| 宋公明 | 95 | 200 |
| 刘玄德 | 115 | 215 |
| 唐三藏 | 98 | 221 |
+-----------+--------+--------+
3 rows in set (0.00 sec)
-- 将所有同学的语文成绩更新为原来的 2 倍
SELECT * FROM exam_result;
+----+-----------+-------+--------+--------+
| id | name | chinese | math | english |
+----+-----------+-------+--------+--------+
| 1 | 唐三藏 | 67 | 98 | 56 |
| 2 | 孙悟空 | 87 | 80 | 77 |
| 3 | 猪悟能 | 88 | 98 | 90 |
| 4 | 曹孟德 | 70 | 90 | 67 |
| 5 | 刘玄德 | 55 | 115 | 45 |
| 6 | 孙权 | 70 | 73 | 78 |
| 7 | 宋公明 | 75 | 95 | 30 |
+----+-----------+-------+--------+--------+
7 rows in set (0.00 sec)
UPDATE exam_result SET chinese = chinese * 2;
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7 Changed: 7 Warnings: 0
SELECT * FROM exam_result;
+----+-----------+-------+--------+--------+
| id | name | chinese | math | english |
+----+-----------+-------+--------+--------+
| 1 | 唐三藏 | 134 | 98 | 56 |
| 2 | 孙悟空 | 174 | 80 | 77 |
| 3 | 猪悟能 | 176 | 98 | 90 |
| 4 | 曹孟德 | 140 | 90 | 67 |
| 5 | 刘玄德 | 110 | 115 | 45 |
| 6 | 孙权 | 140 | 73 | 78 |
| 7 | 宋公明 | 150 | 95 | 30 |
+----+-----------+-------+--------+--------+
7 rows in set (0.00 sec)
4. Delete(删除)
4.1 删除数据
语法:
DELETE FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...];
案例:
-- 删除孙悟空同学的考试成绩
SELECT * FROM exam_result WHERE name = '孙悟空';
+----+-----------+-------+--------+--------+
| id | name | chinese | math | english |
+----+-----------+-------+--------+--------+
| 2 | 孙悟空 | 174 | 80 | 77 |
+----+-----------+-------+--------+--------+
1 row in set (0.00 sec)
DELETE FROM exam_result WHERE name = '孙悟空';
Query OK, 1 row affected (0.17 sec)
SELECT * FROM exam_result WHERE name = '孙悟空';
Empty set (0.00 sec)
-- 删除整张表数据
CREATE TABLE for_delete (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20)
);
Query OK, 0 rows affected (0.16 sec)
INSERT INTO for_delete (name) VALUES ('A'), ('B'), ('C');
Query OK, 3 rows affected (1.05 sec)
Records: 3 Duplicates: 0 Warnings: 0
SELECT * FROM for_delete;
+----+------+
| id | name |
+----+------+
| 1 | A |
| 2 | B |
| 3 | C |
+----+------+
3 rows in set (0.00 sec)
DELETE FROM for_delete;
Query OK, 3 rows affected (0.00 sec)
SELECT * FROM for_delete;
Empty set (0.00 sec)
INSERT INTO for_delete (name) VALUES ('D');
Query OK, 1 row affected (0.00 sec)
SELECT * FROM for_delete;
+----+------+
| id | name |
+----+------+
| 4 | D |
+----+------+
1 row in set (0.00 sec)
SHOW CREATE TABLE for_delete\G
*************************** 1. row ***************************
Table: for_delete
Create Table: CREATE TABLE `for_delete` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
4.2 截断表
语法:
TRUNCATE [TABLE] table_name;
案例:
-- 截断表
CREATE TABLE for_truncate (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20)
);
Query OK, 0 rows affected (0.16 sec)
INSERT INTO for_truncate (name) VALUES ('A'), ('B'), ('C');
Query OK, 3 rows affected (1.05 sec)
Records: 3 Duplicates: 0 Warnings: 0
SELECT * FROM for_truncate;
+----+------+
| id | name |
+----+------+
| 1 | A |
| 2 | B |
| 3 | C |
+----+------+
3 rows in set (0.00 sec)
TRUNCATE for_truncate;
Query OK, 0 rows affected (0.10 sec)
SELECT * FROM for_truncate;
Empty set (0.00 sec)
INSERT INTO for_truncate (name) VALUES ('D');
Query OK, 1 row affected (0.00 sec)
SELECT * FROM for_truncate;
+----+------+
| id | name |
+----+------+
| 1 | D |
+----+------+
1 row in set (0.00 sec)
SHOW CREATE TABLE for_truncate\G
*************************** 1. row ***************************
Table: for_truncate
Create Table: CREATE TABLE `for_truncate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
在 MySQL 中,TRUNCATE 是一个用于快速删除表中所有数据的 SQL 命令,其主要作用和特点如下:
清空表数据TRUNCATE 会删除表中的所有行,但保留表的结构(包括列、索引、约束等),相当于 “清空表内容但不删除表本身”。
语法:
TRUNCATE TABLE 表名;
与 DELETE 的区别
速度更快:TRUNCATE 本质上是通过重新创建表结构来清空数据(而非逐行删除),因此对于大表效率远高于 DELETE(DELETE 是逐行删除并记录日志)。
不触发触发器:TRUNCATE 不会激活表上的 DELETE 触发器,而 DELETE 会。
自增列重置:如果表中有自增列(如 AUTO_INCREMENT),TRUNCATE 会将自增计数器重置为初始值(通常是 1),而 DELETE 不会改变自增计数器。
事务支持:TRUNCATE 是 DDL(数据定义语言)操作,执行后会自动提交事务,无法回滚;DELETE 是 DML(数据操纵语言),可在事务中回滚。
注意事项
- 不能用于带有外键约束的表(除非先删除外键关联)。
- 执行
TRUNCATE需要表的DROP权限(因为其内部实现涉及表重建)。 - 清空的数据无法恢复,操作前需谨慎。
例如,清空 users 表:
TRUNCATE TABLE users;
5. 插入查询结果
语法:
INSERT INTO table_name [(column [, column ...])] SELECT ...;
案例:
-- 删除表中的重复记录,重复的数据只能有一份
CREATE TABLE duplicate_table (id int, name varchar(20));
Query OK, 0 rows affected (0.01 sec)
INSERT INTO duplicate_table VALUES
(100, 'aaa'),
(100, 'aaa'),
(200, 'bbb'),
(200, 'bbb'),
(200, 'bbb'),
(300, 'ccc');
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
-- 创建一张空表 no_duplicate_table,结构和 duplicate_table 一样
CREATE TABLE no_duplicate_table LIKE duplicate_table;
Query OK, 0 rows affected (0.00 sec)
-- 将 duplicate_table 的去重数据插入到 no_duplicate_table
INSERT INTO no_duplicate_table SELECT DISTINCT * FROM duplicate_table;
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
-- 通过重命名表,实现原子的去重操作
RENAME TABLE duplicate_table TO old_duplicate_table,
no_duplicate_table TO duplicate_table;
Query OK, 0 rows affected (0.00 sec)
-- 查看最终结果
SELECT * FROM duplicate_table;
+-----+------+
| id | name |
+-----+------+
| 100 | aaa |
| 200 | bbb |
| 300 | ccc |
+-----+------+
3 rows in set (0.00 sec)
这条 SQL 语句的作用是 将一个查询(SELECT)的结果插入到指定的表(table_name)中,是批量插入数据的常用方式。
具体说明:
INSERT INTO table_name [(column [, column ...])]:指定要插入数据的目标表,以及可选的目标列(如果省略列名,则默认插入所有列,且顺序需与表定义一致)。SELECT ...:这部分是查询语句,其返回的结果集将作为待插入的数据。SELECT结果的列数、数据类型必须与目标表的列(或指定的目标列)一一匹配。
举个例子:假设存在表 users(含 id、name、age 列),和表 new_users(结构与 users 相同),要将 users 中年龄大于 18 的用户插入到 new_users,可以写:
INSERT INTO new_users (id, name, age)
SELECT id, name, age FROM users WHERE age > 18;
如果列顺序完全一致,也可以省略目标列:
INSERT INTO new_users
SELECT id, name, age FROM users WHERE age > 18;
这种方式适合批量迁移数据、复制特定条件的数据到新表等场景。
6. 聚合函数
案例:
-- 统计班级共有多少同学
SELECT COUNT(*) FROM students;
+----------+
| COUNT(*) |
+----------+
| 4 |
+----------+
1 row in set (0.00 sec)
-- 统计班级收集的 qq 号有多少
SELECT COUNT(qq) FROM students;
+-----------+
| COUNT(qq) |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
-- 统计本次考试的数学成绩分数个数
SELECT COUNT(math) FROM exam_result;
+---------------+
| COUNT(math) |
+---------------+
| 6 |
+---------------+
1 row in set (0.00 sec)
SELECT COUNT(DISTINCT math) FROM exam_result;
+------------------------+
| COUNT(DISTINCT math) |
+------------------------+
| 5 |
+------------------------+
1 row in set (0.00 sec)
-- 统计数学成绩总分
SELECT SUM(math) FROM exam_result;
+-------------+
| SUM(math) |
+-------------+
| 569 |
+-------------+
1 row in set (0.00 sec)
-- 不及格 < 60 的总分,没有结果,返回 NULL
SELECT SUM(math) FROM exam_result WHERE math < 60;
+-------------+
| SUM(math) |
+-------------+
| NULL |
+-------------+
1 row in set (0.00 sec)
-- 统计平均总分
SELECT AVG(chinese + math + english) AS 平均总分 FROM exam_result;
+--------------+
| 平均总分 |
+--------------+
| 297.5 |
+--------------+
1 row in set (0.00 sec)
-- 返回英语最高分
SELECT MAX(english) FROM exam_result;
+-------------+
| MAX(english)|
+-------------+
| 90 |
+-------------+
1 row in set (0.00 sec)
-- 返回 > 70 分以上的数学最低分
SELECT MIN(math) FROM exam_result WHERE math > 70;
+-------------+
| MIN(math) |
+-------------+
| 73 |
+-------------+
1 row in set (0.00 sec)
| 聚合函数 | 作用说明 | 示例场景 |
|---|---|---|
COUNT(*) | 统计所有行数(包括 NULL 值的行) | 统计班级总人数(SELECT COUNT(*) FROM students) |
COUNT(列名) | 统计指定列中非 NULL 值的行数 | 统计班级中填写了 QQ 号的人数(SELECT COUNT(qq) FROM students) |
COUNT(DISTINCT 列名) | 统计指定列中非 NULL 且不重复的值的数量 | 统计数学成绩中不同分数的个数(SELECT COUNT(DISTINCT math) FROM exam_result) |
SUM(列名) | 计算指定列的总和(忽略 NULL 值,无符合条件时返回 NULL) | 计算数学成绩的总分(SELECT SUM(math) FROM exam_result) |
AVG(表达式) | 计算指定列或表达式的平均值(忽略 NULL 值) | 计算语文 + 数学 + 英语的平均总分(SELECT AVG(chinese + math + english) ...) |
MAX(列名) | 查找指定列中的最大值(忽略 NULL 值) | 查找英语成绩的最高分(SELECT MAX(english) FROM exam_result) |
MIN(列名) | 查找指定列中的最小值(忽略 NULL 值,可结合 WHERE 条件筛选范围) | 查找数学成绩 >70 分的最低分(SELECT MIN(math) FROM exam_result WHERE math > 70) |
共性特点:
- 聚合函数用于对一组数据进行计算并返回单一结果,通常配合
GROUP BY分组使用(示例中未分组,默认对全表数据聚合)。 - 除
COUNT(*)外,其他聚合函数均忽略 NULL 值(即不参与计算)。
7. GROUP BY 子句的使用
在 SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。
语法:
SELECT column1, column2, ... FROM table GROUP BY column;
案例:
-- 显示每个部门的平均工资和最高工资
SELECT deptno, AVG(sal), MAX(sal) FROM EMP GROUP BY deptno;
-- 显示每个部门的每种岗位的平均工资和最低工资
SELECT AVG(sal), MIN(sal), job, deptno FROM EMP GROUP BY deptno, job;
-- 显示平均工资低于 2000 的部门和它的平均工资
SELECT AVG(sal) AS myavg FROM EMP GROUP BY deptno HAVING myavg < 2000;
这条 SQL 语句的作用是 根据指定的列(column)对表中的数据进行分组,然后查询每个分组中的指定列(column1, column2, ...)的值。
分组的核心逻辑是:将表中 “column 列值相同” 的行归为一组,最终结果会为每个分组返回一条记录。
关键说明:
分组依据:GROUP BY column 表示按照 column 列的值进行分组。例如,按 “班级” 分组时,同一个班级的所有学生会被归为一组。
查询列的限制:
SELECT 后指定的列(column1, column2, ...)必须满足以下条件之一:
-
是
GROUP BY后指定的分组列(即column本身); -
与聚合函数(如
COUNT()、SUM()、AVG()等)配合使用(用于计算每个分组的统计值)。 -
若查询非分组列且不使用聚合函数,结果会是 “未定义的”(不同数据库可能返回随机值)。
示例:
假设有 exam_result 表(含 class 班级、name 姓名、math 数学成绩),数据如下:
| class | name | math |
|---|---|---|
| 1 班 | 张三 | 80 |
| 1 班 | 李四 | 90 |
| 2 班 | 王五 | 70 |
| 2 班 | 赵六 | 85 |
场景 1:按班级分组,查询每个班级及该班的学生人数
SELECT class, COUNT(name) AS 学生人数
FROM exam_result
GROUP BY class;
结果:
+-------+----------+
| class | 学生人数 |
+-------+----------+
| 1班 | 2 |
| 2班 | 2 |
+-------+----------+
场景 2:按班级分组,查询每个班级的数学平均分
SELECT class, AVG(math) AS 数学平均分
FROM exam_result
GROUP BY class;
结果:
+-------+--------------+
| class | 数学平均分 |
+-------+--------------+
| 1班 | 85.0000 |
| 2班 | 77.5000 |
+-------+--------------+
总结:
GROUP BY 的核心是 “将相同特征的数据聚合成组”,通常与聚合函数配合使用,用于统计各组的汇总信息(如总数、平均值、最大值等),是数据分析中按类别统计的常用手段。
8. 实战 OJ
-
牛客:找出所有员工当前 (to_date='9999-01-01') 具体的薪水 salary 情况,对于相同的薪水只显示一次,并按照逆序显示
-
牛客:获取所有部门当前
manager的当前薪水情况,给出dept_no,emp_no以及salary,当前表示to_date='9999-01-01' -
牛客:从
titles表获取按照title进行分组,每组个数大于等于 2,给出title以及对应的数目t
LeetCode:
面试题:SQL 查询中各个关键字的执行先后顺序
FROM > ON > JOIN > WHERE > GROUP BY > WITH > HAVING > SELECT > DISTINCT > ORDER BY > LIMIT
from > on > join > where > group by > with > having > select > distinct > order by > limit
-
FROM:首先指定要查询的表。
-
ON:在多表连接时,用于指定连接条件。
-
JOIN:用于表之间的连接操作。
-
WHERE:对数据进行筛选,过滤不符合条件的行。
-
GROUP BY:对结果集进行分组。
-
HAVING:对分组后的结果进行筛选。
-
SELECT:指定要查询的列。
-
DISTINCT:用于去除重复的行。
-
ORDER BY:对结果集进行排序。
-
LIMIT:限制返回的行数。
需要注意的是,WITH 是一个子查询的语法,它在逻辑上可以看作是在查询的最开始执行的,用于定义临时的表或视图,但并不影响上述关键字的执行顺序。
在实际的 SQL 查询中,数据库引擎会根据查询的复杂性和优化器的规则对查询进行优化,但上述顺序是逻辑上的执行顺序。
174万+

被折叠的 条评论
为什么被折叠?



