All guides

Get a CREATE TABLE statement from a CSV file

Every database can bulk-load a CSV, but only into a table that already exists, so the first job is a CREATE TABLE whose columns match the header. The converter writes it for your dialect from the file itself, quoting the names that need quoting, and adds the INSERTs if you want the data in the same script.

Column names from the header

The header row becomes the column list. A name with a space, a dash or a capital letter is quoted the way your database expects — double quotes for Postgres and SQLite, backticks for MySQL, square brackets for SQL Server — so "order date" survives as a column rather than as an error. Pick the dialect and the table name, and the statement is written for it.

If the header is not the first row — a report title sits above it — the health check here finds that, and the editor removes the extra rows without touching the rest.

Why every column starts as text

The generated CREATE TABLE gives every column a text type, and every INSERT writes the value as it appears in the file. That is deliberate: a CSV has no types, and guessing them is how a leading zero disappears, how 1/2 becomes a date, and how one stray word in a numeric column stops the whole load. Text always loads.

Cast in the database, where you can decide what happens when a value does not fit: ALTER the column with a USING clause in Postgres, or create the typed table you want and INSERT INTO it with a SELECT that converts, checking the rows that fail rather than losing them.

Loading the rows

For a file of a few thousand rows, the INSERTs the converter writes after the CREATE TABLE are the simplest route — five hundred rows per statement, which replays quickly and stays under server limits. Run the script and the data is in.

For a large file, use the CREATE TABLE and load the rows with your database’s own bulk command — COPY in Postgres, LOAD DATA in MySQL, .import in SQLite, BULK INSERT in SQL Server — which every database does faster than any INSERT script. The converter refuses files past a hundred thousand rows for exactly that reason and says so.

The sample file

order_id,cust_ref,amount,status
S-1001,00412,150.00,paid
S-1002,00413,89.50,paid
S-1003,00412,32.10,refunded
S-1004,00415,410.00,paid
S-1005,00416,55.25,pending
S-1006,00999,12.00,paid
S-1007,,77.70,paid

Obviously made-up data, small enough to read. Download it and drop it on the tool to see the fix before trying your own file.

Questions

Does it guess the column types?
No — every column is text, and every value is inserted as written. Type it in the database, where a value that does not fit is an error you can see rather than a silent change.
What happens to column names with spaces or capitals?
They are quoted in the style of the dialect you pick — double quotes, backticks or square brackets — so the name in the database is the name in your header.
Can I get the CREATE TABLE without the INSERTs?
The statement is the first thing in the script, on its own, so copy that part. The INSERTs follow it and can be left out of what you run.
Which databases are supported?
Postgres, MySQL, SQLite and SQL Server, each with its own quoting and string escaping. Most others accept the Postgres form.
My file has a million rows — will this work?
Not as INSERTs, and the page says so above a hundred thousand rows. Take the CREATE TABLE from a sample of the file and load the full file with your database’s bulk import, which is built for it.
Is my file uploaded anywhere?
No. The CREATE TABLE is written from your file’s header and rows on your own device; the first place your data goes is the database you choose to run the statement against.