CSV to SQL Converter
Convert any CSV file or pasted data into optimized SQL INSERT statements instantly. Generates properly escaped INSERT INTO statements for MySQL, PostgreSQL, SQLite, and SQL Server. Supports data type auto-detection, custom table names, bulk multirow insertion, and schema generation.
Convert any CSV file or pasted data into optimized SQL INSERT statements instantly. Generates properly escaped INSERT INTO statements for MySQL, PostgreSQL, SQLite, and SQL Server. Supports data type auto-detection, custom table names, bulk multirow insertion, and schema generation.
This tool is designed to provide a seamless experience for developers by handling complex operations directly in your browser with maximum speed and security.
A CSV to SQL converter reads tabular CSV data — rows and columns separated by a delimiter — and generates SQL INSERT INTO statements that populate a relational database table with the values from each row. The column headers from the first row of the CSV become the column names in the INSERT statement, and every subsequent row becomes one INSERT statement.
This sounds mechanical, and most of it is. The part that is not mechanical — and where hand-written conversions go wrong consistently — is string escaping. SQL uses single quotes to delimit string literals. If a CSV value contains a single quote — an apostrophe in a name like "O'Brien", a possessive in a product description like "John's laptop", a contraction in any natural language text field — that single quote will break the SQL syntax of every INSERT statement that contains it. An unescaped single quote in an INSERT value is not just a syntax error; in certain contexts it is also a SQL injection vector. The correct SQL escape for a literal single quote inside a single-quoted string is two consecutive single quotes: O''Brien. This tool applies that escaping automatically to every string value in every row.
CSV to SQL is a standard category of data tooling because the two formats occupy different but adjacent positions in the data workflow. CSV is the universal export format of spreadsheets, business intelligence tools, legacy systems, and data warehouses. SQL INSERT statements are the standard import mechanism for relational databases — MySQL, PostgreSQL, SQLite, SQL Server, and Oracle all accept them. When you need to move data from a spreadsheet or a legacy system into a relational database, generating INSERT statements from the CSV is one of the most direct paths, particularly for moderate-sized datasets where a full ETL pipeline would be overengineering.
The generated INSERT statements from this tool follow standard SQL syntax compatible with all major relational databases. String values are single-quoted and escaped. Numeric values are output unquoted. NULL values (from empty CSV cells or explicit null markers) are output as SQL NULL. Boolean-looking values (true/false) are output as database-native TRUE/FALSE. The target table name is configurable — you set it to match the actual table in your database before running the statements.
This tool reads CSV data — pasted directly or uploaded as a file — and generates a series of SQL INSERT INTO statements, one per row, that you can execute against a relational database to populate a table with your CSV data. The first row of your CSV is treated as the header row. The column names from that row appear in the column list of every INSERT statement: INSERT INTO table_name (col1, col2, col3) VALUES (...). This explicit column list approach is intentional — INSERT statements without a column list depend on column order matching the table definition exactly, which is fragile and breaks silently if the table schema is ever modified. Always listing the columns explicitly means the statement works correctly regardless of column order in the database table. String values are single-quoted in the output and all single quotes within string values are escaped as doubled single quotes per the SQL standard. This escaping is applied universally — every string field in every row — so you do not need to pre-process your CSV data to handle special characters. Names with apostrophes, text fields with quotes, addresses with punctuation all insert correctly. Numeric values — cells that contain only digits, with or without a decimal point — are output without quotes. This matters for columns that are defined as INTEGER, NUMERIC, DECIMAL, or FLOAT in your database schema. Inserting a number as a quoted string ('42' instead of 42) works in MySQL due to implicit type coercion, but fails with a type mismatch error in strict-mode databases and in PostgreSQL when the column type does not permit string-to-number coercion. Unquoted numeric output avoids this class of error. Empty CSV cells are output as NULL in the INSERT statement — not as empty strings, not as zero, but as SQL NULL — which is the correct representation of a missing value in a relational database. If your application logic distinguishes between NULL and empty string for a particular column, review those fields and decide whether you want NULL or '' before running the statements. The target table name is set in the table name field before generating. The generated statements use that name verbatim in every INSERT INTO table_name. Set this to the exact name of your target table including any schema prefix if required by your database setup (for example, public.users in PostgreSQL).
1. Paste your CSV data into the input area, or click Load Example to see the expected format. Make sure your first row contains column headers — these become the column names in the generated INSERT statements. If your CSV does not have headers, add them manually before pasting.
2. Set the target table name in the Target Table Name field. This must match the exact name of the table in your database, including capitalisation. If your database uses schema-prefixed table names (common in PostgreSQL with multiple schemas), enter the full prefixed name: public.users or analytics.events.
3. Click Generate SQL Inserts. The output panel shows one INSERT INTO statement per CSV row, with all string values single-quoted and escaped, numeric values unquoted, and empty cells represented as NULL.
4. Review the first few generated statements before running them. Check that string fields are correctly quoted, numeric fields are unquoted, and NULL appears where you expect missing values. If a field that should be a number is being quoted as a string, it likely has non-numeric characters in your CSV — clean the source data and regenerate.
5. Check for column type compatibility before executing. The generated statements use implicit type values — strings as single-quoted text, numbers as bare values, booleans as TRUE/FALSE. Verify that these match your table's column definitions. A VARCHAR column accepts a quoted string; an INTEGER column does not accept a quoted string in strict-mode databases.
6. Copy the full SQL output and paste it into your database client — MySQL Workbench, pgAdmin, the psql command line, SQLite Browser, Supabase SQL editor, or any SQL client that accepts standard INSERT statements. For large datasets, consider wrapping the statements in a transaction: BEGIN; ... all INSERT statements ... COMMIT; — this makes the entire import atomic and lets you roll back if something goes wrong.
Run the statements. If any fail with a constraint violation or type mismatch, read the error message — it will include the specific row and column that caused the issue. Fix the source data in your CSV, regenerate, and re-run.
Every project that touches a relational database eventually needs to import data from a spreadsheet or a legacy system export. The business analyst has the data in Excel. The legacy ERP exports to CSV. The client sends a CSV of product catalogue entries that need to go into the database before launch. The QA team has test fixtures in a spreadsheet. Every one of these situations requires the same conversion: CSV rows into SQL INSERT statements. The naive approach is to write a quick script — Python with the csv module, a few lines of string formatting, done. This works until your data has an apostrophe in it. Then you add escaping. Then your data has a row with a different number of columns than the header. Then you have a date column that needs to be formatted differently for MySQL versus PostgreSQL. Then you have a column that should be NULL for empty cells but your string formatting is inserting empty strings. Each of these issues takes time to debug, and the resulting script is ten times longer than you planned when you started. I have written this script more times than I can count across different projects and different teams. The implementation details are always the same, the edge cases are always the same, and the time spent on it is time that contributes nothing to the actual project. This tool handles all of those edge cases — correct escaping, NULL for empty cells, unquoted numerics, explicit column lists — and generates the output in seconds. The explicit column list in every generated INSERT statement deserves special mention because it is the detail most hand-written scripts get wrong. INSERT INTO users VALUES ('Priya', 'Singh', 'priya@example.com') without a column list depends on the values being in the exact order the table was created. If anyone runs an ALTER TABLE to add a column, or if the table was created in a different column order on the target environment, every INSERT from your script inserts values into the wrong columns. INSERT INTO users (name, surname, email) VALUES (...) is explicit and immune to column order changes. It is also self-documenting — you can read the INSERT statement and know exactly which value goes where. For database seeding during development, this tool is the fastest path from a client-provided spreadsheet to a populated local or staging database. For data migrations, it generates auditable SQL that you can review, commit to source control, and run in a controlled deployment window. For quick ad-hoc data imports, it removes the need for database-specific import tools like MySQL's LOAD DATA INFILE or PostgreSQL's COPY command, both of which require file system access on the database server that you often do not have in cloud-hosted environments.
Automatic single-quote escaping — apostrophes in string values become doubled single quotes per SQL standard
Numeric values output unquoted — prevents type mismatch errors in strict-mode PostgreSQL and MySQL
Empty CSV cells output as SQL NULL — correct missing value representation & not empty strings
Explicit column list in every INSERT statement — safe against table schema column order changes
Custom table name configuration including schema-prefixed names like public.users
Compatible with MySQL & PostgreSQL & SQLite and SQL Server standard INSERT syntax
Runs entirely in your browser — zero data transmitted to any server
Free with no account & no install & no rate limits
Seeding a development or staging database with realistic sample data from a spreadsheet
Migrating legacy system data exported as CSV into a MySQL & PostgreSQL or SQLite database
Importing a client-provided product catalogue & user list or content inventory into a relational database before launch
Generating auditable SQL INSERT scripts for a controlled production data migration window
Creating test fixture data from QA-maintained spreadsheets for database integration tests
Importing analytics exports or business intelligence data into a reporting database
Populating a reference or lookup table from a CSV of static values maintained by a business team
Bulk-inserting historical records from a CSV archive into a new database schema
Example Input
id,name,email,role,years_experience,salary,is_active,joined_at,notes 1,Priya Singh,priya@techcorp.io,Principal Engineer,15,185000.00,true,2019-03-12, 2,Arjun Mehta,arjun@techcorp.io,Senior Dev,8,120000.00,true,2020-07-01,Team lead for backend 3,Sana Qureshi,sana@techcorp.io,DevOps Lead,10,135000.00,true,2018-11-22,On leave until June 4,Rohan Verma,rohan@techcorp.io,Frontend Engineer,3,85000.00,false,2022-01-15,Contract ended 5,"O'Brien, Marcus",marcus@techcorp.io,QA Engineer,6,95000.00,true,2021-04-10,
Example Output
INSERT INTO employees (id, name, email, role, years_experience, salary, is_active, joined_at, notes) VALUES (1, 'Priya Singh', 'priya@techcorp.io', 'Principal Engineer', 15, 185000.00, TRUE, '2019-03-12', NULL); INSERT INTO employees (id, name, email, role, years_experience, salary, is_active, joined_at, notes) VALUES (2, 'Arjun Mehta', 'arjun@techcorp.io', 'Senior Dev', 8, 120000.00, TRUE, '2020-07-01', 'Team lead for backend'); INSERT INTO employees (id, name, email, role, years_experience, salary, is_active, joined_at, notes) VALUES (3, 'Sana Qureshi', 'sana@techcorp.io', 'DevOps Lead', 10, 135000.00, TRUE, '2018-11-22', 'On leave until June'); INSERT INTO employees (id, name, email, role, years_experience, salary, is_active, joined_at, notes) VALUES (4, 'Rohan Verma', 'rohan@techcorp.io', 'Frontend Engineer', 3, 85000.00, FALSE, '2022-01-15', 'Contract ended'); INSERT INTO employees (id, name, email, role, years_experience, salary, is_active, joined_at, notes) VALUES (5, 'O''Brien, Marcus', 'marcus@techcorp.io', 'QA Engineer', 6, 95000.00, TRUE, '2021-04-10', NULL);
ERROR: column does not exist — INSERT fails with unknown column name
Fix: The column name in the generated INSERT statement does not match any column in your database table. Check for capitalisation differences (SQL is case-insensitive for keywords but PostgreSQL column names are case-sensitive when quoted), leading or trailing spaces in your CSV header row, or column names in your CSV that do not exist in the target table. Fix the CSV header to match your table schema exactly, then regenerate.
ERROR: invalid input syntax for type integer — string value in a numeric column
Fix: A column defined as INTEGER or NUMERIC in your database is receiving a quoted string value. This happens when a CSV cell that should be a number contains non-numeric characters — a currency symbol like '$185,000', a percentage sign, or spaces. Clean the source data to contain only numeric characters (digits, decimal point, optional leading minus) for numeric columns, then regenerate. The tool outputs numbers unquoted only when the cell contains a pure numeric value.
ERROR: duplicate key value violates unique constraint — INSERT fails on a unique or primary key column
Fix: A value in your CSV conflicts with an existing row in the table for a column with a UNIQUE or PRIMARY KEY constraint. Either your CSV contains a duplicate id value internally, or the data already exists in the table from a previous import. Use INSERT INTO table ON CONFLICT (id) DO NOTHING in PostgreSQL, INSERT IGNORE in MySQL, or INSERT OR IGNORE in SQLite to skip conflicting rows without failing the entire import.
ERROR: syntax error at or near the apostrophe — INSERT fails for a row containing a single quote in a string value
Fix: This should not happen with tool-generated output because the tool automatically escapes all single quotes as doubled single quotes. If you are seeing this error, you may have manually edited the generated SQL after copying it and accidentally removed an escaping double-quote, or you are running SQL that was not generated by this tool. Check the failing INSERT statement for any string value containing an apostrophe and ensure it appears as two consecutive single quotes: O''Brien, not O'Brien.
ERROR: value too long for type character varying(n) — INSERT fails with data truncation
Fix: A string value in your CSV is longer than the maximum length defined for that column in your database schema. Either increase the column size with ALTER TABLE table_name ALTER COLUMN col_name TYPE VARCHAR(new_length), or truncate the value in your source CSV to fit within the existing column length. Review which column is causing the error from the error message and check what length constraint is defined on that column.
Running INSERT statements against a table that has a different column count or order than your CSV — the generated statements use an explicit column list from your CSV headers, so column order in the database table does not matter. What does matter is that every column name in the generated INSERT list actually exists in your target table with a compatible type. Run DESCRIBE table_name in MySQL or \d table_name in PostgreSQL before executing to compare your CSV headers against the actual table schema.
Assuming NULL is the right value for all empty CSV cells — the tool outputs SQL NULL for empty cells because NULL is the correct SQL representation of a missing value. But some database schemas use empty string '' as the sentinel for 'no value' in VARCHAR columns, particularly in legacy databases designed before NULL handling was well understood. If your application code checks for empty string rather than NULL, you will have silent logic errors. Review empty-cell handling against your actual schema and application code before running a bulk import.
Not wrapping a bulk import in a transaction — if you are inserting hundreds or thousands of rows and one row fails midway due to a constraint violation, every row before the failure is committed and every row after is not. You end up with a partially imported dataset that is harder to clean up than a complete failure. Always wrap bulk INSERT scripts in BEGIN; ... COMMIT; (PostgreSQL/SQLite) or START TRANSACTION; ... COMMIT; (MySQL) so the entire import succeeds or the entire import rolls back atomically.
Using the generated INSERT statements on a table with a UNIQUE or PRIMARY KEY constraint without checking for conflicts — if any value in your CSV matches an existing row in the database for a unique column, the entire INSERT will fail with a duplicate key error. Use INSERT OR IGNORE (SQLite), INSERT IGNORE (MySQL), or INSERT ... ON CONFLICT DO NOTHING (PostgreSQL) syntax if you want to skip conflicting rows, or INSERT ... ON CONFLICT DO UPDATE if you want to upsert.
Forgetting to match the date format expected by your database — the tool outputs date strings from your CSV exactly as they appear. If your CSV contains dates as MM/DD/YYYY but your database column is a DATE type expecting YYYY-MM-DD, the INSERT will fail or store an incorrect value. Standardise date formats in your CSV to ISO 8601 (YYYY-MM-DD) before converting, which is accepted by all major SQL databases.
Git Cheatsheet
Quick reference guide for essential Git commands, branching workflows, remote repositories, stashing, and rollbacks.
Regex Cheatsheet
Interactive guide to Regex anchors, character classes, quantifiers, lookarounds, capturing groups, and search flags.
HTTP Headers Cheatsheet
Complete guide to standard and security HTTP headers including Authorization, CORS control, caching policies, and CSP directives.
SQL Cheatsheet
Complete guide to SQL statements including SELECT queries, WHERE filters, aggregate functions, JOIN types, and DDL commands.
Can I customise the table name?
Yes. The Target Table Name field lets you set the exact table name used in every generated INSERT INTO statement. The default is my_table — always change this to match your actual database table before running the output. If your database uses schema-prefixed table names, enter the full name including the schema prefix: public.users for a PostgreSQL table in the public schema, or dbo.Employees for a SQL Server table in the dbo schema. The table name you enter is used verbatim in the output.
Does it handle special characters and prevent SQL injection?
Yes. All single quotes in string values are automatically escaped as doubled single quotes — the SQL standard escape sequence. This handles apostrophes in names (O'Brien becomes O''Brien), possessives in text fields, and any other naturally occurring single quotes in your data. This escaping also means the generated INSERT statements are safe to run without SQL injection risk from your CSV data values. Note that this is escaping for static SQL strings, not parameterised queries — the tool generates escaped literal values, not query parameters.
How does it handle empty cells in the CSV?
Empty CSV cells are output as SQL NULL in the generated INSERT statements — not as empty strings (''), not as zero, but as NULL. This is the correct SQL representation of a missing or unknown value. In most cases this is what you want. If your database schema uses empty string as the sentinel for 'no value' in a particular column — a legacy pattern in some older schemas — you will need to post-process the generated SQL to replace NULL with '' for those columns, or clean your CSV to populate empty cells with a space or placeholder value before converting.
Is the output compatible with MySQL, PostgreSQL, and SQLite?
Yes. The generated INSERT INTO table (col1, col2) VALUES (...) syntax is standard SQL accepted by MySQL, PostgreSQL, SQLite, SQL Server, Oracle, and MariaDB. The escaping (doubled single quotes for apostrophes) is the SQL standard approach and is supported by all of these databases. TRUE and FALSE boolean literals are supported in PostgreSQL and MySQL — SQLite stores booleans as integers (1 and 0), so you may need to replace TRUE/FALSE with 1/0 in the generated output for SQLite targets.
Should I wrap the generated INSERT statements in a transaction?
Yes, always, for bulk imports of more than a few rows. Wrapping all INSERT statements in a transaction makes the entire import atomic — either all rows are committed or none are, depending on whether any error occurs. Without a transaction, a failure midway through a 500-row import leaves you with a partially populated table that is difficult to reason about and harder to clean up than a complete rollback. Use BEGIN; ... COMMIT; in PostgreSQL and SQLite, or START TRANSACTION; ... COMMIT; in MySQL. If an INSERT fails inside a transaction, the database rolls back to the state before BEGIN automatically.
How does it handle numeric values versus string values?
Cells that contain only numeric characters — digits, a single decimal point, and an optional leading minus sign — are output as unquoted numeric literals in the SQL. Everything else is output as a single-quoted string. This distinction matters because PostgreSQL and strict-mode MySQL reject a quoted string ('42') being inserted into an INTEGER column. MySQL in non-strict mode silently coerces the string to a number, which works but masks a real data quality issue. Unquoted numeric output avoids the coercion entirely. If a numeric column in your CSV contains formatting characters like currency symbols or thousands separators, clean the source data before converting.
What is the best way to import very large CSV files?
For CSV files with thousands of rows, generating individual INSERT statements is workable but not the most efficient approach for the database. Each INSERT statement is a separate operation that requires parsing, planning, and executing independently. For large imports, consider two alternatives. First, if you have server file system access, PostgreSQL's COPY command and MySQL's LOAD DATA INFILE are purpose-built for bulk CSV import and are orders of magnitude faster than individual INSERT statements. Second, you can restructure the generated INSERT statements into multi-row INSERT format — INSERT INTO table (cols) VALUES (row1), (row2), (row3) — which batches many rows into one statement and significantly reduces round-trips. For moderate datasets up to a few thousand rows in a cloud-hosted database without file system access, individual INSERT statements are perfectly practical.
Is my CSV data sent to any server?
No. The entire conversion runs in JavaScript in your browser. Your CSV data is never transmitted to any server, never logged, and never stored anywhere outside your local browser tab. This is a deliberate architectural decision, not just a privacy claim. Open your browser's network inspector before pasting any data and you will see zero outbound requests carrying your CSV. This makes the tool safe for sensitive data — customer records, employee data, financial figures, or any CSV you would not want to upload to a third-party service.
Recent Activity
No recent activity