SQL INSERT INTO:向表中添加行
第 8.1 课 · 阅读时间:约 7 分钟 · 练习题 ↓
SQL INSERT INTO 语句向表中添加新行。在本课中,你将学习 INSERT 的语法、为什么应该始终列出列名、如何一次插入多行、如何用 INSERT INTO ... SELECT 复制数据,以及 NULL、DEFAULT 和自增列是如何填充的。
到目前为止,本课程中的每个查询都是用 SELECT 读取数据。从本模块开始,你将开始修改数据。INSERT、UPDATE 和 DELETE 构成了数据操作语言(DML);其中 INSERT 用于创建新行。
SQLtest 上的示例数据库是只读的,因此在那里执行这些语句会返回权限错误。示例使用 Sakila 模式来展示语法以及真实数据库会强制执行的规则。
INSERT 语法
带列列表(推荐)
INSERT INTO table_name (column1, column2, column3)
VALUES (value1, value2, value3);
值与列按位置对应:第一个值进入列出的第一列,依此类推。没有列出的列会得到默认值或 NULL。
不带列列表
INSERT INTO table_name
VALUES (value1, value2, value3, ...);
这种写法必须为每一列提供值,并且顺序要与表中定义列的顺序一致。如果以后有人添加了一列,这条语句就会出错,更糟的是,会把值写入错误的列。在需要保存和重复使用的代码中,请始终列出列名。
插入一行
INSERT INTO actor (first_name, last_name)
VALUES ('JOHNNY', 'DEPP');
结果:新增一位演员。actor_id 自动填充(自增),last_update 从默认值中获得当前时间。
值的规则与 WHERE 中相同:文本和日期用单引号括起来,数字不加引号。
必填列
定义为 NOT NULL 且没有默认值的列必须提供值。在 Sakila 中,customer.create_date 就是这样的列:
-- 错误:Field 'create_date' doesn't have a default value
INSERT INTO customer (store_id, first_name, last_name, email, address_id)
VALUES (1, 'ALICE', 'JOHNSON', 'alice.j@example.com', 5);
-- 正确:必填列有值
INSERT INTO customer (store_id, first_name, last_name, email, address_id, create_date)
VALUES (1, 'ALICE', 'JOHNSON', 'alice.j@example.com', 5, NOW());
结果:1 号门店新增一位客户。customer_id 自动生成,active 得到默认值 1。
值还必须满足外键约束:store_id = 1 和 address_id = 5 必须存在于 store 和 address 表中,否则数据库会拒绝这一行。
插入多行
用逗号分隔的多个值列表可以在一条语句中插入多行:
INSERT INTO actor (first_name, last_name)
VALUES ('TOM', 'HANKS'),
('MERYL', 'STREEP'),
('LEONARDO', 'DICAPRIO');
结果:新增三位演员。
一条多行语句比多条单行语句快得多:数据库只解析一次,并一次性写入更改。这是批量加载数据的标准方式。
NULL 和 DEFAULT 值
NULL 向允许为空的列写入“没有值”:
INSERT INTO customer (store_id, first_name, last_name, email, address_id, create_date)
VALUES (1, 'BOB', 'SMITH', NULL, 5, NOW());
结果:一位没有电子邮件地址的客户。
省略某一列会用它的默认值填充;如果没有默认值,则为 NULL。
DEFAULT 显式请求默认值,在列出所有列时很方便:
INSERT INTO actor (actor_id, first_name, last_name, last_update)
VALUES (DEFAULT, 'CATE', 'BLANCHETT', DEFAULT);
结果:actor_id 得到下一个自增编号,last_update 得到当前时间。
INSERT INTO ... SELECT
INSERT 也可以不用 VALUES,而是从查询中获取行。表之间复制数据、归档数据或向报表表加载数据时都会这样做:
INSERT INTO target_table (column1, column2, column3)
SELECT source_column1, source_column2, source_column3
FROM source_table
WHERE condition;
SELECT 列表可以组合列、计算结果和常量。例如,如果存在 customer_archive 表,就可以把非活跃客户复制进去:
INSERT INTO customer_archive (customer_id, full_name, archived_at, status_note)
SELECT customer_id,
CONCAT(first_name, ' ', last_name),
CURRENT_DATE,
'Auto-archived'
FROM customer
WHERE active = 0;
结果:15 行,每位非活跃客户一行,包含全名、当天日期和固定的备注。
SELECT 中列的数量和顺序必须与 INSERT 的列列表一致。列名不必相同,但位置必须对应。
常见的 INSERT 错误
| 错误 | 原因 |
|---|---|
| Column count doesn't match value count | 值列表与列列表的长度不同 |
| Field '…' doesn't have a default value | 省略了没有默认值的 NOT NULL 列 |
| Duplicate entry '…' for key 'PRIMARY' | 该键值已经存在 |
| Cannot add or update a child row: a foreign key constraint fails | 被引用的行不存在 |
| Incorrect … value | 值与列的数据类型不匹配 |
要点:
INSERT INTO table (columns) VALUES (values)添加一行;值按位置与列对应。- 始终列出列名:这样语句才能在表结构变化后继续正确工作。
- 没有默认值的
NOT NULL列必须提供值;外键必须指向已存在的行。 - 一条语句可以插入多行:
VALUES (...), (...), (...)。 INSERT INTO ... SELECT插入查询的结果。- 省略的列得到默认值或
NULL;DEFAULT关键字显式请求默认值。
常见问题
如何在 SQL 中插入多行?
在 VALUES 后列出多组值,用逗号分隔:INSERT INTO actor (first_name, last_name) VALUES ('TOM', 'HANKS'), ('MERYL', 'STREEP');。这在 MySQL、MariaDB、PostgreSQL、SQL Server 和 SQLite 中都适用。
如何把行从一张表复制到另一张表?
使用 INSERT INTO target (columns) SELECT columns FROM source WHERE condition;。SELECT 返回的列数和顺序必须与目标表的列列表一致。
INSERT 中没有列出的列会怎样?
它们会得到默认值。自增键会得到下一个编号。如果某列没有默认值,它会得到 NULL;如果该列是 NOT NULL,语句就会失败。