Turn a CSV export into SQL INSERT statements, with single quotes escaped and empty cells written as NULL. Tick Add CREATE TABLE to get a draft table definition as well. Use it to seed a dev database or run a one-off fix. Semicolon, tab and pipe separated files convert the same way once you pick the matching Separator.
id,name,email,active,signed_up,notes
1,Alex Morgan,alex@example.com,true,2026-01-14,VIP customer
2,Sam Patel,sam@example.com,false,2026-02-03,
3,Riley O'Brien,riley@example.com,true,2026-03-21,"Referred by Alex, follow up" INSERT INTO users (id, name, email, active, signed_up, notes) VALUES
(1, 'Alex Morgan', 'alex@example.com', TRUE, '2026-01-14', 'VIP customer'),
(2, 'Sam Patel', 'sam@example.com', FALSE, '2026-02-03', NULL),
(3, 'Riley O''Brien', 'riley@example.com', TRUE, '2026-03-21', 'Referred by Alex, follow up'); O'Brien becomes 'O''Brien'. Doubling is the standard SQL escape and works in every dialect. The tool does not use backslash escaping, which is a MySQL extension.
An empty field is written as NULL, not as an empty string, whether or not Detect types is on. If a column needs '' instead, replace NULL in the output for that column.
A value that parses cleanly as a number is written without quotes. Turn Detect types off for zip codes, phone numbers and IDs with leading zeros, so the database stores 007 as text instead of the number 7.
With Detect types on, true/false and yes/no become TRUE and FALSE, and a cell that says null becomes NULL. A 1 or 0 stays a number. MySQL stores TRUE and FALSE as 1 and 0 anyway.
Use one multi-row INSERT for a clean bulk load. The database parses one statement and commits once, instead of 1,000 times for 1,000 rows. However, it is all or nothing: one bad row rolls back the whole statement. One per row is slower, but you can re-run only the rows that failed, which helps during a messy migration.
For a production import, use your database's own loader.
That means COPY in PostgreSQL,
LOAD DATA INFILE in MySQL and .import
in SQLite. They run an order of magnitude faster on large files
and never build SQL from data. This page is for seeding a dev
database and one-off fixes.
-- PostgreSQL: reads the file server-side
COPY users (id, name, email, active)
FROM '/path/to/users.csv'
WITH (FORMAT csv, HEADER true);
-- psql, when the file is on your machine rather than the server
\copy users FROM 'users.csv' WITH (FORMAT csv, HEADER true)
-- MySQL
LOAD DATA LOCAL INFILE 'users.csv'
INTO TABLE users
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
-- SQLite
.mode csv
.import --skip 1 users.csv users On a large file these loaders run an order of magnitude faster than generated INSERTs, and they never build SQL from data.
import csv
import psycopg
with open("users.csv", newline="", encoding="utf-8") as f:
rows = list(csv.DictReader(f))
with psycopg.connect("postgresql://localhost/app") as conn:
with conn.cursor() as cur:
# executemany sends the values separately from the SQL:
# nothing in the data can be read as SQL
cur.executemany(
"INSERT INTO users (id, name, email) VALUES (%s, %s, %s)",
[(r["id"], r["name"], r["email"]) for r in rows],
)
conn.commit() <?php
$pdo = new PDO('pgsql:host=localhost;dbname=app', $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$stmt = $pdo->prepare('INSERT INTO users (id, name, email) VALUES (?, ?, ?)');
$fh = fopen('users.csv', 'r');
fgetcsv($fh); // skip the header
$pdo->beginTransaction();
while (($row = fgetcsv($fh)) !== false) {
$stmt->execute([$row[0], $row[1], $row[2]]);
}
$pdo->commit(); // one transaction is far faster than one per row
fclose($fh); The generated CREATE TABLE is a draft. It guesses one type per column from the values in the file, and it has no information about primary keys, foreign keys, indexes, defaults or the right VARCHAR width. For example, a name column whose longest value is 38 characters becomes VARCHAR(50). Read it and fix it before you run it.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
Each single quote is doubled, so O'Brien becomes 'O''Brien'. That is the standard SQL escape and works in every dialect. The tool does not use backslash escaping, which is a MySQL extension.
Yes. With Detect types on, a value that parses cleanly as a number is written unquoted, and true/false or yes/no become TRUE and FALSE. Turn it off to quote every value as a string, which keeps the leading zeros on zip codes and phone numbers. Empty cells become NULL either way.
Pick either in the Statements menu. A multi-row INSERT loads much faster because the database parses and commits once instead of once per row. However, one bad row fails the whole statement, so use One per row when you expect to re-run failures.
Yes. Tick Add CREATE TABLE and the tool emits one with a type guessed per column: INTEGER, DECIMAL, BOOLEAN, DATE or VARCHAR. Treat it as a draft, since the data says nothing about primary keys, indexes, constraints or the right VARCHAR width.
The escaping is correct, but a production import should not build SQL from data at all. Use your database's own loader (COPY in Postgres, LOAD DATA INFILE in MySQL) or a parameterized prepared statement. This tool is for seeding a dev database and one-off migrations.
Choose Semicolon in the Separator menu before pasting. Excel writes semicolons in locales that use a comma for decimals, which is why so many European exports look like this. There is no auto-detection here, so the menu has to match the file. Quoted fields, doubled quotes and line breaks inside quotes are handled identically whichever separator you pick.
Yes. Pick Pipe or Tab under Separator and the file is parsed on that character instead of the comma. Tab works for a .tsv export or a block copied from a spreadsheet, and pipe for database dumps. The table name, type detection and CREATE TABLE options behave the same, and the count above SQL Output confirms the column number is right.
To read the generated SQL with proper indentation, run it through the SQL formatter. For other destinations, the same CSV converts to JSON, a PHP array or a table.