news 2026/10/16 7:26:00

MySQL增删查改实战:从SQL基础语法到安全操作习惯

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL增删查改实战:从SQL基础语法到安全操作习惯

1. 从一条SQL到一套基本功:为什么要认真对待增删查改

很多人学MySQL,第一眼看到的就是SELECT、INSERT、UPDATE、DELETE这四条语句,觉得简单到不需要花心思——无非就是“查一下”“加一行”“改个值”“删掉呗”。但我见过太多人,包括我自己刚入行的时候,都在这个“简单”上面栽过跟头。

举个例子,我早年做某个后台管理系统的数据修正,线上用户表里有一批字段值需要批量调整。我当时图省事,写了一条不带WHERE条件的UPDATE,结果整张表的数据全部被改成了同一个值。要不是有备份,那就是实实在在的生产事故。后来我复盘这件事,问题的根源不在于“SQL语法没背熟”,而在于我压根没有把增删查改当成一套需要系统性理解的“基本功”来对待。

这篇内容,就是围绕“基础增删查改”这个主题,把四个核心操作从语法、执行逻辑、实际场景到坑点、排查方法,完整梳理一遍。适合刚接触数据库的初学者把它当入门手册,也适合写过一段时间SQL但总感觉“哪里不对劲”的开发者对照查漏补缺。这里面没有晦涩的底层原理,每一条都对应实际开发中会用到的场景,看完可以直接在命令行或者客户端里照着敲一遍。

1.1 先理解MySQL里“增删查改”的底层工作方式

在学习具体语句之前,先建立两个最基本的概念,否则后面所有操作都会觉得像在“背单词”。

第一个概念是“表结构先行”。MySQL是关系型数据库,所有数据存储在“表”里,表由“行”和“列”构成。你想往里放数据,必须先告诉MySQL这张表长什么样——有哪些列、每列存什么类型的数据。这就好比你要在Excel里记账,肯定得先设计好表头,而不是随手往空白格子里填数字。所以,CREATE TABLE虽然不属于增删查改的四个操作,但没有它,后面四条语句根本无法执行。

第二个概念是“条件决定范围”。UPDATE和DELETE可以作用于一行,也可以作用于一百万行,唯一的分水岭就是WHERE子句。很多初学者会觉得WHERE只是“可选参数”,但实际上,它才是决定这条语句是“精准手术”还是“无差别轰炸”的关键。从设计上讲,MySQL的UPDATE和DELETE默认会扫描所有符合条件的行,如果没有条件限制,那就是全表范围生效。这不是MySQL设计得危险,而是它的逻辑本来就是“你让我改哪些,我改哪些;你没说清楚,我就当全部”。

1.2 准备好你的练习环境

既然要看懂、学会并亲手跑通增删查改,第一步是有一个能用的MySQL环境。如果你完全没装过,推荐直接用 Docker 拉一个镜像,五分钟就能跑起来:

docker run --name mysql-demo -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:8.0

提示:上面命令里的密码仅用于本地学习。实际开发中,数据库密码强度、访问权限、端口暴露范围都需要单独做安全加固,不要为了图方便在公网环境用弱口令。

如果你不熟悉Docker,直接在本地安装MySQL服务端和命令行客户端也可以。装完之后,先通过客户端连上去验证环境是否正常:

mysql -uroot -p

登录成功之后,接下来所有操作都在这个会话里进行。我个人建议专门建一个测试库,避免把系统库弄乱:

CREATE DATABASE IF NOT EXISTS demo_library DEFAULT CHARSET utf8mb4; USE demo_library;

我后面所有示例都基于这个demo_library库展开。用utf8mb4字符集,是因为它既能存中文,又能覆盖绝大多数Unicode字符,省得之后数据处理遇到乱码问题。

2. 增删查改的前置工作:建表与基础数据准备

2.1 创建一张带约束的学生表

我选用“学生信息管理”这个场景来演示,因为它足够形象,字段类型也覆盖了日常高频使用的整数、字符串、日期、枚举等类型。在demo_library库里执行下面这条建表语句:

CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键,自增', student_no VARCHAR(20) UNIQUE NOT NULL COMMENT '学号,唯一约束', name VARCHAR(50) NOT NULL COMMENT '姓名', gender ENUM('M', 'F') DEFAULT 'M' COMMENT '性别,M男F女', age INT NOT NULL DEFAULT 18 COMMENT '年龄', class_name VARCHAR(50) DEFAULT NULL COMMENT '班级', enroll_date DATE NOT NULL COMMENT '入学日期', score DECIMAL(5,2) DEFAULT 0.00 COMMENT '综合成绩' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生信息表';

这里每一个设计点都有讲究,不是随便写的。id设置为主键并自增,这是MySQL里最常用的“记录唯一标识”做法,确保每一行都有稳定的定位锚点。student_no加了UNIQUE唯一约束,防止重复学号混入数据。gender用ENUM枚举,限制取值范围,比直接存字符串更省空间,也在数据库层杜绝了脏数据。score用DECIMAL(5,2),意思是总共5位数字,小数占2位,最大能存999.99,用来存成绩不会出现浮点精度问题。

注意:DECIMAL和FLOAT/DOUBLE看起来都能存小数,但DECIMAL是定点数,存的是精确值;FLOAT/DOUBLE是浮点数,存的是近似值。涉及金额、分数、数量这类需要精确比较的数据,一律用DECIMAL。

2.2 插入第一批测试数据(多条插入)

建完表之后,先插入几条数据,为后面的查询、修改、删除提供“实验材料”:

INSERT INTO student (student_no, name, gender, age, class_name, enroll_date, score) VALUES ('S1001', '张三', 'M', 20, '计算机1班', '2023-09-01', 88.50), ('S1002', '李四', 'F', 19, '计算机1班', '2023-09-01', 92.00), ('S1003', '王五', 'M', 21, '软件2班', '2022-09-01', 77.25), ('S1004', '赵六', 'F', 19, NULL, '2024-09-01', 85.00), ('S1005', '孙七', 'M', 20, '数据1班', '2023-09-01', 91.50);

一次插入多行,用逗号分隔,比逐条执行五条INSERT语句效率高得多。注意我没有指定id字段,因为它自增,MySQL会自动为每一行生成唯一值。class_name允许为空,所以赵六那条记录故意留了NULL,方便后续演示空值筛选的场景。

2.3 快速验证当前数据

在正式开始讲解四个操作之前,先跑一条最基础的查询,看看目前表里有什么:

SELECT * FROM student\G;

在命令行客户端里,\G可以把每一行的结果显示成纵向排列,列多的时候特别清晰。我看到的结果是5行数据,id从1到5,每列都有值或为NULL,说明前期的建表和插入都没有问题。接下来就从查询开始,一步步把四大操作全部过一遍。

3. SELECT查询:最常用也最需要体系化理解的操作

查询是增删查改里用得最多的一个,也是变化最多的一个。我见过很多人写SQL只停留在SELECT * FROM 表名 WHERE 条件,一旦遇到排序、去重、分组、关联,就开始凭感觉拼语句,结果数据对不对心里完全没底。这里把查询按场景拆开讲。

3.1 基础查询与列控制

最原始的查询就是把整个表的数据拉出来看:

SELECT * FROM student;

*代表所有列,日常工作里其实不建议在正式环境这么用,因为字段多了之后网络传输开销大,而且视野会被无关数据干扰。更规范的写法是明确列出你需要的字段:

SELECT student_no, name, age FROM student;

这个习惯一开始就养成,后面写复杂查询时受益很明显。另外,查询时可以在列名后面加别名,让结果集中看:

SELECT name AS 姓名, age AS 年龄 FROM student;

别名的AS可以省略,写成SELECT name 姓名 FROM student也能跑,但我建议保留AS,阅读代码时更直观。

3.2 条件过滤:WHERE的完整用法

WHERE后面可以跟比较运算符、逻辑运算符、范围判断、模糊匹配等多种条件。这里列出几个最常见场景。

等值匹配:

SELECT * FROM student WHERE class_name = '计算机1班';

