ToolActToolAct

Excel to SQL Converter

Upload Excel file to convert to SQL INSERT statements

Drop Excel file here or click to select file

What is Excel to SQL?

Excel to SQL is an online data format conversion tool that converts Excel (.xlsx/.xls) files into SQL INSERT statements for easy database import.

Excel is the most commonly used spreadsheet format, widely used for data storage and analysis. SQL is the standard query language for relational databases, and INSERT statements are used to insert data into database tables.

With this tool, you can quickly convert Excel spreadsheet data into executable SQL statements, supporting multiple sheet selection, custom table names, and quote styles for convenient data migration and import operations.

How to Use

How to use

  1. Upload an Excel file (.xlsx or .xls format)
  2. If multiple sheets exist, select the sheet to convert
  3. Set the table name (default is table_name)
  4. Choose whether to use the first row as field names
  5. SQL INSERT statements are auto-generated, copy with one click

SQL Generation Checks

  • Inspect column names, data types, quotes, and NULL handling before running generated SQL against a real database.
  • For production imports, test on a temporary table first and keep a backup of the original spreadsheet.

Use Cases

Generate SQL from a selected workbook sheetUpload an Excel file, choose the sheet, set a table name, and generate INSERT statements from either header names or generated col1, col2, col3 column names. The entire pipeline runs on the device, so source spreadsheet contents never leave the browser, which is helpful when working with internal price lists, HR data, or staging snapshots that should not leave the laptop.
Match identifier quoting for the target database draftSwitch table and column quoting between backticks, double quotes, and single quotes, and optionally include a simple VARCHAR(255) CREATE TABLE statement. All parsing and SQL generation happens locally, so a draft script can be reviewed for column names, data types, and quote handling before being executed against the target database.
Prepare local seed data with clear limitationsThe converter preserves cell values as SQL strings or NULL and escapes single quotes, but it does not infer types, constraints, indexes, date semantics, transactions, or bulk-load syntax. Treat the output as a draft for seed data, not as a finished migration.
Pick the right quote style for the target RDBMSMySQL and SQLite accept backticks, PostgreSQL wants double quotes, and SQL Server prefers brackets; pick the matching style in the dropdown so the generated script runs in the target console without manual edits. Be aware that SQLite treats double-quoted identifiers as string literals when no DUAL-column context is implied, so the safe cross-dialect default is the single-quote value style with a backtick or bracket for table/column names. Type inference is purely lexical too: a column whose first non-empty cell is 1, 2, 3 becomes INT, a column starting with 2024-01-01 is exported as a string even though it looks like a date, and monetary cells stored with a thousand separator will be exported with that separator inside the string.
Wrap multi-row inserts inside a transactionThe page emits one INSERT per row, which is slow and unsafe for big imports. Paste the whole block into a BEGIN/COMMIT pair or use the engine's bulk loader when moving more than a few hundred rows into a live database. Header-row detection walks the first non-empty row of the chosen sheet and emits `INSERT INTO ... (col1, col2, ...)` based on its text; DATE cells are read using the Excel serial number convention (days since 1900-01-01 with the 1900 leap-year bug shifting March 1 back one day, so 25569 is the 1970-01-01 Unix epoch). Formula cells that have not been recalculated carry a stale `.value`, and merged-cell ranges expose only the top-left anchor, so a wide merged title row will look like a single NULL to the parser.

Technical Principle

