How to sanitize excel column headers for postgresql, mysql, and sqlite import
- Step 1Open the tool and drop your export — Land on /excel-tools/excel-header-sanitizer (redirects to Header Rename) and drop the
.xlsxor.csvyou plan to load into Postgres/MySQL/SQLite. Row 1 is read as headers. - Step 2List the columns against your target schema — Each header appears with an inline input. Have your
CREATE TABLE(or intended column list) open so you rename to the exact identifiers the table expects. - Step 3Type a valid identifier for each header — Use lowercase snake_case:
First Name→first_name,Order #→order_id,Date (UTC)→date_utc. Avoid reserved words (order,user,select,group) by choosing a distinct name. Leave a field blank to keep an already-clean header. - Step 4Run the rename and scan for duplicates — Click
Rename N headers. There is no uniqueness check, so check the preview header row — two columns renamed to the same identifier will break the import. - Step 5Download the renamed file — XLSX input downloads as
name.renamed.xlsx; CSV downloads asname.renamed.csv. For Postgres\copy, CSV is usually the cleanest path. - Step 6Load with headers as column names — Run
\copy mytable FROM 'name.renamed.csv' WITH (FORMAT csv, HEADER true)(Postgres),LOAD DATA INFILE ... IGNORE 1 LINES(MySQL), or.import --csv name.renamed.csv mytable(SQLite). The clean headers now match your column names.
Excel header → safe SQL identifier
Typical Excel header patterns and a recommended snake_case target. You type these — the tool does not generate them automatically.
| Excel header | Problem for SQL | Type this instead |
|---|---|---|
First Name | Space requires double-quoting in every query | first_name |
Order # | # is not a valid identifier character | order_id or order_number |
Date (UTC) | Parentheses and space; date is also a type name | date_utc or created_at_utc |
% Margin | Leading % and space | margin_pct |
User | user is reserved in PostgreSQL and MySQL | user_name or account_user |
2024 Revenue | Starts with a digit (illegal unquoted) | revenue_2024 |
Identifier rules by engine
What each target engine accepts as an unquoted column name. When in doubt, lowercase snake_case starting with a letter is portable across all three.
| Engine | Unquoted name rules | Reserved-word handling |
|---|---|---|
| PostgreSQL | Letters, digits, underscores; must not start with a digit; folded to lowercase unless quoted | Reserved words usable only when double-quoted everywhere — avoid them |
| MySQL | Letters, digits, underscores, $; backtick-quote anything irregular | Reserved words need backticks in every reference |
| SQLite | Very permissive, but quoting irregular names is required and error-prone | Few reserved restrictions, but stick to snake_case for portability |
What the tool does and does not do for SQL prep
The Header Rename tool is a manual rename pass, not a SQL validator. Know the boundary before you rely on it.
| Capability | Provided? | Detail |
|---|---|---|
| Inline rename of every header | Yes | Type each target identifier; blank keeps the original |
| Auto snake_case conversion | No | You type the names; nothing is transliterated |
| Reserved-word detection | No | order or user is written verbatim — you must avoid them |
| Duplicate-name detection | No | Two columns renamed alike produce duplicate headers |
| Data-row preservation | Yes | Values reach the loader unchanged |
Cookbook
Real Excel-to-database header fixes. Left is the export; right is the identifier you type and the resulting load.
Postgres \copy with HEADER true
The cleanest Postgres path: rename headers to match your table, export CSV, and let \copy map the header row to columns. No quoting needed because every name is snake_case.
Headers: First Name | Last Name | Order # | Date (UTC)
You type: first_name | last_name | order_id | date_utc
Download: orders.renamed.csv
CREATE TABLE orders (first_name text, last_name text,
order_id bigint, date_utc timestamptz);
\copy orders FROM 'orders.renamed.csv' WITH (FORMAT csv, HEADER true);Dodging a reserved word
User and Order are reserved in Postgres/MySQL. The tool will happily write them verbatim — so rename them to non-reserved forms yourself.
Headers: User | Order | Group You type: account_user | order_ref | group_name Output header row: account_user,order_ref,group_name (If you had kept 'user', every query would need "user".)
MySQL LOAD DATA INFILE
MySQL's loader ignores the header line and maps by position. You still want clean names so the columns you specify in the load statement are readable and match your table.
Headers: 2024 Revenue | % Margin You type: revenue_2024 | margin_pct Download: kpis.renamed.csv LOAD DATA INFILE 'kpis.renamed.csv' INTO TABLE kpis FIELDS TERMINATED BY ',' IGNORE 1 LINES (revenue_2024, margin_pct);
SQLite .import
SQLite's .import --csv can create columns from the header row. Clean snake_case names mean the auto-created table is immediately queryable without quoting.
Headers: Customer Name | E-Mail | Phone # You type: customer_name | email | phone Download: contacts.renamed.csv sqlite> .import --csv contacts.renamed.csv contacts sqlite> SELECT customer_name, email FROM contacts;
Avoiding an accidental duplicate column
If your export already has both Email and Email Address, do not collapse them to the same identifier — the import will see two email columns. Give them distinct names.
Headers: Email | Email Address WRONG: email | email -> duplicate header, import fails RIGHT: email | email_alt Output header row: email,email_alt
Edge cases and what actually happens
Reserved word typed as a header
No validationThe tool writes whatever you type, including SQL reserved words like order, user, select, group. PostgreSQL and MySQL then require the name to be quoted in every query forever. There is no reserved-word warning — choose a non-reserved identifier (order_ref, account_user) yourself before downloading.
Two columns mapped to one identifier
No collision checkRenaming Email and Email Address both to email produces two email headers. \copy ... HEADER true and most loaders fail on duplicate column names, or silently bind only one. The tool gives no warning — verify the preview header row and use distinct names.
Header starts with a digit
Illegal unquoted2024_revenue is written verbatim, but an identifier starting with a digit is illegal unless quoted in Postgres and MySQL. Type a safe form like revenue_2024. The tool does not rewrite or prefix it for you.
Formulas in the source XLSX
Flattened by designWhen you upload XLSX, formulas are flattened to their computed values during the in-browser CSV round-trip. For a database load this is usually what you want (you load values, not formulas), but be aware the name.renamed.xlsx contains no live formulas and no original number formatting.
Number formatting lost on XLSX round-trip
ExpectedXLSX output is rebuilt from CSV, so a column displayed as $1,200.00 in Excel becomes the raw value. For SQL this is correct — you want 1200.00, not a formatted string. If your source stored currency as text with symbols, clean it with a sibling tool before loading.
Multi-sheet workbook
First sheet onlyOnly the first sheet is read and written. If your workbook has a lookups tab plus a data tab, move the data tab to first position (or save it as its own file) before uploading, or you will rename and export the wrong sheet.
Banner or title row above the real headers
MisreadThe tool treats row 1 as the header row. A report with Q3 Export in row 1 and the real columns in row 2 will list the wrong strings to rename. Delete the banner row in your source first.
Free-tier access
Pro requiredHeader Rename is Pro-gated. Free users can view the page but must upgrade to run it. Pro enforces CSV-family limits (100 MB / 100,000 rows); the Excel hub card advertises the Excel free tier (5 MB / 10,000 rows) for the broader category.
Frequently asked questions
What makes a valid PostgreSQL column name?
Letters, digits, and underscores; it must not start with a digit; and it must not be a reserved keyword unless double-quoted everywhere. Lowercase snake_case starting with a letter (first_name, order_id) is the safest, most portable choice across Postgres, MySQL, and SQLite.
Does the tool auto-convert headers to snake_case for me?
No. There is no auto snake_case generator. You type each target identifier. For SQL this is the right model — only you know whether Order # should map to order_id or order_number, and whether a name collides with a reserved word.
Will the tool warn me about reserved words like 'order' or 'user'?
No. It writes exactly what you type. There is no reserved-word filter, so avoid order, user, select, group, table, etc. by choosing distinct names (order_ref, account_user). Otherwise you will be double-quoting that column in every query.
Does renaming change my data values?
No. Only the header row is rewritten. Numeric, date, and text values pass through unchanged, so they reach COPY / LOAD DATA / .import exactly as exported.
Should I load CSV or XLSX into my database?
CSV is usually simplest for \copy (Postgres), LOAD DATA INFILE (MySQL), and .import (SQLite). The tool gives you CSV out for a CSV upload, or XLSX out for an XLSX upload. If you uploaded XLSX but want CSV, re-upload the CSV form, or use a converter.
What about headers that start with a number, like '2024 Revenue'?
Identifiers can't start with a digit (unquoted) in Postgres/MySQL. Type a safe form such as revenue_2024. The tool stores whatever you type without rewriting it, so the safe naming is up to you.
How do I handle two similar columns like 'Email' and 'Email Address'?
Give them distinct identifiers (email, email_alt). Do not rename both to email — the tool has no duplicate check and your loader will choke on two columns with the same name.
Are formulas preserved if I upload an XLSX?
No. XLSX inputs are flattened to computed values during the in-browser CSV round-trip. For a database load this is what you want — you load the values, not the formulas — but the output XLSX contains no live formulas or original formatting.
Can it rename headers across every sheet in a workbook?
No — only the first sheet is processed. Move your data sheet to first position or save it as its own file before uploading if the workbook has multiple tabs.
Is my data uploaded to a server?
No. Parsing and renaming run entirely in your browser. This matters for SQL prep because the spreadsheet often holds PII destined for a production database — none of it leaves your machine.
Can I automate this in an ETL pipeline?
Yes. GET /api/v1/tools/csv-header-rename returns the schema; pair the @jadapps/runner and POST a renames JSON map keyed by old header name or column index, e.g. {"First Name":"first_name","Order #":"order_id"}. Execution is local and runner-backed. Chain it before your load step in a scheduled job.
What other header cleanup tools pair well with this?
For lowercasing existing names use the case converter; to strip stray special characters from values use the special-character stripper; to trim whitespace across cells use the whitespace trimmer. To turn the cleaned spreadsheet into a CREATE TABLE statement, see JSON to SQL.
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.