范围匹配,用IN:

SELECT * FROM student WHERE class_name IN ('计算机1班', '数据1班');

区间匹配,用BETWEEN ... AND ...:

SELECT * FROM student WHERE age BETWEEN 19 AND 20;

模糊匹配,用LIKE:

SELECT * FROM student WHERE name LIKE '张%';

%代表任意长度的任意字符,_代表单个任意字符。所以'张%'能匹配到“张三”“张伟”这样的名字,而'张_'只能匹配到“张三”这种姓张且名字只有一个字的人。

空值判断是很多人的知识盲区,划个重点:

SELECT * FROM student WHERE class_name IS NULL;

这里不能用class_name = NULL。原因很简单:MySQL里NULL表示“未知”,拿“未知”跟任何值做比较,结果都是“未知”,而WHERE只接受“真”条件,等于NULL永远不会命中。

组合条件用AND和OR:

SELECT * FROM student WHERE class_name = '计算机1班' AND age >= 20;

注意:当AND和OR同时出现时,AND优先级高于OR。如果条件复杂,建议每一次都用小括号明确逻辑分组,别让读代码的人猜意图。

3.3 排序:ORDER BY的细节

查询结果默认按照存储顺序返回,很多时候我们想要的是按照某个字段排序后的结果:

SELECT * FROM student ORDER BY score DESC;

DESC表示降序,ASC表示升序,升序是默认值。多字段排序的写法是:

SELECT * FROM student ORDER BY class_name ASC, score DESC;

这句话的意思是先按班级升序排,班级相同的再按成绩降序排。这个“从左到右依次生效”的规则要记住,顺序写反了,排序结果就完全不是你想要的样子。

3.4 去重:DISTINCT

想知道表里出现了哪些班级,直接查会有重复值:

SELECT DISTINCT class_name FROM student;

这里会过滤掉完全重复的行,结果里“计算机1班”只会出现一次。DISTINCT用在多列上时,是“多列组合去重”,不是分别去重。

3.5 限制行数:LIMIT

MySQL里限制查询返回行数用的是LIMIT offset, count,第一参数是偏移量,第二参数是返回行数:

SELECT * FROM student ORDER BY score DESC LIMIT 2;

这条语句返回成绩最高的前2条记录。分页场景下常用的写法是:

SELECT * FROM student ORDER BY id LIMIT 10, 5;

偏移量为10,取出5行,也就是“跳过前10行,从第11行开始取5行”。这个过程对应的是第2页每页5条数据的效果。

3.6 聚合统计与分组

统计总数、平均值、最大值、最小值,是查询里非常常见的需求。对应函数分别是COUNT、AVG、MAX、MIN,SUM用来求和:

SELECT COUNT(*) AS 总人数, AVG(score) AS 平均分, MAX(score) AS 最高分 FROM student;

按班级统计人数和平均分,需要配合GROUP BY:

SELECT class_name, COUNT(*) AS 人数, AVG(score) AS 平均分 FROM student GROUP BY class_name;

GROUP BY会把相同值的行分到同一组,然后对每一组做聚合计算。有一个后续过滤的坑要特别注意:分组之后的过滤条件不能用WHERE,要用HAVING。

查找平均分高于85分的班级:

SELECT class_name, AVG(score) AS avg_score FROM student GROUP BY class_name HAVING avg_score > 85;

简单记忆方式是:WHERE过滤的是分组前的原始行,HAVING过滤的是分组后的聚合结果。

3.7 关联查询:JOIN的基本姿势

数据规范化的结果就是不同信息分散在不同的表里。比如我们再建一张班级表,然后让学生表和班级表通过班级ID关联:

CREATE TABLE class ( id INT PRIMARY KEY AUTO_INCREMENT, class_name VARCHAR(50) UNIQUE NOT NULL ); INSERT INTO class (class_name) VALUES ('计算机1班'), ('软件2班'), ('数据1班'), ('网络1班');

最常用的内连接写法:

SELECT s.name, s.student_no, c.class_name FROM student s INNER JOIN class c ON s.class_name = c.class_name;

