跳到主要内容

CSV 转 SQL 实战:从表格生成 INSERT 语句批量导入数据库

把带表头的 CSV 转成可执行的 CREATE TABLE 和 INSERT 语句,讲清表名列名映射、类型推断、单引号转义和批量导入,附一段真实输入输出例子。

发布于 作者 李雷
#CSV 转 SQL #数据库导入 #INSERT 语句 #数据迁移

CSV 转 SQL 实战:从表格生成 INSERT 语句批量导入数据库

手头有一份 CSV,要把它灌进数据库,这是开发里几乎每周都会撞到的活。表格可能来自运营导出的 Google Sheets,可能是同事邮件发来的注册名单,也可能是从老库 dump 出来准备搬家的数据。要让这些数据进库,本质上就是把每一行变成一条 INSERT 语句,再配一份能装下它们的表结构。

听起来简单,真动手会发现坑不少:列名里有空格、值里夹着单引号、空单元格到底算 NULL 还是空字符串、邮编 02134 被当成数字丢了前导零。下面把这条路从头到尾走一遍。

INSERT INTO 语法到底长什么样

一条标准的插入语句结构很固定:

INSERT INTO products (id, name, price, in_stock) VALUES
  (1, 'Keyboard', 199.00, 1),
  (2, 'O''Brien Mug', 39.50, 0);

三个要点。第一,列名列表写在表名后的括号里,顺序要和 VALUES 里的值一一对应。第二,字符串值用单引号包,数字和布尔不包。第三,值里如果有单引号,要写成两个单引号转义,所以 O'Brien 变成 'O''Brien',否则引号会提前闭合,整条语句报语法错误。

批量插入就是把多组 VALUES 用逗号串起来,放在一条语句里。这种写法导入最快,数据库只解析一次。

表名和列名怎么映射

CSV 的第一行是表头,它直接决定列名。如果导出的文件没有表头,先补一行名字,不然生成出来的列名会是 col_1、col_2 这种,后面写查询时根本认不出哪列是哪列。

列名还要清洗成合法标识符。表头里的「Order Date」带空格,不能直接当列名,空格要转成下划线变成 order_date。碰上 SQL 保留字(比如 order、select),就得加引号包起来。表名则由你自己指定,比如 productsusers

标识符的引用方式还分方言。MySQL 用反引号:` order_date ;PostgreSQL 和 SQLite 用双引号:"order_date"。布尔列在 PostgreSQL 输出 TRUE/FALSE,在 MySQL 和 SQLite 输出 1/0`。换库的时候这些差异最容易被忽略,手动改起来很烦,交给工具按方言切换更稳。

类型推断:别让一个杂值毁掉整批导入

CREATE TABLE 要给每列定类型。靠谱的做法是扫一整列的所有行再下结论:全是整数就是 INT,带小数就是 DECIMAL,全是 true/false/1/0 就是 BOOLEAN,匹配 YYYY-MM-DD 就是 DATE,其余落到 VARCHAR,长度按最长值取上一个合适的容量。

关键规则是:只要列里出现一个不符合的值,就整列回退到 VARCHAR。这样某一行的杂值不会让推断出的类型装不下数据,导致 INSERT 中途失败。

但推断不是万能的。一列美国邮编 02134 全是数字,会被推成 INT,前导零直接没了。所以生产环境的表结构,务必回看一眼 CREATE TABLE,把编码、ID、电话这类前导零或格式重要的列手动改成 VARCHAR。

一段真实的输入输出

输入这样一段 CSV:

id,name,price,in_stock
1,Keyboard,199.00,true
2,O'Brien Mug,39.50,false

选 PostgreSQL 方言、表名 products,生成的结果是:

CREATE TABLE "products" (
  "id" INT,
  "name" VARCHAR(16),
  "price" DECIMAL(10,2),
  "in_stock" BOOLEAN
);

INSERT INTO "products" ("id", "name", "price", "in_stock") VALUES
  (1, 'Keyboard', 199.00, TRUE),
  (2, 'O''Brien Mug', 39.50, FALSE);

注意三处自动处理:price 被推成 DECIMAL,in_stock 推成 BOOLEAN 并输出大写 TRUE/FALSE,第二行那个撇号被转义成了两个单引号。复制下来直接 psql mydb < products.sql 就能跑。

批量 INSERT 还是逐行 INSERT

两种模式各有用处。批量模式把所有行塞进一条 VALUES,导入最快,适合几千几万行的真实数据灌库。逐行模式每个数据行一条语句,版本控制里 diff 更干净,改某一行 fixture 时一眼能看出动了哪条,审查者还能注释掉单独一行隔离不稳定的用例。做种子数据、测试 fixture 选逐行,跑真实批量导入选批量。

我自己的用法

我常干的一件事是从开发库快速搭测试数据。把一份产品目录从表格导出成 CSV,粘进 CSV 转 SQL 转换器,方言选 PostgreSQL,表名设 products,一次粘贴就拿到带类型的建表语句加批量 INSERT,省掉手写表结构再手敲几十行的功夫。如果只是想先看看 CSV 解析对不对、不急着进库,我会先用 CSV 转 JSON 工具 把结构摊开核对一遍,确认没有错位再生成 SQL。整个过程都在浏览器本地跑,数据不出标签页,处理客户数据时也踏实。

把握住列名映射、类型推断和单引号转义这三件事,CSV 进库就不再是手敲的体力活,而是粘贴、复制、执行三步的事。


Made by Toolora · Updated 2026-06-13