INSERT、UPDATE 和 DELETE
前面的课都只是查数据,表本身一点没变。这一课开始改数据:加一行、改几格、删几行。
这一页每段代码都从一份新的网店数据开始,前一段改的不会留到下一段,放心改。改完在同一段里再 SELECT 一次,就能看到改成了什么样。
INSERT:加一行
网店来了一位新客户。INSERT INTO 表 (列, 列, …) VALUES (值, 值, …) 把一行放进表里,值和列一个对一个:
1INSERT INTO customers (id, name, city, joined, email)2VALUES (11, '何佳', '深圳', '2025-10-28', '[email protected]');3 4SELECT * FROM customers WHERE id >= 10;
改数据的语句没有结果表,页面上显示 Query OK,影响了 1 行:成功了,改动了 1 行。后面的 SELECT 查出新客户已经在表里了。
一次可以插好几行,每行一对括号,中间用逗号隔开:
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;
| id | name | category | price | stock |
|---|---|---|---|---|
| 11 | 便利贴 | 文具 | 3.50 | 150 |
| 12 | 保温杯 | 厨房 | 29.00 | 30 |
没写的列
列名可以只写一部分。没写到的列,值是 NULL(建表时规定了默认值的除外,第 19 课讲):
1INSERT INTO customers (id, name)2VALUES (11, '何佳');3 4SELECT * FROM customers WHERE id = 11;
| id | name | city | joined | |
|---|---|---|---|---|
| 11 | 何佳 | NULL | NULL | NULL |
小技巧: 列名其实可以不写,INSERT INTO customers VALUES (…) 按表里列的顺序填。可这样一旦表多了一列,或者你记错了顺序,就会填错地方。写上列名更稳。
插不进去的时候
表有自己的规矩。id 是主键,每一行都不能一样。3 号商品已经有了,再插一个 3 号:
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 块:
1UPDATE products2SET price = 5.003WHERE id = 1;4 5SELECT id, name, price FROM products WHERE id = 1;
| id | name | price |
|---|---|---|
| 1 | 笔记本 | 5.00 |
新值可以用原来的值来算,一次也可以改好几列,用逗号隔开。文具到货了,每样加 50 件库存,同时打九五折:
1UPDATE products2SET stock = stock + 50,3 price = price * 0.954WHERE category = '文具';5 6SELECT name, price, stock FROM products WHERE category = '文具';
| name | price | stock |
|---|---|---|
| 笔记本 | 4.28 | 170 |
| 中性笔(10 支) | 5.70 | 130 |
price * 0.95 算出来是 4.275,可 price 这一列只留两位小数,存进去就成了 4.28。
页面上会显示改动了几行?
1UPDATE products2SET stock = stock - 13WHERE category = '数码';
WHERE 留下的行才会改。数码类有 4 件商品(耳机、台灯、数据线、手机壳),所以改了 4 行。
DELETE:删数据
DELETE FROM 表 WHERE 条件 删掉满足条件的行。台灯没有库存、也从没卖出过,把它下架:
1DELETE FROM products2WHERE stock = 0;3 4SELECT id, name, stock FROM products;
| id | name | stock |
|---|---|---|
| 1 | 笔记本 | 120 |
| 2 | 中性笔(10 支) | 80 |
| 3 | 双肩包 | 15 |
| 4 | 水杯 | 40 |
| 5 | 耳机 | 10 |
| 7 | 数据线 | 200 |
| 8 | 咖啡杯 | 60 |
| 9 | 手机壳 | 35 |
| 10 | 帆布袋 | 25 |
可要是想删的行还被别的表用着,数据库不让删。1 号商品笔记本出现在好几个订单的明细里:
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 元:
1UPDATE products2SET price = 0;3 4SELECT name, price FROM products;
| name | price |
|---|---|
| 笔记本 | 0.00 |
| 中性笔(10 支) | 0.00 |
| 双肩包 | 0.00 |
| 水杯 | 0.00 |
| 耳机 | 0.00 |
| 台灯 | 0.00 |
| 数据线 | 0.00 |
| 咖啡杯 | 0.00 |
| 手机壳 | 0.00 |
| 帆布袋 | 0.00 |
影响了 10 行:整张表的价格全成了 0。DELETE FROM products; 也一样,会把整张表清空。真的数据库里,这一下是撤不回来的(除非用第 20 课的事务)。
先 SELECT,再改
一个好习惯:改之前,先用同样的 WHERE 写一条 SELECT,看看会碰到哪几行。没问题了,再把 SELECT … FROM 换成 UPDATE … SET 或 DELETE FROM:
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;
| id | status |
|---|---|
| 9 | 待发货 |
| id | status |
|---|---|
| 1 | 已发货 |
| 3 | 已发货 |
| 9 | 已发货 |
第一条查出只有 9 号订单,改的也就只是它。
练一练
写好代码,点检查。提示随便看,实在想不出来再看答案。检查的是最后一个结果表,所以改完要再 SELECT 一次。
新客户
✓把新客户插进 customers:编号 11,名字「何佳」,城市「深圳」,注册日期 2025-10-30,没有邮箱。然后查出编号 9 及以后客户的 id、name、city、email,按 id 排。
| id | name | city | |
|---|---|---|---|
| 9 | 吴昊 | 成都 | NULL |
| 10 | 郑雪 | 杭州 | [email protected] |
| 11 | 何佳 | 深圳 | NULL |
1SELECT id, name, city, email2FROM customers3WHERE id >= 94ORDER BY id;
厨房打折
✓厨房类的商品全部打九折(价格乘 0.9)。然后查出厨房类商品的 name 和 price,按 id 排。
| name | price |
|---|---|
| 水杯 | 10.80 |
| 咖啡杯 | 8.91 |
1SELECT name, price2FROM products3WHERE category = '厨房'4ORDER BY id;
删掉取消的订单
✓4 号订单已经取消了,要把它彻底删掉。下面的代码报错了:先删掉它在 order_items 里的明细,再删订单。最后查出 4 号客户的订单 id 和 status,按 id 排。
| id | status |
|---|---|
| 12 | 待发货 |
1DELETE FROM orders2WHERE id = 4;3 4SELECT id, status5FROM orders6WHERE customer_id = 47ORDER BY id;
这一课学会了
INSERT INTO 表 (列, …) VALUES (…), (…);插入一行或几行;没写的列是NULL。UPDATE 表 SET 列 = 值, 列 = 值 WHERE …;修改;新值可以用原来的值算。DELETE FROM 表 WHERE …;删除;还被别的表指着的行删不了(ERROR 1451)。- 不写
WHERE就是改(删)所有行。 - 改之前先用同样的
WHERE写一条SELECT看一眼;改完再SELECT看结果。 - 主键重复是
ERROR 1062,NOT NULL的列写空值是ERROR 1048。