INNER JOIN只返回两边都能匹配上的记录。如果你的某个学生属于一个不存在的班级,那他在结果中不会出现。搞清楚JOIN的核心逻辑——ON后面是“关联条件”,WHERE后面是“过滤条件”——就不会在复杂SQL里迷路。

4. INSERT插入:从单行到批量,再到防重复插入

插入操作的语法本身很简单,核心变化在于“插入的数据来源”“插入的批量和去重策略”。

4.1 单行插入的两种写法

指定列名插入是日常开发中最常见的写法:

INSERT INTO student (student_no, name, gender, age, class_name, enroll_date, score) VALUES ('S1006', '周八', 'M', 22, '软件2班', '2022-09-01', 79.00);

省略列名则必须给所有非自增且非默认值的列提供数据:

INSERT INTO student VALUES (NULL, 'S1007', '吴九', 'F', 19, '数据1班', '2024-09-01', 90.00);

这里的NULL是给自增主键id用的,MySQL会自动生成实际的id值。省略列名的写法对表结构变化极其敏感,一旦列顺序调整就会报错或数据错位,不推荐在正式环境使用。

4.2 多条插入与性能优势

把多行数据放进一条VALUES里,逗号隔开:

INSERT INTO student (student_no, name, gender, age, class_name, enroll_date, score) VALUES ('S1008', '郑十', 'M', 20, '网络1班', '2023-09-01', 81.00), ('S1009', '陈十一', 'F', 19, '计算机1班', '2024-09-01', 87.50);

一次插入两行和分两次逐条插入,最终结果一样,但效率差别很大。每条INSERT都要经历完整的SQL解析、权限检查、存储引擎写入过程,多条插入减少了这些开销和网络往返。我自己测试过,万行级别的数据,用多条插入比逐条执行快一个数量级不止。

4.3 从现有表插入数据:INSERT INTO ... SELECT

需要从一张表筛选数据写入另一张表时,可以用INSERT INTO ... SELECT:

CREATE TABLE student_bak LIKE student; INSERT INTO student_bak (student_no, name, gender, age, class_name, enroll_date, score) SELECT student_no, name, gender, age, class_name, enroll_date, score FROM student WHERE score >= 85;

这条语句很实用,比如做数据归档、临时表过滤、表结构同步时,都不需要先把数据捞到应用层再逐条写入,直接在数据库内部完成搬运。

4.4 防重复插入:INSERT IGNORE与ON DUPLICATE KEY UPDATE

网上常见的需求是“这个学生已经存在就别报了,不存在才插入”。如果student_no有唯一约束,直接插入重复值会报错:

INSERT INTO student (student_no, name, gender, age, class_name, enroll_date, score) VALUES ('S1001', '张三', 'M', 20, '计算机1班', '2023-09-01', 88.50);

这里因为S1001已存在,MySQL会抛出Duplicate entry错误。两种处理方式:

第一种,忽略冲突,直接跳过:

INSERT IGNORE INTO student (student_no, name, gender, age, class_name, enroll_date, score) VALUES ('S1001', '张三', 'M', 20, '计算机1班', '2023-09-01', 88.50);

第二种,冲突时改为更新:

INSERT INTO student (student_no, name, gender, age, class_name, enroll_date, score) VALUES ('S1001', '张三', 'M', 22, '计算机1班', '2023-09-01', 91.00) ON DUPLICATE KEY UPDATE age = VALUES(age), score = VALUES(score);

这种写法在“同步数据”场景下非常常用,本质上是“存在就更新,不存在就插入”。需要提醒一点,触发冲突的前提是表中存在唯一约束或主键约束,没有约束的行重复数据不会被拦截。

5. UPDATE更新:精准定位,小范围修改

更新操作是把双刃剑,改对了效率很高,改错了代价极大。所以更新操作的核心不是“怎么写更新语句”,而是“怎么把范围限制得足够精准”。

5.1 更新单条记录

我通过学号定位到具体某个人,然后修改他的班级和成绩:

UPDATE student SET class_name = '数据1班', score = 93.00 WHERE student_no = 'S1002';

