Home/Articles/Excel to PostgreSQL

From Spreadsheets to Databases: Why (and How) to Move Your Excel Files to PostgreSQL

When Excel starts taking five minutes to open and every sort triggers the spinning wheel, it's a signal — not to buy a faster computer, but to move your data somewhere built for this. Here's the full migration path.

8 min read·Data Onboarding Fundamentals

Excel is an excellent tool — for calculations, quick analysis, and sharing numbers with colleagues. But it was designed as a personal productivity tool, not a data store. When your spreadsheet starts exhibiting the symptoms below, you've pushed it past what it was built to do, and a database is the correct next step.

Excel vs PostgreSQL — key differences

CapabilityExcelPostgreSQL
Maximum rows~1,000,000 (hard limit)Billions — no practical limit
Performance at scaleSlows significantly above ~100k rowsConsistent speed regardless of row count
Concurrent usersOne editor at a time (file locked)Hundreds of simultaneous readers and writers
Data type enforcementFlexible — any value in any cellStrict — wrong type is rejected at insert
Accidental data lossOne keystroke can delete a columnChanges require explicit SQL — hard to do by accident
Reporting toolsLimited to Excel chartsConnects to Tableau, Power BI, Looker, Metabase
AutomationMacros — manual trigger requiredTriggers, scheduled jobs, event-driven pipelines
CostMicrosoft 365 subscriptionFree and open source

If your spreadsheet has fewer than 50,000 rows, opens in under a second, and is only ever edited by one person, Excel is probably fine. The migration to PostgreSQL pays off once any of those conditions breaks down — especially multi-user access and row count.

Before You Migrate: The Four Spreadsheet Problems Databases Don't Accept

Databases are more organized than spreadsheets by design. A few Excel conventions that work perfectly for human readers break completely when imported into PostgreSQL. These are worth fixing in the spreadsheet before you even save the CSV.

1

Merged cells

Merging two cells in Excel is a visual formatting trick — the data only exists in one cell, and the other is empty. A database sees rows and columns, not formatting. When imported, merged cell regions produce empty values in every cell except the top-left. Remove all merged cells before exporting: Home → Find & Select → Go To Special → check "Blanks" to find them.

2

Spaces and special characters in column headers

PostgreSQL column names can technically contain spaces if double-quoted, but every query that touches them will require those quotes — which creates friction forever. Clean headers now: replace spaces with underscores (Customer Name → customer_name), remove currency symbols, percent signs, and slashes, and lowercase everything. Simple names pay dividends in every future query.

3

Mixed types in the same column

Excel allows any value in any cell. A column can contain 1000 as a number, "N/A" as a string, and a blank — all in the same column. A database column has a declared type, and every value must match it. Find and replace text placeholders ("N/A", "None", "TBD", "--") with blank cells before export, so they import as NULL. If a date column contains any cells formatted as text, reformat them all consistently.

4

Multiple tables on one sheet

Excel sheets sometimes contain two separate data structures side by side, or a summary table below the main table. PostgreSQL expects one flat rectangular grid per table: a single header row at the top, data rows below, nothing else. Each distinct dataset needs its own sheet before export, and ultimately its own database table.

Step 1: Export as CSV UTF-8

PostgreSQL can't read .xlsx files directly. The bridge between Excel and PostgreSQL is a CSV file — a plain text export where each row is a line and each column is separated by a comma. The encoding choice at export time matters more than most people realize.

Always choose CSV UTF-8 — not plain CSV

In Excel's Save As dialog, the file type dropdown contains both "CSV (Comma delimited)" and "CSV UTF-8 (Comma delimited)." The plain CSV option exports in your system's regional encoding — Windows-1252 on most English Windows machines. Any accented character, currency symbol, em-dash, or non-ASCII character in your data becomes garbled or causes a hard import failure. PostgreSQL expects UTF-8. Always choose the UTF-8 option, even if you think your data is "all English."

CSV export checklist

CheckWhy it matters
File type: CSV UTF-8 (Comma delimited)Any other encoding breaks non-ASCII characters
One sheet exported per fileEach sheet = one CSV = one database table
No merged cells remainingMerged cells produce empty gaps in the imported data
Text fields with commas are double-quoted by ExcelConfirm by opening the CSV in Notepad and inspecting a few rows
Date columns formatted as YYYY-MM-DDPostgreSQL's default date format — avoids type mismatch errors
No empty rows between header and dataEmpty rows import as rows of NULLs, corrupting row count

Step 2: Create the Table in PostgreSQL

