CSV to SQL Converter
CREATE TABLE and INSERT statements from any CSV, in your browser.
Your CSV is parsed in this tab — never uploadedGenerate SQL INSERT and CREATE TABLE statements from a CSV file
Turn spreadsheet rows into a ready-to-run SQL script
Paste or drop a CSV and this tool reads the header row, infers a sensible column type for each field, and writes a CREATE TABLE plus batched INSERT statements you can run in MySQL, PostgreSQL, SQLite, SQL Server or plain ANSI SQL. Identifiers are quoted the way each engine expects — backticks for MySQL, double quotes for PostgreSQL, square brackets for SQL Server — so reserved words like order or select never break the script.
Type inference is deterministic, not a guess from an AI model: a leading-zero ZIP such as 00501 stays TEXT so the zero survives, a value past the signed 32-bit limit (2,147,483,647) is promoted to BIGINT, and only real true/false or yes/no columns become BOOLEAN. Every string value is single-quote escaped, so a hostile cell like Robert'); DROP TABLE students;-- is emitted as one inert literal. Nothing is uploaded — the parser and generator run entirely in your browser tab.
The same CSV produces different SQL for each engine, because the type names and literals genuinely differ. An integer is INT in MySQL and SQL Server but INTEGER in PostgreSQL, SQLite and ANSI; a fixed-point decimal column becomes DECIMAL or NUMERIC, while one in scientific notation becomes DOUBLE, DOUBLE PRECISION, FLOAT or REAL; booleans are written TRUE/FALSE for MySQL and PostgreSQL but 1/0 for SQLite and SQL Server’s BIT; and timestamps land as DATETIME, TIMESTAMP or DATETIME2. SQL Server output also prefixes string literals with N so Unicode survives, and because T-SQL caps a multi-row VALUES clause at 1000 rows, the batch size is clamped there automatically — pick the dialect first and the rest follows.
Numbers are sized from the data you actually paste. A column of 19.99 and 1234.5 becomes DECIMAL(6,2) — wide enough for the longest integer part and the deepest fractional part at once — instead of a lossy float, which is what you want for money. Text columns are measured too: short fields become VARCHAR(n) sized to the longest value, and anything past 255 characters falls back to TEXT (NVARCHAR(MAX) on SQL Server). Empty cells become NULL by default so partial rows still load, and a column is only marked NOT NULL when every row carries a value.
This is a statement generator, not a migration engine, and it stays deliberately literal about your data. It does not invent primary keys, indexes or foreign keys — it cannot know your schema — and it does not emit UPDATE, UPSERT or MERGE. Dates are recognized only in unambiguous ISO 8601 form (2026-03-14); anything with a slash or a two-digit year is kept as text on purpose. Review the CREATE TABLE before running it against a real database, add the keys and constraints your model needs, and for tables past a few hundred thousand rows use the native bulk loader shown below rather than one giant INSERT script.
Running the generated script: psql, mysql and sqlite3 in bulk
Generate the script, save it as data.sql, then feed it to your database's command-line client. The INSERT rows are batched (100 per statement by default, adjustable) so the file parses fast even for large tables.
# PostgreSQL
psql -d mydb -f data.sql
# MySQL / MariaDB
mysql -u root -p mydb < data.sql
# SQLite
sqlite3 mydb.db < data.sql
# SQL Server
sqlcmd -S localhost -d mydb -i data.sqlWrapping the whole load in a single transaction is the biggest speed win: each committed INSERT otherwise forces its own disk flush. Turn autocommit off — or bracket the script — so thousands of rows commit once instead of thousands of times.
BEGIN;
-- generated INSERT statements go here
COMMIT;For files with hundreds of thousands of rows, skip INSERT statements entirely and use your engine's native bulk loader against the raw CSV — it is far faster and streams instead of building one huge script. Use this tool for the CREATE TABLE, then load the data with the commands below.
-- PostgreSQL (psql meta-command, reads the file client-side)
\copy places FROM 'places.csv' WITH (FORMAT csv, HEADER true)
-- MySQL
LOAD DATA LOCAL INFILE 'places.csv' INTO TABLE places
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n' IGNORE 1 LINES;
-- SQLite (inside the sqlite3 shell)
.mode csv
.import --skip 1 places.csv placesWhy a column becomes TEXT when you expected a number
Inference is all-or-nothing per column: the tool picks the most specific type that every non-empty cell satisfies. A single value that fails the numeric or date test drops the whole column to TEXT, which is deliberate — it never silently reshapes your data. Empty cells count as NULL, not as a failure.
| Value in the column | Inferred type | Why |
|---|---|---|
| 00501 | TEXT / VARCHAR | A leading zero is lost as an integer, so ZIPs, SKUs and phone codes stay text and quoted. |
| 1,000 | TEXT | The thousands separator fails the numeric test. Strip separators first if you want INTEGER. |
| 5000000000 | BIGINT | Past the signed 32-bit limit of 2,147,483,647, so INT is promoted to BIGINT. |
| only 0 and 1 | INTEGER | Bare 0/1 is ambiguous — only true/false or yes/no columns become BOOLEAN. |
| 01/02/2020 | TEXT | Ambiguous day/month order. Only ISO 8601 (2020-01-02) is recognized as DATE. |
| 19.99 | DECIMAL / NUMERIC | Fixed-point, so precision and scale are measured from the actual values. |
If one column refuses to type the way you want, clean that column in the source CSV (remove currency symbols, thousands separators or stray text) and regenerate — you do not need to hand-edit the SQL. Reserved-word headers such as order or select are safe as-is because every identifier is always quoted for the chosen dialect.
FAQ
Does it upload my CSV anywhere?
No. All parsing and SQL generation happen locally in your browser tab — the file never leaves your device, and no server, account or third-party call is involved. Once the page has loaded you can even work offline.
Which SQL dialects can it generate?
MySQL, PostgreSQL, SQLite, SQL Server (T-SQL) and generic ANSI SQL. The chosen dialect controls identifier quoting, the data-type names in CREATE TABLE, string escaping rules and how booleans are written (TRUE/FALSE versus 1/0).
Why did my ZIP code column come out as TEXT instead of a number?
Because a leading zero like 00501 would be lost if stored as an integer. The generator detects leading zeros, thousands separators and ambiguous dates, and keeps those columns as quoted TEXT so the exact value survives the round trip into your database.