这里没必要用主键id,因为学号本身有唯一约束,也能精确定位。关键是WHERE条件返回的行数必须符合预期。对唯一字段做条件过滤时,无论用哪个唯一字段,结果都应该只有一行。

5.2 批量更新多条记录

把“计算机1班”所有学生的成绩统一加2分:

UPDATE student SET score = score + 2 WHERE class_name = '计算机1班';

注意这里不是把分数改成固定值,而是在原值基础上加2。很多初学者会写错成SET score = 92,如果原值是不同的,就全变成同一个数了,这是数据逻辑错误。

5.3 关联更新:UPDATE JOIN

当更新条件需要依赖另一张表的数据时,UPDATE JOIN很实用。假设我们需要把没有对应班级的学生,班级统一改为“未分配”:

UPDATE student s LEFT JOIN class c ON s.class_name = c.class_name SET s.class_name = '未分配' WHERE c.class_name IS NULL;

这里LEFT JOIN保证学生表所有行都保留,班级表匹配不上时c.class_name为NULL,然后WHERE只处理这些“没有对应班级”的学生。整个逻辑就是“把所有找不到班级的学生标记为未分配”。

注意:做关联更新之前,强烈建议先跑一遍等价的SELECT确认影响范围。比如上面的操作,可以先执行SELECT s.* FROM student s LEFT JOIN class c ON s.class_name = c.class_name WHERE c.class_name IS NULL;,看到结果符合预期,再改成UPDATE执行。

5.4 UPDATE的常见误操作与防护

不带WHERE的UPDATE会更新全表所有行。我早期那起事故就是这么发生的。现在我在命令行执行批量更新之前,一直保持一个习惯,先把WHERE子句写在最前面,再补SET部分。更稳妥的做法是使用SELECT先确认受影响行数。

MySQL客户端还支持启动参数--safe-updates,开启后,不带WHERE或LIMIT的UPDATE和DELETE会被拒绝执行。对新手来说,这个参数值得设为默认。

mysql -uroot -p --safe-updates

6. DELETE删除:清理数据的正确方式与安全底线

删除操作的危险系数最高,因为数据一旦被删,在没有备份的情况下基本无法恢复。

6.1 删除指定行

删除学号为S1008的学生:

DELETE FROM student WHERE student_no = 'S1008';

这一步影响行数应该是1。可以通过SELECT ROW_COUNT();查看上一条语句影响的行数,用于校验。

6.2 按条件批量删除

把成绩低于80分的学生批量删除:

DELETE FROM student WHERE score < 80;

执行前可以先查一下:

SELECT COUNT(*) FROM student WHERE score < 80;

确认数量符合预期,再执行删除。

6.3 DELETE与TRUNCATE的区别

想清空一张表时,有两个选择:

DELETE FROM student; TRUNCATE TABLE student;

两者都能让表里没数据,但机制完全不同。DELETE FROM student是一行一行按条件删除,会触发行级删除操作,自增主键的计数器不会重置;TRUNCATE TABLE student是直接重建表结构并清空数据,速度更快,自增计数器会重置为初始值。如果只是想清空测试数据并让id从1重新开始,TRUNCATE更合适;如果需要对删除过程做精细控制(比如配合事务回滚),则用DELETE。

提示:TRUNCATE操作无法通过WHERE条件限制范围,它会直接清空整张表,使用前必须确认自己选对了表名。

6.4 外键约束对DELETE的影响

如果表之间存在外键关系,删除被引用的数据会被外键约束拦截。比如某订单表中引用了用户表,直接删除用户表中被引用的用户,会报错。这时需要先处理关联表中的数据,或者设计外键时使用ON DELETE CASCADE让删除自动级联。级联删除虽然方便,但也容易造成大面积数据丢失,生产环境要谨慎评估。

6.5 删除操作的底线建议

备份先行。不管多简单的删除,我都建议先确认当前表数据已有备份。一个常用的快速备份方式是:

CREATE TABLE student_bak_20250101 AS SELECT * FROM student;

这样即使删错了,也能从备份表把数据捞回来。