The page parses the uploaded workbook with SheetJS - XLSX.read(arrayBuffer, {type: 'array'}) returns a workbook object whose worksheet has cells indexed by A1 keys, then XLSX.utils.sheet_to_json(sheet, {header: 1, defval: null}) walks the bounded !ref range into an array of arrays. The first non-empty row (when first-row-as-header is on) is taken as column names; otherwise SheetJS-style col1, col2, col3 are synthesized. Each remaining row is emitted as a single SQL statement of the form INSERT INTO `table` (`c1`, `c2`, ...) VALUES (v1, v2, ...);, with optional CREATE TABLE `table` (`c1` VARCHAR(255), ...); prepended. Identifier quoting varies by SQL dialect and is governed by the SQL:1992 standard and each vendor's deviation: standard SQL and PostgreSQL quote identifiers with double quotes ("col"), MySQL and MariaDB use backticks (`col`) by default and only accept double quotes when ANSI_QUOTES SQL mode is on, SQLite accepts both backticks and double quotes (and, for backwards compatibility, treats double-quoted identifiers that don't resolve as string literals - a well-known footgun documented in the SQLite Quirks page), SQL Server and Sybase use square brackets ([col]). Value quoting follows SQL string-literal rules: single quotes wrap the literal and are escaped by doubling them ('O''Brien'), per ISO/IEC 9075. Empty cells map to the unquoted literal NULL, not the empty string ''; numeric cells with cell.t === 'n' are emitted unquoted; booleans become 1/0 or TRUE/FALSE depending on dialect; dates require explicit handling. Date cells need special care because SheetJS preserves the underlying numeric serial: Excel stores dates as days since 1900-01-01 with the historical 1900-02-29 leap-year bug shifting pre-March-1900 dates by one day, and the Excel-for-Mac 1904 system uses 1904-01-01 as epoch instead. The conversion to ISO 8601 (YYYY-MM-DD HH:mm:ss, the format MySQL DATETIME and PostgreSQL TIMESTAMP both accept) is (serial - 25569) * 86400000 ms after the Unix epoch, then formatted in UTC. Type inference is purely lexical and shallow: a column whose first non-empty cell is integer becomes INT, decimal becomes DECIMAL(10,2), text becomes VARCHAR(255), and a column starting with 2024-01-01 may be exported as a string unless the source cell carries cell.t === 'd'. Bulk inserts are emitted as one INSERT per row, which is slow at scale; combining 100-500 rows into a single INSERT INTO t VALUES (...), (...), (...); reduces network round trips by ~100x, and wrapping the script in BEGIN; ... COMMIT; turns the import into one atomic transaction that rolls back on the first failed row.

  • Identifier quoting by dialect: MySQL/MariaDB `col` (backticks, or "col" with ANSI_QUOTES on); PostgreSQL and standard SQL "col"; SQL Server [col]; SQLite accepts both (but "col" silently falls back to a string literal when col is not a known identifier).
  • String literal escape (ISO/IEC 9075): wrap with single quotes and double internal single quotes (O'Brien → 'O''Brien'); never inline raw backslashes - PostgreSQL standard_conforming_strings defaults to on since 9.1.
  • Excel date serial: days since 1900-01-01 with the 1900-02-29 bug (or 1904-01-01 if workbook.date1904 is true); ISO 8601 string = new Date((serial - 25569) * 86400000).toISOString().
  • Type inference is lexical: integers → INT, decimals → DECIMAL(10,2), text → VARCHAR(255); dates that look like dates but aren't typed cell.t === 'd' export as strings; monetary cells with thousand separators export with the separator inside the string.
  • NULL handling: an empty Excel cell becomes the unquoted literal NULL, not '' - the difference matters for NOT NULL columns and for COUNT(col) which skips NULLs but counts ''.
  • Bulk insert: combining 100-500 rows into a single INSERT INTO t VALUES (...),(...),...; cuts network round trips ~100x versus one INSERT per row; MySQL's max_allowed_packet (default 64 MB) caps the per-statement size.
  • Wrap the generated script in BEGIN;...COMMIT; (PostgreSQL/SQLite) or START TRANSACTION;...COMMIT; (MySQL InnoDB) so a single failed row rolls back the whole batch; MyISAM tables ignore the transaction and partially commit.

Examples

Excel sheet → INSERT statements

Sheet "users" (3 rows):
id | name    | email             | age
1  | Alice   | alice@mail.com    | 28
2  | Bob     | bob@mail.com      | 34

Generated SQL:
INSERT INTO users (id, name, email, age) VALUES (1, 'Alice', 'alice@mail.com', 28);
INSERT INTO users (id, name, email, age) VALUES (2, 'Bob', 'bob@mail.com', 34);

Single multi-row INSERT (faster import)

Use the "combine rows" option for bulk loads:

INSERT INTO products (sku, name, price) VALUES
  ('A001', 'USB-C Cable',  9.90),
  ('A002', 'HDMI Adapter', 14.50),
  ('A003', 'Mouse Pad',    4.25);

Reduces 3 round trips to 1 — safer for batches of 100-500 rows.

Quote escaping for names with apostrophes

Source cell: O'Brien

Generated SQL (single quotes doubled):
INSERT INTO customers (id, name) VALUES (42, 'O''Brien');

NULL handling — empty Excel cell becomes literal NULL, not '':
INSERT INTO customers (id, phone) VALUES (43, NULL);

Wrap import in a transaction

BEGIN;
INSERT INTO orders (id, customer_id, total, created_at) VALUES (1001, 7, 199.50, '2026-06-01');
INSERT INTO orders (id, customer_id, total, created_at) VALUES (1002, 7, 42.00,  '2026-06-02');
INSERT INTO orders (id, customer_id, total, created_at) VALUES (1003, 9, 78.30,  '2026-06-03');
COMMIT;

If any row fails the whole batch rolls back.

FAQ

Is the spreadsheet uploaded?

No. The file is parsed in your browser via SheetJS and the SQL is generated locally. Nothing is sent to a server, so even sensitive datasets stay on your device.

What SQL output does it produce?

A CREATE TABLE statement followed by individual INSERT INTO rows (one row per statement). The generated SQL uses the table name you entered and the quote style you selected (single, double, or backtick).

How are column types inferred?

The page samples each column and picks the narrowest type that fits: INTEGER, DECIMAL, VARCHAR(N), BOOLEAN, or DATE/DATETIME. You can override before generating SQL. Mixed-type columns fall back to VARCHAR.

What about Excel dates?

Excel dates are stored as serial numbers. The page outputs them as the raw value from the sheet. Check the generated SQL and adjust date literals to match your target database format if needed.

How are special characters and quotes escaped?

Single quotes are doubled (Smith's → Smith''s). Backslashes and Unicode pass through literally - this matches PostgreSQL standards-compliant strings. If you target MySQL with NO_BACKSLASH_ESCAPES disabled, you may need to escape backslashes manually.

Will the result work on MySQL, PostgreSQL, SQLite, MSSQL?

The basic INSERTs work on all four. The CREATE TABLE statement uses portable types (INT, VARCHAR, DECIMAL, DATE). For dialect-specific types (SERIAL, AUTO_INCREMENT, IDENTITY), edit the CREATE statement to match your target.

Are formulas evaluated?

No. The cached value Excel saved is used. Open the source workbook, recalculate, save, then re-upload if you need fresh formula values.