2.12 数据插入(INSERT INTO)
我刚入行时,以为数据分析师只需要SELECT查数据就够了。直到有一次,运营同事拿着一份Excel表格找到我:"这是618大促的临时订单数据,你帮我把这些数据导入数据库,我要做分析。"我愣住了------我只会查,不会插。后来我硬着头皮学了INSERT INTO,才发现原来往数据库里写数据并不难。
在电商数据分析工作中,你可能会遇到这些场景:
-
运营从第三方平台导出了一批线下订单,需要导入数据库与线上订单合并分析。
-
大促期间,需要将实时订单数据写入临时表,供监控看板使用。
-
数据清洗后,将结果写入新表,供后续报表使用。
-
定期将历史数据归档到备份表。
这一章我会带你彻底搞懂INSERT INTO语句的所有用法:全字段插入、指定字段插入、单行插入、批量插入,甚至将查询结果直接插入另一张表。学完之后,你不仅能查数据,还能自己建表、导数据,成为一个更全能的分析师。
学习前准备:
-
已完成MySQL安装(参考系列前几章)
-
已安装DBeaver或Navicat
-
准备一个练习数据库,比如
insert_demo
学习前环境准备(快速回顾)
如果你已经完成了前面的教程,可以跳过本节。否则按以下步骤快速搭建练习环境。
步骤1:确保MySQL服务已启动。
步骤2:创建练习数据库。
sql
CREATE DATABASE insert_demo
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE insert_demo;
步骤3:创建一张订单表作为演示。
sql
CREATE TABLE orders (
order_id VARCHAR(50) PRIMARY KEY COMMENT '订单号',
user_id INT NOT NULL COMMENT '用户ID',
amount DECIMAL(10,2) NOT NULL COMMENT '金额',
order_status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1待支付,2已支付,3已取消,4已完成',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '下单时间'
);
INSERT INTO基础认知
INSERT INTO是SQL中用于向表中添加新行的语句。它是DML(数据操纵语言)的一部分。数据分析师虽然以查询为主,但以下情况必须用到插入:
-
将外部数据(CSV、Excel)导入数据库暂存。
-
创建临时表用于复杂分析。
-
数据清洗后将结果写入新表。
-
将历史数据归档。
基本语法格式:
sql
INSERT INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...);
我的踩坑经历 :第一次用
INSERT INTO时,我把列名写错了顺序,导致金额插到了用户ID字段里,变成了一堆奇怪的数字。从那以后,我养成习惯:指定列名时,顺序和数据类型一定要与VALUES一一对应。
全字段插入与指定字段插入
4.1 全字段插入(省略列名)
如果为表中所有列 提供值,可以省略列名,直接写VALUES。值的顺序必须与表定义时的列顺序完全一致。
sql
INSERT INTO orders VALUES ('ORD001', 1001, 299.00, 2, '2025-06-01 10:00:00');
分步操作:
-
确认表结构:
DESC orders;查看列顺序。 -
按顺序提供值:字符串用单引号,数字直接写,日期时间用
'YYYY-MM-DD HH:MM:SS'。 -
执行语句,成功插入一行。
预期结果 :Query OK, 1 row affected。
注意 :如果表有自增列或默认值列,全字段插入时也需要显式提供值(可以用DEFAULT关键字)。
4.2 指定字段插入(推荐)
只给部分列赋值,其他列使用默认值或允许NULL。必须明确列出要插入的列名。
sql
INSERT INTO orders (order_id, user_id, amount, order_status)
VALUES ('ORD002', 1002, 189.00, 1);
这里create_time列有默认值CURRENT_TIMESTAMP,会自动填充。
分步操作:
-
写
INSERT INTO orders (列名列表)。 -
VALUES中值数量与列名列表数量一致。 -
执行,查看结果:
SELECT * FROM orders;
预期结果 :新增一行,create_time自动为当前时间。
4.3 电商场景实操
运营需要将线下手工订单录入系统,只有订单号、用户ID和金额,状态默认为"已支付"(状态码2)。
sql
INSERT INTO orders (order_id, user_id, amount, order_status)
VALUES ('OFFLINE001', 8888, 599.00, 2);
实操避坑提醒 :全字段插入虽然省事,但表结构可能变化(如新增字段),导致语句报错或数据错位。生产环境推荐使用指定字段插入,明确列出列名,可读性更好,也更安全。
单行插入与批量插入
5.1 单行插入
一次只插入一行数据,就是前面讲的基本语法。
sql
INSERT INTO orders (order_id, user_id, amount, order_status)
VALUES ('ORD003', 1003, 399.00, 2);
5.2 批量插入(一次插入多行)
在VALUES后用逗号分隔多组括号,每组代表一行。效率远高于逐条插入,尤其适合大数据量导入。
sql
INSERT INTO orders (order_id, user_id, amount, order_status) VALUES
('ORD004', 1004, 129.00, 2),
('ORD005', 1005, 499.00, 1),
('ORD006', 1006, 59.00, 4);
分步操作:
-
准备多行数据,每组值用括号包围,逗号分隔。
-
执行语句,返回
Query OK, 3 rows affected。 -
用
SELECT COUNT(*) FROM orders验证行数增加了3。
5.3 电商场景实操:大促订单数据批量入库
618大促期间,每小时会生成一批订单数据,需要批量插入到数据库的临时表中。
sql
INSERT INTO orders_temp (order_id, user_id, amount, order_status, create_time) VALUES
('H202506011001', 1001, 299.00, 2, '2025-06-01 10:00:00'),
('H202506011002', 1002, 189.00, 2, '2025-06-01 10:01:00'),
('H202506011003', 1003, 599.00, 1, '2025-06-01 10:02:00');
注意 :批量插入的数据量建议一次不超过1000行,否则可能超过MySQL的max_allowed_packet限制。如果数据量很大,可以分批插入。
我的踩坑经历 :有一次我试图一次性插入10万行数据,结果MySQL报错
Packet too large。后来我把数据分成每5000行一批,用脚本循环插入,顺利完成。批量插入虽快,也要注意单次数据包大小限制。
查询结果插入(INSERT INTO ... SELECT)
6.1 核心定义
将一条SELECT查询的结果直接插入到目标表中。这是数据同步、备份、临时表创建的常用技巧。
语法:
sql
INSERT INTO 目标表 (列1, 列2, ...)
SELECT 列1, 列2, ...
FROM 源表
WHERE 条件;
6.2 电商场景实操:跨表同步
场景一:创建历史订单备份表
将2024年之前的订单移动到备份表。
sql
-- 先创建结构相同的备份表
CREATE TABLE orders_archive LIKE orders;
-- 将旧数据插入备份表
INSERT INTO orders_archive
SELECT * FROM orders
WHERE create_time < '2024-01-01';
场景二:将退款订单单独存入退款表
假设有退款表refund_orders,结构与订单表类似,需要将已退款的订单同步过去。
sql
-- 先创建退款表(简略版)
CREATE TABLE refund_orders (
order_id VARCHAR(50) PRIMARY KEY,
user_id INT,
amount DECIMAL(10,2),
refund_time DATETIME
);
-- 从订单表查询已取消的订单(假设取消即退款)
INSERT INTO refund_orders (order_id, user_id, amount, refund_time)
SELECT order_id, user_id, amount, NOW()
FROM orders
WHERE order_status = 3;
分步操作:
-
确认源表有需要的数据。
-
确认目标表已存在,且列数据类型兼容。
-
执行
INSERT INTO ... SELECT。 -
验证目标表中的行数。
预期结果:所有符合条件的订单被复制到退款表。
6.3 避坑提醒
-
目标表必须提前存在,不会自动创建。
-
列的数量、顺序、数据类型必须匹配。
-
如果目标表有自增主键,
SELECT中可以不包含该列,让数据库自动生成。 -
如果目标表有唯一约束或主键,要避免插入重复数据。
我的踩坑经历 :有一次我用
INSERT INTO ... SELECT同步数据,忘记目标表已经有一些数据了,结果插入了重复主键,语句报错。后来改用INSERT IGNORE或ON DUPLICATE KEY UPDATE来避免冲突。批量插入前最好先检查目标表是否为空,或使用去重逻辑。
综合实操案例:618大促订单数据批量入库与退款数据同步
7.1 案例背景
某服饰类目天猫店铺在618大促期间,需要完成以下任务:
-
将运营提供的线下订单CSV数据(模拟)批量插入到
orders表。 -
从
orders表中筛选出已退款的订单(状态=3),同步到refund_orders表。
7.2 准备工作
创建订单表(如果还没有)和退款表。
sql
USE insert_demo;
CREATE TABLE IF NOT EXISTS orders (
order_id VARCHAR(50) PRIMARY KEY,
user_id INT NOT NULL,
amount DECIMAL(10,2) NOT NULL,
order_status TINYINT NOT NULL DEFAULT 1,
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS refund_orders (
refund_id INT PRIMARY KEY AUTO_INCREMENT,
order_id VARCHAR(50) NOT NULL,
user_id INT,
amount DECIMAL(10,2),
refund_time DATETIME,
FOREIGN KEY (order_id) REFERENCES orders(order_id)
);
7.3 分步操作
步骤1:批量插入线下订单数据(模拟CSV导入)
假设有5条线下订单:
sql
INSERT INTO orders (order_id, user_id, amount, order_status, create_time) VALUES
('OFF001', 2001, 399.00, 2, '2025-06-01 09:00:00'),
('OFF002', 2002, 259.00, 2, '2025-06-01 10:30:00'),
('OFF003', 2003, 699.00, 1, '2025-06-01 11:15:00'),
('OFF004', 2004, 129.00, 3, '2025-06-01 12:00:00'),
('OFF005', 2005, 499.00, 2, '2025-06-01 14:20:00');
步骤2:验证插入结果
sql
SELECT COUNT(*) FROM orders; -- 应该看到新增5行
步骤3:将已退款订单同步到退款表
sql
INSERT INTO refund_orders (order_id, user_id, amount, refund_time)
SELECT order_id, user_id, amount, NOW()
FROM orders
WHERE order_status = 3;
步骤4:验证退款表数据
sql
SELECT * FROM refund_orders;
预期结果 :退款表中有一条记录,对应OFF004订单。
步骤5:补充大促实时订单数据(批量插入)
模拟从实时系统导出的一批订单:
sql
INSERT INTO orders (order_id, user_id, amount, order_status, create_time) VALUES
('ONLINE001', 3001, 199.00, 2, '2025-06-01 15:00:00'),
('ONLINE002', 3002, 899.00, 2, '2025-06-01 15:05:00'),
('ONLINE003', 3003, 49.00, 4, '2025-06-01 15:10:00');
7.4 结果验证与合规提示
-
所有数据插入成功,无主键冲突。
-
退款表正确同步了退款订单。
📌 电商数据合规提示 :在插入订单数据时,如果包含用户手机号、地址等敏感信息,必须先脱敏。本案例中订单表只有
user_id(内部ID),不涉及个人敏感字段。生产环境中,INSERT INTO ... SELECT同步数据时,注意不要复制敏感字段。
本章踩坑清单与合规总结
8.1 新手常见踩坑
| 错误 | 原因 | 正确做法 |
|---|---|---|
| 全字段插入时顺序错误 | 没查看表结构 | 用指定字段插入,或DESC确认顺序 |
| 批量插入时一行写错导致全部失败 | 批量插入是原子操作 | 先少量测试,或用INSERT IGNORE |
| 插入NULL到NOT NULL列 | 未提供值且无默认值 | 提供有效值或修改表结构 |
INSERT INTO ... SELECT目标表不存在 |
没提前建表 | 先CREATE TABLE ... LIKE |
| 插入重复主键 | 未检查唯一性 | 用INSERT IGNORE或ON DUPLICATE KEY UPDATE |
8.2 电商数据合规红线
-
插入数据时不要包含明文敏感信息:如手机号、身份证号,必须加密或脱敏。
-
批量导入外部数据需审批:来自第三方的数据可能存在合规风险(如爬虫数据),导入前需法务确认。
-
数据备份:在插入大量数据前,先备份目标表,防止误操作导致数据丢失。
-
使用事务 :如果插入操作涉及多表,应使用
START TRANSACTION和COMMIT,保证一致性。
结语
INSERT INTO是SQL中最基本的写入操作,但掌握它能让你的数据分析工作流更加完整。无论是导入外部数据、创建临时表,还是做数据归档,你都游刃有余。
有问题的评论区留言,我看到会回复。