elefcode
← All guides

Dev Basics · 4 min read

SQL INSERT Statements: Single Rows, Bulk Inserts, and Upserts

Loading data into a database — seed data, a spreadsheet import, a migration — usually comes down to INSERT statements. A few habits make them faster and safer.

Try it yourself with the related tool.

Generate INSERT statements →

Advertisement

The basic statement

INSERT INTO users (name, email) VALUES ('Ana', '[email protected]'); — always list the columns explicitly. Relying on column order breaks as soon as someone adds or reorders a column, and explicit columns let defaults and auto-increment IDs fill themselves in.

Batch rows together

A multi-row insert — VALUES (...), (...), (...) — sends many rows in one statement and is dramatically faster than one statement per row, because each statement has its own round trip and commit overhead. Batches of a few hundred to a few thousand rows work well. Wrapping a large load in a single transaction helps further.

For very large files, use the database's bulk loader, such as PostgreSQL's COPY or MySQL's LOAD DATA.

Escaping values

In a SQL string literal, a single quote is escaped by doubling it: 'O''Brien'. Generated scripts must escape every value, and NULL must be written without quotes. In application code, never build SQL by concatenating user input — use parameterised queries to prevent SQL injection.

Upserts

To insert a row or update it if it already exists, PostgreSQL and SQLite use INSERT ... ON CONFLICT (email) DO UPDATE SET name = excluded.name, while MySQL uses ON DUPLICATE KEY UPDATE. Upserts need a unique constraint to detect the conflict.

Related guides