Kodewick
第 18 课,共 21 课目录

INSERT、UPDATE 和 DELETE

第 18 课,共 21 课 · 第 5 部分 · 改数据和建表 · 约 15 分钟

前面的课都只是查数据,表本身一点没变。这一课开始改数据:加一行、改几格、删几行。

这一页每段代码都从一份新的网店数据开始,前一段改的不会留到下一段,放心改。改完在同一段里再 SELECT 一次,就能看到改成了什么样。

INSERT:加一行

网店来了一位新客户。INSERT INTO 表 (列, 列, …) VALUES (值, 值, …) 把一行放进表里,值和列一个对一个:

main.sql
1INSERT INTO customers (id, name, city, joined, email)2VALUES (11, '何佳', '深圳', '2025-10-28', '[email protected]');3 4SELECT * FROM customers WHERE id >= 10;
输出
第 1 行的语句
Query OK,影响了 1 行
第 4 行的语句
idnamecityjoinedemail
10郑雪杭州2025-09-14[email protected]
11何佳深圳2025-10-28[email protected]
2 行

改数据的语句没有结果表,页面上显示 Query OK,影响了 1 行:成功了,改动了 1 行。后面的 SELECT 查出新客户已经在表里了。

一次可以插好几行,每行一对括号,中间用逗号隔开:

main.sql
1INSERT INTO products (id, name, category, price, stock)2VALUES (11, '便利贴', '文具', 3.50, 150),3    (12, '保温杯', '厨房', 29.00, 30);4 5SELECT * FROM products WHERE id > 10;
输出
第 1 行的语句
Query OK,影响了 2 行 · Records: 2 Duplicates: 0 Warnings: 0
第 5 行的语句
idnamecategorypricestock
11便利贴文具3.50150
12保温杯厨房29.0030
2 行

没写的列

列名可以只写一部分。没写到的列,值是 NULL(建表时规定了默认值的除外,第 19 课讲):

main.sql
1INSERT INTO customers (id, name)2VALUES (11, '何佳');3 4SELECT * FROM customers WHERE id = 11;
输出
第 1 行的语句
Query OK,影响了 1 行
第 4 行的语句
idnamecityjoinedemail
11何佳NULLNULLNULL
1 行

小技巧: 列名其实可以不写,INSERT INTO customers VALUES (…) 按表里列的顺序填。可这样一旦表多了一列,或者你记错了顺序,就会填错地方。写上列名更稳。

插不进去的时候

表有自己的规矩。id 是主键,每一行都不能一样。3 号商品已经有了,再插一个 3 号:

main.sql
1INSERT INTO products (id, name, category, price, stock)2VALUES (3, '雨伞', '箱包', 35.00, 20);
输出
ERROR 1062 (23000): Duplicate entry '3' for key 'products.PRIMARY'

「3」已经有了:主键(或 UNIQUE 的列)不能重复。

ERROR 1062 说 3 这个值重复了。同样,name 这一列规定了不能是空值(NOT NULL),往里写 NULL 会得到 ERROR 1048。出错的语句一行都不会插进去。这些规矩是建表时定的,第 19 课自己建表时再细讲。

UPDATE:改数据

UPDATE 表 SET 列 = 新值 WHERE 条件 把满足条件的行改掉。笔记本涨价到 5 块:

main.sql
1UPDATE products2SET price = 5.003WHERE id = 1;4 5SELECT id, name, price FROM products WHERE id = 1;
输出
第 1 行的语句
Query OK,影响了 1 行 · Rows matched: 1 Changed: 1 Warnings: 0
第 5 行的语句
idnameprice
1笔记本5.00
1 行

新值可以用原来的值来算,一次也可以改好几列,用逗号隔开。文具到货了,每样加 50 件库存,同时打九五折:

main.sql
1UPDATE products2SET stock = stock + 50,3    price = price * 0.954WHERE category = '文具';5 6SELECT name, price, stock FROM products WHERE category = '文具';
输出
第 1 行的语句
Query OK,影响了 2 行 · Rows matched: 2 Changed: 2 Warnings: 0
第 6 行的语句
namepricestock
笔记本4.28170
中性笔(10 支)5.70130
2 行

price * 0.95 算出来是 4.275,可 price 这一列只留两位小数,存进去就成了 4.28。

先猜一猜

页面上会显示改动了几行?

1UPDATE products2SET stock = stock - 13WHERE category = '数码';

DELETE:删数据

DELETE FROM 表 WHERE 条件 删掉满足条件的行。台灯没有库存、也从没卖出过,把它下架:

main.sql
1DELETE FROM products2WHERE stock = 0;3 4SELECT id, name, stock FROM products;
输出
第 1 行的语句
Query OK,影响了 1 行
第 4 行的语句
idnamestock
1笔记本120
2中性笔(10 支)80
3双肩包15
4水杯40
5耳机10
7数据线200
8咖啡杯60
9手机壳35
10帆布袋25
9 行

可要是想删的行还被别的表用着,数据库不让删。1 号商品笔记本出现在好几个订单的明细里:

main.sql
1DELETE FROM products2WHERE id = 1;
输出
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`town`.`order_items`, CONSTRAINT `order_items_ibfk_2` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`))

表「order_items」里还有行通过外键指向这一行,不能删掉或改它的键。先处理「order_items」里的那些行,或者建外键时写 ON DELETE CASCADE。

ERROR 1451:order_items 里还有行指向它,删了那些订单明细就说不清买的是什么了。这叫外键,第 19 课讲。要删,得先删掉指向它的那些行。

忘了 WHERE

UPDATE 和 DELETE 的 WHERE 可以不写,不写的意思是「所有行」。本来只想把一件商品改成 0 元:

main.sql
1UPDATE products2SET price = 0;3 4SELECT name, price FROM products;
输出
第 1 行的语句
Query OK,影响了 10 行 · Rows matched: 10 Changed: 10 Warnings: 0
第 4 行的语句
nameprice
笔记本0.00
中性笔(10 支)0.00
双肩包0.00
水杯0.00
耳机0.00
台灯0.00
数据线0.00
咖啡杯0.00
手机壳0.00
帆布袋0.00
10 行

影响了 10 行:整张表的价格全成了 0。DELETE FROM products; 也一样,会把整张表清空。真的数据库里,这一下是撤不回来的(除非用第 20 课的事务)。

先 SELECT,再改

一个好习惯:改之前,先用同样的 WHERE 写一条 SELECT,看看会碰到哪几行。没问题了,再把 SELECT … FROM 换成 UPDATE … SET 或 DELETE FROM:

main.sql
1SELECT id, status2FROM orders3WHERE customer_id = 1 AND status = '待发货';4 5UPDATE orders6SET status = '已发货'7WHERE customer_id = 1 AND status = '待发货';8 9SELECT id, status FROM orders WHERE customer_id = 1;
输出
第 1 行的语句
idstatus
9待发货
1 行
第 5 行的语句
Query OK,影响了 1 行 · Rows matched: 1 Changed: 1 Warnings: 0
第 9 行的语句
idstatus
1已发货
3已发货
9已发货
3 行

第一条查出只有 9 号订单,改的也就只是它。

练一练

写好代码,点检查。提示随便看,实在想不出来再看答案。检查的是最后一个结果表,所以改完要再 SELECT 一次。

练习 1

新客户

把新客户插进 customers:编号 11,名字「何佳」,城市「深圳」,注册日期 2025-10-30,没有邮箱。然后查出编号 9 及以后客户的 id、name、city、email,按 id 排。

要显示
idnamecityemail
9吴昊成都NULL
10郑雪杭州[email protected]
11何佳深圳NULL
3 行
exercise1.sql
1SELECT id, name, city, email2FROM customers3WHERE id >= 94ORDER BY id;
输出
点「运行」或按 Ctrl+Enter
练习 2

厨房打折

厨房类的商品全部打九折(价格乘 0.9)。然后查出厨房类商品的 name 和 price,按 id 排。

要显示
nameprice
水杯10.80
咖啡杯8.91
2 行
exercise2.sql
1SELECT name, price2FROM products3WHERE category = '厨房'4ORDER BY id;
输出
点「运行」或按 Ctrl+Enter
练习 3

删掉取消的订单

4 号订单已经取消了,要把它彻底删掉。下面的代码报错了:先删掉它在 order_items 里的明细,再删订单。最后查出 4 号客户的订单 id 和 status,按 id 排。

要显示
idstatus
12待发货
1 行
exercise3.sql
1DELETE FROM orders2WHERE id = 4;3 4SELECT id, status5FROM orders6WHERE customer_id = 47ORDER BY id;
输出
点「运行」或按 Ctrl+Enter

这一课学会了

  • INSERT INTO 表 (列, …) VALUES (…), (…); 插入一行或几行;没写的列是 NULL。
  • UPDATE 表 SET 列 = 值, 列 = 值 WHERE …; 修改;新值可以用原来的值算。
  • DELETE FROM 表 WHERE …; 删除;还被别的表指着的行删不了(ERROR 1451)。
  • 不写 WHERE 就是改(删)所有行。
  • 改之前先用同样的 WHERE 写一条 SELECT 看一眼;改完再 SELECT 看结果。
  • 主键重复是 ERROR 1062,NOT NULL 的列写空值是 ERROR 1048。