【MySQL数据库基础】(七)删库跑路?先学会怎么“存”和“取”吧!MySQL 基础查询全攻略(上)

前言
如果说算法是灵魂,那么数据库就是肉体。无论你的架构多么牛叉,最终都要落地到数据的增删改查(CRUD)上。
很多初学者觉得 SQL 简单,不就是SELECT *吗?但真正到了高并发、大数据量的场景,基础不牢地动山摇。今天,咱们就带你深入浅出地剖析 MySQL 的“创建(Create)”与“查询(Retrieve)”,从零开始,拒绝死板!下面就让我们正式开始吧!

在开始写代码前,咱们先统一一下黑话。C (Create):创建/插入。R (Retrieve):读取/查询。U (Update):更新/修改。D (Delete):删除。
简单来说,这就是数据的生命周期。本文我们将重点攻克前两个:如何优雅地把数据存进去,以及如何精准地把数据搜出来。
一、Create:给数据库注入灵魂
要存数据,得先有表。咱们先在 Bash 终端里操作一把,创建一个名为 students 的学生表:
-- 这里是在 MySQL 命令行执行的 SQL CREATE TABLE students ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, -- 自增主键,防止乱码 ID [cite: 14] sn INT NOT NULL UNIQUE COMMENT '学号', -- 唯一学号,不能重复 [cite: 15] name VARCHAR(20) NOT NULL, -- 姓名,不能为空 [cite: 16] qq VARCHAR(20) -- QQ 号 [cite: 17] ); [cite: 13] 1.1 插入数据的“姿势”
有了表,接下来就是插入数据了。
姿势一:全列插入
如果你懒得写列名,可以直接全列插入。但注意,VALUES 后面的参数必须和表定义的列顺序、数量一字不差!
-- 这里的 id 如果填 NULL,由于我们设置了 AUTO_INCREMENT,MySQL 会自动帮我们数数 [cite: 20] INSERT INTO students VALUES (100, 10000, '唐三藏', NULL); [cite: 21] INSERT INTO students VALUES (101, 10001, '孙悟空', '11111'); [cite: 23] 姿势二:指定列插入
这是最推荐的方式。只插入你关心的列,不仅安全,还能减少数据传输。
INSERT INTO students (id, sn, name) VALUES (102, 20001, '曹孟德'), (103, 20002, '孙仲谋'); [cite: 41, 42, 43] 1.2 进阶操作:当“撞衫”时怎么办?
在插入数据时,经常会遇到主键冲突或唯一键冲突。 例如,你再次插入 id=100 的数据,MySQL 会报错:Duplicate entry '100' for key 'PRIMARY'。
方案 A:发生冲突就更新(ON DUPLICATE KEY UPDATE)
这种做法像极了现实生活中的“覆盖式安装”。如果主键冲突了,就按照我后面写的规则改一下。
INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师') ON DUPLICATE KEY UPDATE sn = 10010, name = '唐大师'; [cite: 79, 80] 注意:MySQL 返回的affected rows很有意思。如果是 0,说明没改;如果是 1,说明直接插入成功;如果是 2,说明发生了冲突并进行了更新。方案 B:简单粗暴的替换(REPLACE)
REPLACE 的逻辑是:没冲突就正常插;有冲突就先把你删了,我重新插一条!
REPLACE INTO students (sn, name) VALUES (20001, '曹阿瞒'); [cite: 100]二、Retrieve:大海捞针的艺术
存数据是为了用数据。SELECT语句是 SQL 的灵魂,它的语法极其丰富。
我们先搞一个考试成绩表 exam_result作为演示:
CREATE TABLE exam_result ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL, chinese float DEFAULT 0.0, math float DEFAULT 0.0, english float DEFAULT 0.0 ); [cite: 118] -- 批量插入一些英雄好汉的数据 [cite: 121] 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); [cite: 121, 122, 124, 127, 131, 134, 137, 138] 2.1 SELECT 的基础变幻
1. 全列查询(不推荐!)
SELECT * FROM exam_result; [cite: 146] 在生产环境中,千万别乱用*。首先,传输大量数据费带宽;其次,可能无法利用索引优化,导致查询变慢。
2. 指定列查询
只拿你想要的那一列,简单明了。
SELECT id, name, english FROM exam_result; [cite: 192] 3. 给查询结果“整整容”——别名
觉得列名太生硬?可以换个好听的名字展示。甚至可以对列进行计算。
-- 这里将三门成绩相加,并起个外号叫“总分” [cite: 311] SELECT id, name, chinese + math + english AS 总分 FROM exam_result; [cite: 310, 311] 4. 去重(DISTINCT)
如果只想看有哪些数学分数存在(不要重复的),就用 DISTINCT。
SELECT DISTINCT math FROM exam_result; [cite: 356] 2.2 WHERE 子句:数据的过滤器
如果没有 WHERE,数据库就是个垃圾堆。我们要筛选出有价值的信息,就需要各种运算符。
常见比较运算符
>>=<<=:最基础的大小比较。BETWEEN a0 AND a1:范围查询(闭区间)。IN (option, ...):离散集合匹配。IS NULL/IS NOT NULL:专门对付 NULL。LIKE:模糊匹配。%匹配任意个字符,_匹配一个。
案例实战
Q1:找出语文成绩在 [80, 90] 的同学?
SELECT name, chinese FROM exam_result WHERE chinese BETWEEN 80 AND 90; [cite: 406] Q2:姓孙的同学有哪些?
SELECT name FROM exam_result WHERE name LIKE '孙%'; [cite: 439] Q3:总分在 200 以下的同学?
陷阱警告:在WHERE条件中,不能使用你在SELECT里起的别名!
-- 错误写法:WHERE 总分 < 200 (会报错) SELECT name, chinese + math + english AS 总分 FROM exam_result WHERE chinese + math + english < 200; [cite: 475, 476, 477] 2.3 ORDER BY:让数据“排排坐”
排序是查询的最后一道工序。
ASC:升序(默认)。DESC:降序。多字段排序:我们可以先按数学降序,数学一样的再按英语升序。
SELECT name, math, english FROM exam_result ORDER BY math DESC, english ASC; [cite: 651] 冷知识:在ORDER BY中,是可以使用别名的!这和WHERE刚好相反。
2.4 LIMIT:分页查询的救星
如果你有 100 万条数据,一次性显示出来肯定卡死。这时就需要分页。
-- 从第 0 条开始,取 3 条(第一页) [cite: 725, 726, 733, 735] SELECT * FROM exam_result LIMIT 3 OFFSET 0; [cite: 735] -- 从第 3 条开始,取 3 条(第二页) [cite: 729, 758, 760] SELECT * FROM exam_result LIMIT 3 OFFSET 3; [cite: 760] 在对陌生的大表进行查询时,养成随手加LIMIT 1的习惯,这是后端开发的一种修养,防止因全表扫描导致的数据库卡死。
总结
本篇我们聊了“增”和“查”的最基础部分。在下一篇,我们将深入探讨“聚合函数”、“分组查询”以及让人头疼的“表连接”。
想要精通数据库,不仅要会写代码,更要懂它的心。 我们下期再见!