CSV to SQL
Turn CSV rows into CREATE TABLE and INSERT statements for PostgreSQL, MySQL, SQL Server, or SQLite, with column types inferred from the data.
Local workspace
Named projects in IndexedDB · Local only — never synced to our servers. Worksp…
Batch workspace
Format multiple files locally in one run.
Loading a CSV into a database usually means either a fragile import wizard or hand-written INSERT statements. This converter reads the CSV the way a spreadsheet does, including quoted fields that contain commas and line breaks, then infers a type per column and writes both the CREATE TABLE and batched INSERT statements for your dialect. Values that look numeric but aren't, such as zip codes with a leading zero or 20-digit identifiers, stay text, which is the difference between data that imports correctly and data that quietly changes on the way in.
Common errors and fixes
ERROR: column "order" does not exist
A column name is a reserved word. The generated SQL quotes every identifier for the chosen dialect, so run the output for the database you selected rather than mixing dialects.
ERROR: invalid input syntax for type bigint
A value doesn't match the inferred type, usually because the sample rows were all numeric and the real data isn't. Convert the full file so the column widens to text.
Quoted field not terminated
A quoted CSV field is missing its closing quote, or a literal quote inside it wasn't doubled. RFC 4180 requires "" for a quote inside a quoted field.
Data truncated for column at row 1
MySQL is rejecting a value longer than the column allows. Widen the column, or change the generated TEXT type to the size your schema expects.
Options
| Option | Description |
|---|---|
| Dialect | Sets how identifiers are quoted, which types are used, and how booleans are written. |
| Table name | Name used in the CREATE TABLE and INSERT statements. |
| Include CREATE TABLE | Turn off when the table already exists and you only need the inserts. |
| First row is a header | Off, columns are named column_1, column_2, and every row is treated as data. |
| Delimiter | Detection works for most files; set it explicitly for semicolon CSVs exported by European spreadsheets. |
| Rows per INSERT | Multi-row inserts load far faster than one statement per row, but very large batches can exceed a server's packet limit. |
FAQ
How are column types chosen?
Each column gets the narrowest type that fits every value in it: integer, numeric, boolean, date, timestamp, or text. One value that doesn't fit widens the whole column, so a column of numbers with a single "n/a" becomes text rather than failing on import.
Why is my zip code text instead of a number?
Because 02134 stored as a number becomes 2134. Values with a leading zero stay text, as do numbers longer than 15 digits, which would otherwise lose precision. The same protection covers phone numbers and external IDs.
How are apostrophes and quotes escaped?
A single quote is doubled, so O'Brien becomes 'O''Brien'. For MySQL, backslashes are escaped too, because MySQL treats them as escape characters inside string literals by default.
What happens to empty cells?
They become NULL. CSV can't distinguish an empty string from a missing value, so if a column genuinely needs empty strings, adjust those rows after generating.
Why are the inserts batched?
One multi-row INSERT is much faster than one statement per row. The default is 100 rows per statement, which stays well inside typical packet and parameter limits; lower it if your server rejects large statements.