MySQL笔记---基本查询
1. 插入数据(增)
INSERT 语句用于向数据库表中插入新记录。基本语法:
INSERT INTO 表名称 [(列1, 列2, ...)]
VALUES (值1, 值2, ...) [, (值1, 值2, ...)];
我们统一使用这张表进行举例:
-- 创建一张学生表
DROP TABLE IF EXISTS students;
CREATE TABLE students ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, sn INT NOT NULL UNIQUE COMMENT '学号', name VARCHAR(20) NOT NULL, qq VARCHAR(20)
);
1.1 单行数据 + 全列插入
不指定对哪些列插入数据,此时默认对所有列按照顺序插入:
INSERT INTO 表名称 VALUES (值1, 值2, ...);mysql> INSERT INTO students VALUES (100, 10000, '唐三藏', NULL);
Query OK, 1 row affected (0.01 sec)mysql> INSERT INTO students VALUES (101, 10001, '孙悟空', '1000');
Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM students;
+-----+-------+-----------+------+
| id | sn | name | qq |
+-----+-------+-----------+------+
| 100 | 10000 | 唐三藏 | NULL |
| 101 | 10001 | 孙悟空 | 1000 |
+-----+-------+-----------+------+
2 rows in set (0.00 sec)
1.2 多行数据 + 指定列插入
显式指定要对哪些列插入数据(剩下的列使用默认值或自增值):
INSERT INTO 表名称 (列1, 列2, ...) VALUES (值1, 值2, ...) [, (值1, 值2, ...)];mysql> INSERT INTO students (id, sn, name) VALUES -> (102, 20001, '曹孟德'), -> (103, 20002, '孙仲谋');
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0mysql> SELECT * FROM students;
+-----+-------+-----------+------+
| id | sn | name | qq |
+-----+-------+-----------+------+
| 100 | 10000 | 唐三藏 | NULL |
| 101 | 10001 | 孙悟空 | 1000 |
| 102 | 20001 | 曹孟德 | NULL |
| 103 | 20002 | 孙仲谋 | NULL |
+-----+-------+-----------+------+
4 rows in set (0.00 sec)
1.3 冲突则更新
如果插入的数据与已存在的数据发生冲突(主键,唯一键等):
mysql> INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师');
ERROR 1062 (23000): Duplicate entry '100' for key 'students.PRIMARY'
mysql> INSERT INTO students (sn, name) VALUES (20001, '曹阿瞒');
ERROR 1062 (23000): Duplicate entry '20001' for key 'students.sn'
我们可以采用冲突则更新的方式进行插入:
INSERT INTO 表名称 [(列1, 列2, ...)]
VALUES (值1, 值2, ...)
ON DUPLICATE KEY UPDATE 列 = 值 [, 列 = 值]
-- ON DUPLICATE KEY 当发生重复key的时候
即,若发生冲突,则不进行插入,而是对被冲突的数据进行更新:
mysql> INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师') -> ON DUPLICATE KEY UPDATE sn = 10010, name = '唐大师';
Query OK, 2 rows affected (0.01 sec)mysql> SELECT * FROM students;
+-----+-------+-----------+------+
| id | sn | name | qq |
+-----+-------+-----------+------+
| 100 | 10010 | 唐大师 | NULL |
| 101 | 10001 | 孙悟空 | 1000 |
| 102 | 20001 | 曹孟德 | NULL |
| 103 | 20002 | 孙仲谋 | NULL |
+-----+-------+-----------+------+
4 rows in set (0.00 sec)
当我们执行插入语句之后,可以看到执行的反馈提示两行受到影响,当采用如上方式进行插入时,受影响行数有三种情况:
- 0 row affected: 表中有冲突数据,但冲突数据的值和 update 的值相等;
- 1 row affected: 表中没有冲突数据,数据被插入 ;
- 2 row affected: 表中有冲突数据,并且数据已经被更新。
除了执行后的输出结果,我们还可以通过ROW_COUNT()函数查询最近一次受影响行数:
mysql> SELECT ROW_COUNT();
+-------------+
| ROW_COUNT() |
+-------------+
| -1 |
+-------------+
1 row in set (0.00 sec)
1.4 替换
除了用INSERT进行插入,我们还可以使用REPALCE进行插入:
REPLACE INTO 表名称 [(列1, 列2, ...)]
VALUES (值1, 值2, ...) [, (值1, 值2, ...)];
相比于INSERT,REPLACE关键字进行插入的行为是:
- 不冲突:直接插入(1 row affected);
- 冲突:删除冲突的数据,再重新插入(2 row affected)。
mysql> REPLACE INTO students (sn, name) VALUES (20001, '曹阿瞒');
Query OK, 2 rows affected (0.01 sec)mysql> SELECT * FROM students;
+-----+-------+-----------+------+
| id | sn | name | qq |
+-----+-------+-----------+------+
| 100 | 10010 | 唐大师 | NULL |
| 101 | 10001 | 孙悟空 | 1000 |
| 103 | 20002 | 孙仲谋 | NULL |
| 105 | 20001 | 曹阿瞒 | NULL |
+-----+-------+-----------+------+
4 rows in set (0.00 sec)
1.5 插入查询结果
可以将查询的结果插入到表中:
INSERT INTO 表名称 SELECT ...
要求查询出来的临时表每一行的属性与目标表每一行的属性完全对应,否则无法插入。
2. 查询数据(查)
SELECT 语句是用于从数据库表中查询和检索数据的核心语句,也是 SQL 中最常用、功能最灵活的语句之一。它支持从单表、多表关联,到复杂的条件过滤、排序、聚合统计等多种需求。
2.1 基本语法结构
SELECT 语句的核心语法遵循固定顺序(执行顺序与书写顺序不同,但书写需严格按此顺序):
SELECT [DISTINCT] 列名1, 列名2, ... -- (4)要查询的列(或*表示所有列)
FROM 表名称1 [JOIN 表名称2 ON 关联条件] -- (1)数据来源(单表或多表关联)
WHERE 行过滤条件 -- (2)筛选符合条件的行(先过滤行,再处理列)
GROUP BY 分组列1, 分组列2, ... -- (3)按指定列分组(用于聚合统计)
HAVING 分组过滤条件 -- (5)筛选分组后的结果(仅对分组有效)
ORDER BY 排序列1 [ASC/DESC], ... -- (6)对结果排序(ASC升序,DESC降序,默认ASC)
LIMIT [偏移量,] 行数 -- (7)限制返回的结果条数(用于分页等场景)
为了方便举例,我们再创建一个表格:
-- 创建表结构
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);mysql> 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.01 sec)
2.2 基本查询
-- 查询指定表的所有列
SELECT * FROM 表名称;-- 查询指定表的指定列
SELECT 列名1, 列名2, ... FROM 表名称;mysql> SELECT name, chinese FROM exam_result;
+-----------+---------+
| name | chinese |
+-----------+---------+
| 唐三藏 | 67 |
| 孙悟空 | 87 |
| 猪悟能 | 88 |
| 曹孟德 | 82 |
| 刘玄德 | 55 |
| 孙权 | 70 |
| 宋公明 | 75 |
+-----------+---------+
7 rows in set (0.00 sec)
2.2.1 去重查询
在SELECT关键字后加上DISTINCT关键字,此时查询出来的结果就不会有重复行:
-- 去重查询指定表的所有列
SELECT DISTINCT * FROM 表名称;-- 去重查询指定表的指定列
SELECT DISTINCT 列名1, 列名2, ... FROM 表名称;
2.2.2 列重命名
被查询的列可以是表达式,例如:
mysql> SELECT name, chinese+math+english FROM exam_result;
+-----------+----------------------+
| name | chinese+math+english |
+-----------+----------------------+
| 唐三藏 | 221 |
| 孙悟空 | 242 |
| 猪悟能 | 276 |
| 曹孟德 | 233 |
| 刘玄德 | 185 |
| 孙权 | 221 |
| 宋公明 | 170 |
+-----------+----------------------+
7 rows in set (0.00 sec)
但是这样的表达式显然可读性较低,我们可以对要查询的列进行重命名:
SELECT DISTINCT 列名1 AS 新列名1, 列名2 AS 新列名2, ... FROM 表名称;
或者
SELECT DISTINCT 列名1 新列名1, 列名2 新列名2, ... FROM 表名称;mysql> SELECT name AS 姓名, chinese+math+english AS 总分 FROM exam_result;
+-----------+--------+
| 姓名 | 总分 |
+-----------+--------+
| 唐三藏 | 221 |
| 孙悟空 | 242 |
| 猪悟能 | 276 |
| 曹孟德 | 233 |
| 刘玄德 | 185 |
| 孙权 | 221 |
| 宋公明 | 170 |
+-----------+--------+
7 rows in set (0.00 sec)
2.3 条件过滤(WHERE)
对被查询的表中的记录(行)进行筛选:
WHERE 条件表达式
2.3.1 比较表达式
比较表达式通过 比较运算符 对两个值(或表达式)进行比较,返回 TRUE(1)、FALSE(0)或 NULL(无法判断,如与 NULL 比较)。
常用于 WHERE 子句筛选行,或 SELECT 子句计算列值。
运算符 | 作用说明 | 适用场景 |
= | 等于(注意:不能判断 NULL) | 精确匹配 |
<> 或 != | 不等于 | 排除特定值 |
> / < | 大于 / 小于 | 范围筛选(单侧) |
>= / <= | 大于等于 / 小于等于 | 范围筛选(包含边界) |
BETWEEN A AND B | 在 A 到 B 之间(包含 A 和 B) | 连续范围筛选 |
IN (值1, 值2, ...) | 在指定集合中 | 离散值匹配 |
NOT IN (...) | 不在指定集合中 | 排除离散值 |
LIKE | 模糊匹配(% 匹配任意字符,_ 匹配单个字符) | 字符串模糊查询 |
NOT LIKE | 不满足模糊匹配 | 排除模糊匹配结果 |
REGEXP / RLIKE | 正则表达式匹配 | 复杂字符串模式匹配 |
IS NULL | 判断值是否为 NULL | 筛选NULL |
IS NOT NULL | 判断值是否不为 NULL | 筛选非NULL |
2.3.2 逻辑表达式(组合多个条件)
逻辑表达式通过 逻辑运算符 组合多个比较表达式,最终返回 TRUE/FALSE/NULL,用于处理 “多条件同时满足” 或 “满足任一条件” 的场景。
运算符 | 作用 | 优先级 |
NOT | 逻辑非(否定条件) | 最高 |
AND | 逻辑与(同时满足) | 中等 |
OR | 逻辑或(满足任一) | 最低 |
注意:
- 逻辑运算符优先级:NOT > AND > OR;
- 如需改变优先级,用 括号 () 强制指定计算顺序。
2.3.3 示例
(1)查询英语不及格的同学及其英语成绩
mysql> SELECT name, english FROM exam_result WHERE english < 60;
+-----------+---------+
| name | english |
+-----------+---------+
| 唐三藏 | 56 |
| 刘玄德 | 45 |
| 宋公明 | 30 |
+-----------+---------+
3 rows in set (0.00 sec)
(2)查询语文成绩在 [80, 90] 分的同学及其语文成绩
mysql> SELECT name, chinese FROM exam_result WHERE chinese BETWEEN 80 AND 90;
+-----------+---------+
| name | chinese |
+-----------+---------+
| 孙悟空 | 87 |
| 猪悟能 | 88 |
| 曹孟德 | 82 |
+-----------+---------+
3 rows in set (0.00 sec)
(3)查询姓孙的同学
mysql> SELECT name FROM exam_result WHERE name LIKE '孙%';
+-----------+
| name |
+-----------+
| 孙悟空 |
| 孙权 |
+-----------+
2 rows in set (0.00 sec)
(4)查询孙某同学
mysql> SELECT name FROM exam_result WHERE name LIKE '孙_';
+--------+
| name |
+--------+
| 孙权 |
+--------+
1 row in set (0.00 sec)
(5)查询qq号不为空的的同学及其qq号
mysql> SELECT name, qq FROM students WHERE qq IS NOT NULL;
+-----------+------+
| name | qq |
+-----------+------+
| 孙悟空 | 1000 |
+-----------+------+
1 row in set (0.00 sec)
2.4 排序(ORDER BY)
ORDER BY 用于对查询结果按指定列排序,默认按 ASC(升序)排列,可指定 DESC(降序)。
ORDER BY 列1 [ASC/DESC] [, 列2 [ASC/DESC]]...
默认情况下使用升序排序。
2.4.1 示例
(1)查询同学及其数学成绩,按数学成绩升序显示
mysql> 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)
(2)查询同学的各门成绩,依次按照数学降序,英语升序,语文升序的方式显示
mysql> SELECT name, math, chinese, english FROM exam_result ORDER BY math DESC, chinese ASC, english ASC;
+-----------+------+---------+---------+
| name | math | chinese | english |
+-----------+------+---------+---------+
| 唐三藏 | 98 | 67 | 56 |
| 猪悟能 | 98 | 88 | 90 |
| 刘玄德 | 85 | 55 | 45 |
| 曹孟德 | 84 | 82 | 67 |
| 孙悟空 | 78 | 87 | 77 |
| 孙权 | 73 | 70 | 78 |
| 宋公明 | 65 | 75 | 30 |
+-----------+------+---------+---------+
7 rows in set (0.00 sec)
2.5 限制结果条数(LIMIT)
LIMIT 用于限制返回的结果行数,常用于分页查询(如 “每页显示 10 条数据”),语法有三种:
- LIMIT 行数:直接返回前 N 行
LIMIT 行数
- LIMIT 偏移量, 行数:从 “偏移量” 位置开始,返回 N 行(偏移量从 0 开始)
LIMIT 偏移量, 行数
- LIMIT 行数 OFFSET 偏移量:从 “偏移量” 位置开始,返回 N 行(偏移量从 0 开始)
LIMIT 行数 OFFSET 偏移量
2.5.1 示例
(1)查询总分排名前三的同学
mysql> SELECT name, math+chinese+english 总分 FROM exam_result ORDER BY 总分 DESC LIMIT 3;
+-----------+--------+
| name | 总分 |
+-----------+--------+
| 猪悟能 | 276 |
| 孙悟空 | 242 |
| 曹孟德 | 233 |
+-----------+--------+
3 rows in set (0.00 sec)
(2)查询总分排行次三名的同学
mysql> SELECT name, math+chinese+english 总分 FROM exam_result ORDER BY 总分 DESC LIMIT 3, 3;
+-----------+--------+
| name | 总分 |
+-----------+--------+
| 唐三藏 | 221 |
| 孙权 | 221 |
| 刘玄德 | 185 |
+-----------+--------+
3 rows in set (0.00 sec)mysql> SELECT name, math+chinese+english 总分 FROM exam_result ORDER BY 总分 DESC LIMIT 3 OFFSET 3;
+-----------+--------+
| name | 总分 |
+-----------+--------+
| 唐三藏 | 221 |
| 孙权 | 221 |
| 刘玄德 | 185 |
+-----------+--------+
3 rows in set (0.00 sec)
2.6 聚合统计(GROUP BY + 聚合函数)
当需要对数据进行 “统计分析”(如计数、求和、平均值)时,需结合 聚合函数 和 GROUP BY 分组。
2.6.1 聚合函数
用于对一组数据进行统计计算(常与 GROUP BY 配合使用)。
函数 | 作用 |
COUNT(*) | 统计行数(包含 NULL) |
COUNT(列名) | 统计指定列非 NULL 的行数 |
SUM(列名) | 计算指定列的总和(仅数值型) |
AVG(列名) | 计算指定列的平均值 |
MAX(列名) | 取指定列的最大值 |
MIN(列名) | 取指定列的最小值 |
聚合函数在不进行分组时,就是对整个表生效。如果使用GROUP BY子句进行分组的话,就是每个组单独统计。
使用聚合函数作为表的查询结果时,表自身的列不能作为查询结果(聚合函数是多行统计的结果,各行之间的列有所不同)。
示例:查询各科平均分
mysql> SELECT AVG(chinese) 语文平均分, AVG(math) 数学平均分, AVG(english) 英语平均分 FROM exam_result;
+-------------------+-----------------+--------------------+
| 语文平均分 | 数学平均分 | 英语平均分 |
+-------------------+-----------------+--------------------+
| 74.85714285714286 | 83 | 63.285714285714285 |
+-------------------+-----------------+--------------------+
1 row in set (0.00 sec)
2.6.2 GROUP BY 分组统计
GROUP BY 列名 [, 列名]...
GROUP BY 按指定列分组(该列值相同的分为一组),聚合函数会作用于每个分组(而非整个表)。
GROUP BY 子句之后出现的列(用于分组的列),都可以作为查询结果(每一个组,这些列都是相同的)。
我们为exam_result新增一列class,并将同学们按照语文分数分为两个班:
mysql> SELECT * FROM exam_result;
+----+-------+-----------+---------+------+---------+
| id | class | name | chinese | math | english |
+----+-------+-----------+---------+------+---------+
| 1 | 01 | 唐三藏 | 67 | 98 | 56 |
| 2 | 02 | 孙悟空 | 87 | 78 | 77 |
| 3 | 02 | 猪悟能 | 88 | 98 | 90 |
| 4 | 02 | 曹孟德 | 82 | 84 | 67 |
| 5 | 01 | 刘玄德 | 55 | 85 | 45 |
| 6 | 01 | 孙权 | 70 | 73 | 78 |
| 7 | 01 | 宋公明 | 75 | 65 | 30 |
+----+-------+-----------+---------+------+---------+
7 rows in set (0.00 sec)
示例:分别查询两个班的平均值
mysql> SELECT class, AVG(chinese) 语文平均分, AVG(math) 数学平均分, AVG(english) 英语平均分 FROM exam_result GROUP BY class;
+-------+-------------------+-------------------+-----------------+
| class | 语文平均分 | 数学平均分 | 英语平均分 |
+-------+-------------------+-------------------+-----------------+
| 01 | 66.75 | 80.25 | 52.25 |
| 02 | 85.66666666666667 | 86.66666666666667 | 78 |
+-------+-------------------+-------------------+-----------------+
2 rows in set (0.00 sec)
2.6.3 HAVING 过滤分组结果
WHERE 过滤的是 “行”,HAVING 过滤的是 “分组后的结果”(仅在 GROUP BY 后使用)。
HAVING 条件表达式
示例:查询语文平均分大于80的班级及其平均分
mysql> SELECT class, AVG(chinese) 语文平均分 FROM exam_result GROUP BY class HAVING 语文平均分 > 80;
+-------+-------------------+
| class | 语文平均分 |
+-------+-------------------+
| 02 | 85.66666666666667 |
+-------+-------------------+
1 row in set (0.00 sec)
2.7 子查询(嵌套查询)
子查询是指 “在一个 SELECT 语句中嵌套另一个 SELECT 语句”,内层查询的结果作为外层查询的条件或数据源。
2.7.1 示例
(1)查询数学成绩大于平均分的同学及其成绩
mysql> SELECT name, math FROM exam_result WHERE math > (SELECT AVG(math) FROM exam_result);
+-----------+------+
| name | math |
+-----------+------+
| 唐三藏 | 98 |
| 猪悟能 | 98 |
| 曹孟德 | 84 |
| 刘玄德 | 85 |
+-----------+------+
4 rows in set (0.00 sec)
(2)查询在students表中出现的同学及其成绩
mysql> SELECT name, math, chinese, english FROM exam_result WHERE name IN (SELECT name FROM students);
+-----------+------+---------+---------+
| name | math | chinese | english |
+-----------+------+---------+---------+
| 孙悟空 | 78 | 87 | 77 |
+-----------+------+---------+---------+
1 row in set (0.00 sec)
3. 删除数据(删)
3.1 DELETE语句
DELETE 语句用于从表中删除符合条件的记录,是数据维护中常用的操作。由于删除操作不可逆(除非有备份或事务回滚),使用时需格外谨慎。基本语法:
DELETE FROM 表名 [WHERE 条件]; -- 若省略WHERE则删除表中所有记录
3.2 TRUNCATE语句
TRUNCATE 语句用于清空表的内容。基本语法:
TRUNCATE [TABLE] 表名;
准确来说是重置表,表的所有参数回到刚创建的状态。
3.3 清空表的两种方式对比
DELETE FROM 表名:逐行删除记录,会记录事务日志(可回滚),不重置自增主键(如自增 ID 会继续从上次的值增长);
TRUNCATE TABLE 表名:直接清空表数据(类似 “删除表再重建”),速度更快,不记录日志(不可回滚),会重置自增主键。
4. 更新数据(改)
UPDATE 语句用于修改表中已存在的记录,是数据维护的核心操作之一。
它支持单表更新、多表关联更新,还能结合条件、函数或子查询实现复杂的更新逻辑。由于更新操作不可逆(除非有备份或事务回滚),使用时需格外注意条件的准确性。基本语法:
UPDATE 表名
SET 列1 = 值1, 列2 = 值2, ... -- 要更新的列及对应新值
[WHERE 条件]; -- 可选,筛选需要更新的记录(省略则更新表中所有记录)