事务保护。在MySQL的InnoDB引擎下,DELETE操作是支持事务回滚的。先开启事务再删除、确认无误后提交,是安全系数最高的玩法:

START TRANSACTION; DELETE FROM student WHERE score < 80; -- 查询确认结果 SELECT COUNT(*) FROM student WHERE score < 80; COMMIT;

如果发现结果不对,用ROLLBACK;代替COMMIT;瞬间回滚。

7. 一个完整实操案例:从零跑通增删查改全流程

到这里,语法已经全部过了一遍。接下来用一个具体场景把四类操作串起来,模拟真实业务中“初始化数据、查询统计、更新校正、清理冗余”的完整链路。

7.1 需求描述

模拟项目X里有一个简单的教务系统需求,需要维护学生信息,并完成以下任务:

  • 新增一批新生数据。
  • 查询计算机1班学生的名单和成绩。
  • 按班级统计各班的平均成绩。
  • 将数据1班的某名学生成绩修改为89.50。
  • 清理一批测试残留数据。

7.2 逐步执行过程

第一步,新增新生数据:

INSERT INTO student (student_no, name, gender, age, class_name, enroll_date, score) VALUES ('S1010', '刘十二', 'F', 18, '计算机1班', '2024-09-01', 0.00), ('S1011', '何十三', 'M', 19, '软件2班', '2024-09-01', 0.00);

新入学的学生还没有参加考试,所以成绩先存0.00,等之后成绩出来再更新。

第二步,查询计算机1班学生名单和成绩:

SELECT student_no, name, score FROM student WHERE class_name = '计算机1班' ORDER BY score DESC;

第三步,按班级统计平均成绩:

SELECT class_name, COUNT(*) AS 人数, AVG(score) AS 平均分 FROM student GROUP BY class_name ORDER BY 平均分 DESC;

第四步,更新单个学生成绩:

UPDATE student SET score = 89.50 WHERE student_no = 'S1010';

执行后再次查询该学生,确认数据变化。

第五步,清理测试残留数据,删除入学日期在2023年之前且成绩小于80的学生:

DELETE FROM student WHERE enroll_date < '2023-01-01' AND score < 80;

先查后删:

SELECT * FROM student WHERE enroll_date < '2023-01-01' AND score < 80;

确认只有王五这一条,再执行删除。

第六步,全表查看最终数据:

SELECT * FROM student ORDER BY class_name, score DESC;

通过这轮实操,可以完整看到一条数据从“插入”到“被查询、被更新、被删除”的全生命周期,这正是增删查改四类操作配合起来解决的业务问题。

8. 高频报错与排查技巧实录

最后分享几个我在日常使用和帮助别人排查时反复遇到的问题,每一条都给排查思路。

8.1 Duplicate entry for key ... 报错

出现在插入数据时,插入的值撞上了已有唯一约束或主键。排查思路是先用冲突的字段值反向查询:

SELECT * FROM student WHERE student_no = 'S1001';

如果确认这一行已经存在且有价值,改用ON DUPLICATE KEY UPDATE或INSERT IGNORE;如果这一行是无用数据,直接删除或换一个编号。

8.2 Unknown column 报错

SQL里写的字段名在表里不存在。先用DESC student;查看表结构,确认字段拼写和表名是否匹配。有时候是因为大小写问题,MySQL在Linux下对字段名区分大小写,而在Windows下通常不区分。

8.3 中文乱码

字符集不匹配导致。数据库、表、连接三层都要保持utf8mb4。连接时指定字符集避免乱码:

mysql -uroot -p --default-character-set=utf8mb4

建表时已经指定了DEFAULT CHARSET utf8mb4,连接也指定了,基本上能杜绝乱码问题。

8.4 修改/删除数据时提示影响行数为0

这不一定代表操作失败,更可能的原因是WHERE条件没有匹配到任何记录。先单独执行条件查询,确认数据是否存在。另一个常见原因是当前会话事务隔离级别下,数据被其他事务修改或锁定,后者会表现为操作卡住而不是影响行数为0。

8.5 误操作后如何恢复