A PostgreSQL table is the container your data lands in. Unlike Excel, where a column can hold anything, each PostgreSQL column has a declared type that every value must satisfy. Before importing, you need a table whose columns match the CSV headers and whose types match the data in each column.

Common column type mappings

Excel column containsPostgreSQL type to useNotes
Whole numbers (IDs, counts)INTEGER or BIGINTUse BIGINT if values exceed 2 billion
Decimal numbers (prices, measurements)NUMERIC(p,s) or FLOATNUMERIC is exact; FLOAT is approximate — use NUMERIC for money
Text (names, descriptions)TEXT or VARCHAR(n)TEXT has no length limit; VARCHAR(n) enforces a maximum
Dates (no time)DATEExpects YYYY-MM-DD format in the CSV
Dates with timeTIMESTAMPExpects YYYY-MM-DD HH:MM:SS
Yes/No, True/FalseBOOLEANAccepts true/false, t/f, yes/no, 1/0 in the CSV

When unsure about types: start with TEXT

If you're not sure which type to use for a column, declare it as TEXT initially. Every value in the CSV can land in a TEXT column without errors — you can then inspect the actual data, verify it's clean, and use ALTER TABLE to change the column type once you're confident. This is the staging table approach: import everything as strings, then cast. It's covered in detail in the PostgreSQL schema evolution guide.

Step 3: Import with pgAdmin (No Code Required)

pgAdmin is the official graphical interface for PostgreSQL, free to download, and the simplest way to import a CSV without writing any commands. Once your table exists and your CSV is ready, the import is five clicks.

1

Right-click the table

In pgAdmin's left sidebar, expand your database → Schemas → Tables. Right-click the table you created and select Import/Export Data.

2

Set to Import mode

Toggle the switch at the top of the dialog to "Import" (not Export). Then click the file browser icon to locate your CSV file.

3

Enable the Header option

Click the Options tab. Toggle "Header" to On. This tells PostgreSQL that the first row contains column names to skip — not data to import. Leaving this off means your column headers import as a data row, which causes an immediate type error.

4

Verify the delimiter

The Delimiter field should be set to comma (,). If you exported from Excel with a different regional setting and your CSV uses semicolons, change it here to match.

5

Click OK

PostgreSQL reads the CSV and inserts each row. A progress indicator shows the row count. When complete, right-click the table and select View/Edit Data to confirm the first few rows look correct.

What Happens When the Import Fails

The first import almost always fails — not because the process is hard, but because spreadsheets contain surprises that only become visible when a strict system tries to enforce types. The failure is informative: PostgreSQL tells you exactly which row and which column caused the error.

invalid input syntax for type integer: "Price"

Fix: The Header option was left Off — the column name "Price" was inserted into a numeric column. Re-run with Header toggled On.

extra data after last expected column

Fix: A field contains a comma that wasn't quoted. Open the CSV in a text editor, find the row number PostgreSQL reported, and wrap the field in double quotes.

invalid input syntax for type date

Fix: Date column has values in MM/DD/YYYY format. Reformat the column in Excel as YYYY-MM-DD before re-exporting, or import the column as TEXT first and cast it.

invalid input syntax for type numeric: "N/A"

Fix: Text placeholder in a numeric column. Use Find and Replace in Excel to replace all instances with blank cells before re-exporting.

A deeper troubleshooting reference for all of these errors — including encoding issues, cloud database file visibility problems, and NULL handling — is in the PostgreSQL CSV import troubleshooting guide.

After the Import: What You Can Do Now

Once your data is in PostgreSQL, the capabilities that weren't available in Excel open up immediately. A few things worth doing right after your first successful import:

Add a primary key

If your CSV didn't include a unique ID column, add one: ALTER TABLE your_table ADD COLUMN id SERIAL PRIMARY KEY. This gives every row a stable, unique identifier that reporting tools and future queries can rely on.

Add indexes on frequently queried columns

PostgreSQL scans every row when filtering without an index. If you'll frequently query by customer email, date, or product SKU, add an index on that column. Query times drop from seconds to milliseconds.

Connect a reporting tool

PostgreSQL connections work in Tableau, Power BI, Metabase, Looker, and Grafana with only a hostname, port, database name, and credentials. No additional software or drivers needed for most tools.

Set up recurring imports

If you receive updated CSV files regularly — weekly sales exports, daily transaction logs — you can automate the import using a script or a tool like Elvity, so the spreadsheet-to-database pipeline runs without manual steps each time.

Automate the spreadsheet → database pipeline

Elvity handles the full migration path — schema inference, type detection, encoding normalization, and recurring import automation — without writing a single line of code.