CSV to SQL Converter
Turn CSV into SQL INSERT statements, with a CREATE TABLE inferred from the data, for MySQL, PostgreSQL, SQL Server or SQLite.
Paste or open a CSV file to get the SQL that loads it: a CREATE TABLE whose column types are inferred from every value, and INSERT statements written for MySQL, PostgreSQL, SQL Server or SQLite. The inferred columns can be renamed, retyped and given a primary key, and a duplicate key can be skipped or updated.
Values are written from the text of the file, never through a floating-point number, so long ids and prices keep every digit. It runs in your browser: nothing you paste or open is sent anywhere.
Options
- Dialect — sets the types, the quoting and the statements. MySQL is the default.
- Table name — taken from the file's name when you open one, else
my_table. A dotted name such assales.ordersis quoted part by part. - CSV delimiter — found in the data by default; the CSV may hold quoted values with commas, quotes and line breaks (RFC 4180).
- Rows per INSERT — 1, 100 (the default), 500 or 1,000 rows in one statement. SQL Server accepts at most 1,000 rows in a VALUES list. For SQLite, a statement that would pass its default limit of 1,000,000 bytes is split, and a note says so.
- CREATE TABLE, DROP TABLE IF EXISTS first and Wrap in a transaction add those statements.
DROP TABLE IF EXISTSneeds SQL Server 2016 or later. - Empty cells as NULL — on by default. Off, an empty cell in a text column is written
''; number, boolean and date columns cannot hold an empty string, so their empty cells stay NULL, with a note. - Read the text NULL as NULL — off by default, so a cell reading
NULLis the four-letter string. On, it is SQL NULL in any case. - Edit columns — under the output, each column's SQL name, type, Nullable and Primary key. The types offered are those every value fits, plus Text.
- On a duplicate key — shown once a primary key is set, for every dialect but SQL Server: fail (plain INSERT), skip the row, or update it. The statements for each dialect are listed under How it works.
How it works
Each column's type is the narrowest every value fits. Whole numbers are an integer within 32 bits, a big integer within 64 bits, and text beyond that. Numbers with a fraction are a decimal sized from the data: the scale is the most digits after the point, and the precision the most digits before it plus the scale; past 38 digits the column is text. A value with a leading zero such as 007 makes the column text, so codes and phone numbers keep their zeros. Booleans are true and false, in any case. Dates and date-times are recognised only in ISO form (2026-01-05, 2026-01-05 10:30, with or without an offset), and only when the date exists; other date formats stay text. Empty cells never decide a type; they make the column nullable.
Text columns are sized for the longest value, rounded up to 16, 32, 64, 128, 255, 500 or 1,000 characters. MySQL counts characters; SQL Server's NVARCHAR counts UTF-16 units, so an emoji counts twice there. MySQL's BOOLEAN is an alias for TINYINT(1). SQLite has no fixed column types: its affinities are used, and dates are stored as ISO text.
Strings double each ' in every dialect. MySQL also reads a backslash as an escape under its default sql_mode, so backslashes are doubled there. SQL Server strings are written N'…' so non-Latin text and emoji survive. Identifiers are always quoted: backticks for MySQL, square brackets for SQL Server, double quotes for PostgreSQL and SQLite. Booleans are TRUE and FALSE in MySQL and PostgreSQL, 1 and 0 in SQL Server and SQLite. SQL Server's DATETIMEOFFSET reads an offset as +hh:mm, so +0530 is written +05:30 there and Z as +00:00. Its DATETIME2 and DATETIMEOFFSET hold seven digits of a fractional second, so a longer fraction is cut to seven there, not rounded, and a note names the columns.
- MySQL — skip:
INSERT IGNORE; update:ON DUPLICATE KEY UPDATE col = VALUES(col). MySQL 8.0.20 deprecatesVALUES()here in favour of a row alias, which MariaDB does not support;VALUES()still works on MySQL 5.7, 8 and MariaDB. - PostgreSQL —
ON CONFLICT (key) DO NOTHINGorDO UPDATE SET col = EXCLUDED.col. One statement cannot update the same key twice, so repeated keys in the data get a warning naming the rows. - SQLite —
INSERT OR IGNORE, orON CONFLICT (key) DO UPDATE(SQLite 3.24 or later). - SQL Server — needs a MERGE statement, which the tool does not write; the option is not shown for it.
Examples
A product list into MySQL
- Input CSV
sku,name,price,in_stock 007,Masala chai,4.50,true 012,Mug "large",12.00,false 031,Kettle,,true
- Options
- the defaults
- SQL output
CREATE TABLE `my_table` ( `sku` VARCHAR(16) NOT NULL, `name` VARCHAR(16) NOT NULL, `price` DECIMAL(4,2), `in_stock` BOOLEAN NOT NULL ); INSERT INTO `my_table` (`sku`, `name`, `price`, `in_stock`) VALUES ('007', 'Masala chai', 4.50, TRUE), ('012', 'Mug "large"', 12.00, FALSE), ('031', 'Kettle', NULL, TRUE);
sku is text, because of its leading zeros. The empty price is NULL, which makes the price column nullable, and the quotes in Mug "large" need no escaping inside a SQL string.
The same list into PostgreSQL, updating existing rows
- Input CSV
sku,name,price,in_stock 007,Masala chai,4.50,true 012,Mug "large",12.00,false 031,Kettle,,true
- Options
- Dialect PostgreSQL, CREATE TABLE off, sku as the primary key, On a duplicate key: Update
- SQL output
INSERT INTO "my_table" ("sku", "name", "price", "in_stock") VALUES ('007', 'Masala chai', 4.50, TRUE), ('012', 'Mug "large"', 12.00, FALSE), ('031', 'Kettle', NULL, TRUE) ON CONFLICT ("sku") DO UPDATE SET "name" = EXCLUDED."name", "price" = EXCLUDED."price", "in_stock" = EXCLUDED."in_stock";
Rows whose sku already exists take the new name, price and stock; the others are inserted.
Into SQL Server
- Input CSV
sku,name,price,in_stock 007,Masala chai,4.50,true 012,Mug "large",12.00,false 031,Kettle,,true
- Options
- Dialect SQL Server, Table name dbo.products
- SQL output
CREATE TABLE [dbo].[products] ( [sku] NVARCHAR(16) NOT NULL, [name] NVARCHAR(16) NOT NULL, [price] DECIMAL(4,2), [in_stock] BIT NOT NULL ); INSERT INTO [dbo].[products] ([sku], [name], [price], [in_stock]) VALUES (N'007', N'Masala chai', 4.50, 1), (N'012', N'Mug "large"', 12.00, 0), (N'031', N'Kettle', NULL, 1);
Strings are N'…', booleans are BIT values, and the schema and table are bracketed separately.
Into SQLite, skipping rows already there
- Input CSV
sku,name,price,in_stock 007,Masala chai,4.50,true 012,Mug "large",12.00,false 031,Kettle,,true
- Options
- Dialect SQLite, CREATE TABLE off, sku as the primary key, On a duplicate key: Skip
- SQL output
INSERT OR IGNORE INTO "my_table" ("sku", "name", "price", "in_stock") VALUES ('007', 'Masala chai', 4.50, 1), ('012', 'Mug "large"', 12.00, 0), ('031', 'Kettle', NULL, 1);
Column types by dialect
| Values | Example | MySQL | PostgreSQL | SQL Server | SQLite |
|---|---|---|---|---|---|
| Integer | 42 | INT | INTEGER | INT | INTEGER |
| Big integer | 3000000000 | BIGINT | BIGINT | BIGINT | INTEGER |
| Decimal | 4.50 | DECIMAL(3,2) | NUMERIC(3,2) | DECIMAL(3,2) | NUMERIC |
| Boolean | true | BOOLEAN | BOOLEAN | BIT | INTEGER |
| Date | 2026-01-05 | DATE | DATE | DATE | TEXT |
| Date-time | 2026-01-05 10:30 | DATETIME | TIMESTAMP | DATETIME2 | TEXT |
| Date-time with offset | 2026-01-05T10:30+05:30 | VARCHAR(32) | TIMESTAMPTZ | DATETIMEOFFSET | TEXT |
| Text, up to 1,000 characters | Masala chai | VARCHAR(16) | TEXT | NVARCHAR(16) | TEXT |
| Text, longer | 1,200 characters | TEXT | TEXT | NVARCHAR(MAX) | TEXT |
Sources
The CSV is read as RFC 4180 describes it. The quoting, types and statements follow each database's reference manual, at its default settings.
Sources
- RFC 4180: Common Format and MIME Type for CSV Files — IETF
- MySQL 8.4: String Literals — Oracle
- MySQL 8.4: INSERT … ON DUPLICATE KEY UPDATE — Oracle
- PostgreSQL: INSERT — PostgreSQL Global Development Group
- PostgreSQL: Lexical Structure — PostgreSQL Global Development Group
- SQL Server: Table Value Constructor — Microsoft
- SQL Server: nchar and nvarchar — Microsoft
- SQLite: UPSERT — SQLite
- SQLite: Limits In SQLite — SQLite
- SQLite: Datatypes In SQLite — SQLite
Reviewed
Frequently asked questions
LOAD DATA, COPY, BULK INSERT, .import) is faster than INSERT statements.See also
- SQL Formatter — to format the statements or other SQL.
- CSV to JSON Converter — to turn the same CSV into JSON, or back.