如果没有开事务,且操作已经提交,最快的恢复途径是备份。所以我会在每次批量操作前做备份表。另一个技巧是利用binlog做时间点恢复,但配置相对复杂,不适合初学者在测试环境折腾。从实操角度说,养成“操作前备份、操作中确认、操作后验证”的习惯,才是避免误操作的根本。

8.6 一条自查清单

  • UPDATE/DELETE语句是否带了精确的WHERE条件?
  • 影响范围是否已通过SELECT或COUNT(*)预检?
  • 是否在事务中执行高风险语句?
  • 是否有备份措施兜底?
  • 字符集是否统一为utf8mb4?
  • 是否养成了给查询结果排序、限制返回行数的习惯?

照着这份清单养成习惯,事实上能避开大部分跟增删查改相关的“低级事故”。

9. 我的一点真实体会

数据库这东西,你越往后做越会发现,真正拉开开发者差距的不是会不会写某个高深的查询语句,而是处理基础操作时的“分寸感”:什么时候该加约束,批量操作前怎么预检,删除数据时如何让心里有底。增删查改就是这分寸感的载体。把这些基础能力磨扎实,后面再学索引、事务、优化,才有稳固的立足点。

最后分享一个小技巧:每次在命令行执行完一条影响数据结果的语句,养成用SELECT ROW_COUNT();确认一下影响行数的习惯。虽然简单,但能帮你尽早发现条件写错的问题,避免错误在数据里隐藏很久才暴露。如果你刚开始学,不妨把我上面示例里的每一条语句都亲手敲一遍,再换成自己的数据场景去变着花样尝试。基础的功夫越扎实,越不至于在关键时刻掉链子。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 7:24:49

复杂逻辑回归实现:从softmax多分类到多项式特征实战

做机器学习时间久了你会发现&#xff0c;逻辑回归这个算法&#xff0c;听起来是入门第一课&#xff0c;但真正把它用到复杂场景里&#xff0c;坑比想象中多得多。这次5-10节的主题"复杂逻辑回归实现"&#xff0c;讲的就是当基础逻辑回归解决不了问题时&#xff0c;我…

作者头像 李华
网站建设 2026/10/16 7:24:12

深入理解 kallsyms:内核符号表的原理、权限与调试实战

我第一次认真研究 kallsyms 内核符号表&#xff0c;不是在读内核源码的时候&#xff0c;而是在某个凌晨三点抓一个诡异崩溃现场的时候。设备打印出来的调用栈只有一串十六进制地址&#xff0c;函数名一个都没有&#xff0c;靠 System.map 对半天还对不齐&#xff0c;最后才想起…

作者头像 李华
网站建设 2026/10/16 7:23:39

WOA优化KELM参数:回归预测的智能调参实战

做回归预测最烦的一件事&#xff0c;就是大量时间花在“调参”上。核极限学习机&#xff08;KELM&#xff09;也一样&#xff0c;正则化系数C和核参数gamma定得好不好&#xff0c;直接决定模型是“欠拟合”还是“过拟合”。手动试参数试到怀疑人生&#xff0c;网格搜索又慢得让…

作者头像 李华
网站建设 2026/10/16 7:23:04

Notepad++排版实战:缩进、正则与插件的完整指南

1. 先搞明白&#xff1a;Notepad 排版到底在解决什么问题1.1 排版不等于美化提到 Notepad 排版&#xff0c;很多人第一反应是“不就是调一下自动换行、改改字号嘛”。这种理解不能说错&#xff0c;但太浅了。我最早也是这么想的&#xff0c;直到有次处理一份十几万行的配置文件…

作者头像 李华
网站建设 2026/10/16 7:22:12

边缘计算典型应用场景与项目落地避坑指南

这几年做项目&#xff0c;跟“边缘”这两个字打交道的频率越来越高。从最早只在工业自动化里听到这个概念&#xff0c;到现在连做门店数字化、做安防改造的客户都在问“能不能在设备端直接算&#xff0c;别什么都往云上送”。我自己的体会是&#xff0c;边缘计算早就不是停留在…

作者头像 李华