How to convert an excel spreadsheet to postgresql insert statements for db seeding
- Step 1Open the generator — The Excel → SQL entry redirects to the JSON to SQL converter, which is the live engine and accepts
.xlsx,.xls,.ods,.csv, and.json. Drop your seed workbook there directly. - Step 2Load the first sheet — SheetJS parses the first sheet only with row 1 as headers. Keep your seed data on the first tab; a
NotesorPivottab in front of it would be read instead. - Step 3Name the table — Type the Postgres table name (default
data). It is double-quoted in the output, so schema-qualified names with special characters stay valid — though to target a schema likepublic.category, edit the generated identifier afterward (the field treats the whole string as one identifier). - Step 4Select PostgreSQL — Click the PostgreSQL dialect button. This gives double-quote identifiers,
TRUE/FALSEbooleans, andDOUBLE PRECISIONfor decimal columns. - Step 5Set CREATE TABLE and conflict behaviour — Leave Include CREATE TABLE and IF NOT EXISTS on for a self-contained, re-runnable file. Tick ON CONFLICT DO NOTHING for idempotent seeding. Add audit fields to Exclude columns (e.g.
row_hash, imported_at) to keep them out of the seed. - Step 6Generate and run — Click Generate SQL, then Copy into
psql/ pgAdmin's Query Tool, or Download SQL into yourdb/seeds/folder. The stats line confirms rows, columns, and statement count before you run it.
PostgreSQL output specifics
What the generator produces when the PostgreSQL dialect is selected, compared with the other two dialects, so you know exactly what lands in psql.
| Aspect | PostgreSQL | vs MySQL | vs SQLite |
|---|---|---|---|
| Identifier quoting | "col" (double quotes) | col ` (backticks) | "col" (double quotes) |
| Boolean values | TRUE / FALSE | 1 / 0 | TRUE / FALSE |
| Boolean column type | BOOLEAN | TINYINT(1) | BOOLEAN |
| Decimal column type | DOUBLE PRECISION | REAL | REAL |
| Conflict clause | ON CONFLICT DO NOTHING | INSERT IGNORE INTO | ON CONFLICT DO NOTHING |
| String escape | Double single quote ('') | Double single quote ('') | Double single quote ('') |
Seeding limits by tier
Two ceilings apply together. The Excel-family limit caps the input file; the code-generation quota caps the rows actually written. Your usable seed size is the smaller of the two.
| Tier | Excel file size | Code-gen rows | Code-gen runs/day |
|---|---|---|---|
| Free | 5 MB | 100 rows | 1 |
| Pro | 50 MB | 1,000 rows | 5 |
| Pro + Media | 200 MB | 10,000 rows | 50 |
| Developer | 500 MB | Unlimited | Unlimited |
Cookbook
PostgreSQL-flavoured before/after fragments for typical seed data. Defaults: dialect Postgres, CREATE TABLE on, IF NOT EXISTS on.
Lookup table seed, ready for psql
A reference table with a boolean active flag. Note TRUE/FALSE (Postgres-native) and the BOOLEAN column type in the DDL.
Excel (Sheet1):
id | code | active
1 | EU | TRUE
2 | US | FALSE
Generated SQL (table 'region'):
CREATE TABLE IF NOT EXISTS "region" (
"id" INTEGER,
"code" TEXT,
"active" BOOLEAN
);
INSERT INTO "region" ("id", "code", "active")
VALUES
(1, 'EU', TRUE),
(2, 'US', FALSE);Idempotent re-seed with ON CONFLICT
With the conflict toggle on, the INSERT ends with ON CONFLICT DO NOTHING, so re-running the seed against a populated table skips existing primary keys silently.
Options: PostgreSQL, ON CONFLICT DO NOTHING
INSERT INTO "region" ("id", "code", "active")
VALUES
(1, 'EU', TRUE),
(2, 'US', FALSE) ON CONFLICT DO NOTHING;Reserved-word column survives quoting
A column literally named 'order' would be a syntax error unquoted. Postgres double-quoting keeps it valid.
Excel:
id | order
1 | 10
2 | 20
Generated SQL:
INSERT INTO "data" ("id", "order")
VALUES
(1, 10),
(2, 20);Dates: standardise, then CAST
Because Excel dates arrive as serials, generate them as ISO text first (via the date standardizer) so they land as TEXT, then alter the column to a real date type in Postgres.
Seed file value (after date standardizer → ISO text):
INSERT INTO "event" ("id", "starts")
VALUES (1, '2024-06-01');
Then in psql:
ALTER TABLE event
ALTER COLUMN starts TYPE date USING starts::date;Drop audit columns from the seed
Operational exports often carry imported_at / row_hash columns you do not want in version-controlled seed data. List them in Exclude columns.
Exclude columns: imported_at, row_hash Result: those two headers are omitted from both the CREATE TABLE and every INSERT, leaving only the business columns in the seed file.
Edge cases and what actually happens
Schema-qualified table name
Manual editThe Table name field is emitted as a single double-quoted identifier, so typing public.region produces "public.region" (one identifier with a dot) — not schema.table. For a schema target, edit the generated identifier to public."region" after copying.
Excel dates infer INTEGER
By designPostgres won't accept a serial number into a date column. Standardise the column to ISO text with the date standardizer first; it then generates as quoted TEXT you can CAST/ALTER to date.
NUMERIC/money column needs exact precision
Precision noteDecimals infer DOUBLE PRECISION, which is floating point. For currency, change the inferred type to NUMERIC(12,2) in the generated DDL before running, since DOUBLE PRECISION can introduce rounding.
Composite or no primary key with ON CONFLICT
Conflict targetON CONFLICT DO NOTHING (without a target) relies on any unique or PK constraint existing on the table. If the table has none, nothing conflicts and every row inserts. Ensure the constraint exists, or this toggle is a no-op.
Multiple sheets in the workbook
First sheet onlyOnly the first tab is read. Lookup tables spread across tabs must be generated one at a time, or combined first with the sheet joiner.
bigserial / large IDs
Precision riskIDs beyond 2^53 lose precision during JS parsing. For bigint keys with very large values, format the Excel column as Text so they pass through verbatim as quoted strings, then cast in SQL.
Free tier 100-row cap on a 5,000-row seed
Upgrade requiredThe code-generation quota caps Free at 100 rows and 1 run/day; the seed is truncated past that. Pro raises it to 1,000 rows / 5 runs, Pro+Media to 10,000, Developer unlimited.
Empty cells vs zero
NULL preservedA blank numeric cell becomes NULL, not 0. If your Postgres column is NOT NULL DEFAULT 0, either fill the cell in Excel or let the default fire — the generated NULL would be rejected by a NOT NULL column without a default.
Mixed-type column quoted as TEXT
TEXT preservedA column mixing numbers and text infers TEXT; numeric-looking values are quoted as strings. Clean or split the column first if Postgres needs it numeric.
Frequently asked questions
Does it produce real PostgreSQL syntax?
Yes — selecting the PostgreSQL dialect gives double-quoted identifiers, TRUE/FALSE booleans, DOUBLE PRECISION decimals, and ON CONFLICT DO NOTHING for conflict handling. It runs as-is in psql and pgAdmin's Query Tool.
How do I make the seed idempotent?
Tick ON CONFLICT DO NOTHING (appends Postgres' conflict clause) and keep IF NOT EXISTS on for the CREATE TABLE. Re-running then skips existing rows and won't re-create the table.
Why are my dates showing as numbers?
Excel dates are serial numbers and arrive as integers, so they infer INTEGER. Convert the column to ISO text first with the date standardizer; it will then generate as TEXT you can CAST to date.
Can I target a specific schema like public?
Partly. The table name is emitted as one double-quoted identifier, so public.region becomes "public.region". To get a true schema target, edit the identifier to public."region" after generating, or set your search_path before running.
What type does a decimal column get?
DOUBLE PRECISION in Postgres. For exact currency or financial data, change it to NUMERIC(p,s) in the generated DDL, because DOUBLE PRECISION is floating point and can round.
Are quotes and apostrophes escaped for Postgres?
Yes — single quotes are doubled (''), which is valid Postgres string escaping. The tool does not use dollar-quoting ($$); doubling is used for every value.
Will it read all my sheets?
No, only the first. Combine tabs with the sheet joiner first if your seed spans multiple sheets.
How many rows can I seed at once?
The Excel file cap is 5 MB (Free) up to 500 MB (Developer), but the code-gen quota is stricter: 100 rows (Free), 1,000 (Pro), 10,000 (Pro+Media), unlimited (Developer). Plan around the row cap.
Is the data uploaded anywhere?
No. SheetJS parses the workbook in your browser and the SQL is generated locally. Only an anonymous usage counter is recorded server-side, which you can disable in settings.
Can I drop columns I don't want in the seed?
Yes — list them comma-separated in Exclude columns (e.g. imported_at, row_hash) and they are omitted from the DDL and every INSERT.
What about a NOT NULL column with blank cells?
Blank cells generate NULL, which a NOT NULL column rejects unless it has a default. Fill the cells in Excel, or remove the NULL rows, before running the seed.
Which related tools help prepare the data?
Use formula-to-value to flatten formulas, the date standardizer for dates, and Excel → Python if you'd rather seed via an ORM script. For JSON sources, the engine is the same JSON to SQL converter.
Privacy first
Every JAD Excel tool runs entirely in your browser using SheetJS and ExcelJS. Your spreadsheets, formulas, and data never leave your device — verified by zero outbound network requests during processing.