Moving a Google Sheet into a database without breaking it
The import is the easy part. The work is deciding which columns were secretly two tables, which were types pretending to be text, and which formulas should stop being formulas. A practical order of operations.
Uploading the CSV takes a minute. The reason people bounce off this is everything that happens next: the sheet arrives intact and wrong, because a spreadsheet stores decisions a database wants stated explicitly.
Here's the order that avoids the rework.
Before you import: three questions about the sheet
1 · Which columns are actually a second table?
This is the big one, and it's usually the only real work.
If your sheet has Client name, Client email and Client phone repeated on
every row, those three columns aren't columns — they're a Clients table
you've been storing a copy of on every line. Ten bookings for the same client
means ten copies of their email, and ten chances for one of them to be the old
one.
Look for any group of columns that repeat together and always change together. Each group is a table, and the original sheet becomes a table that links to it.
2 · Which columns are a type pretending to be text?
Scan for columns where every value is drawn from a small fixed set — Status
with Pending / Confirmed / Cancelled, Priority with High / Medium / Low. Those
want to be single-select fields, not text. The moment they are, filtering is
exact, colouring is possible, and nobody can type "Confimed".
Dates deserve their own look. A spreadsheet column that displays as a date may hold text in some rows — the ones somebody typed by hand, or pasted from an email. Sort the column: text and real dates sort differently, and the strays group together at one end where you can see them.
3 · Which formulas should stop being formulas?
Three different answers, and choosing right is what stops your data drifting:
- Arithmetic on the same row (
= nights * rate) stays a formula. - A VLOOKUP into another sheet becomes a link plus a lookup — you're not computing anything, you're pointing at a record.
- A SUMIF over many rows becomes a rollup on the other side of that link. (There's a longer version of this in lookup vs rollup.)
- A number that must never change — the price you actually charged, on the day you charged it — stops being derived at all and becomes a plain stored value. Recomputing history is not a feature.
Clean these five things first
Faster in the sheet than after the import, every time:
- One header row. Delete the title row above it, the merged cells, the blank spacer row. An importer reads row 1 as your field names.
- No totals row at the bottom. It'll arrive as a record with the word "TOTAL" in the name column. That belongs to a view, not the data.
- Nothing to the right. Notes parked in column P become a field.
- No blank rows in the middle. They import as empty records.
- One sheet, one thing. If a tab holds two tables stacked with a gap, split them before exporting.
Then import
File → Download → Comma-separated values, one tab at a time. Our importer reads CSV and Excel, reads the header row as field names, guesses each column's type, and shows you every guess before it creates anything.
You can change any guess in that preview — each column has a type selector, and you can also rename it, map it onto an existing field, or skip it entirely.
Check the guesses. The ones that go wrong most often are:
- A reference like
CM-1041guessed as text — correct — versus one like001042where leading zeros matter and a number type would eat them. - A column of
Yes/Nothat you'd rather have as a checkbox.
On dates written with slashes, read this bit twice. A column like
03/04/2026 is genuinely ambiguous, and the importer resolves it month-first
— so 03/04/2026 is read as 4 March, not 3 April. If your sheet uses the
day-first convention, either reformat the column to YYYY-MM-DD in the
spreadsheet before exporting (the unambiguous form, and the one we'd recommend
regardless), or import the column as text and convert it after.
There's a second, stranger consequence worth knowing: a day-first column
containing any date past the 12th of a month — 13/04/2026 — fails to parse as
month-first, so the whole column is treated as text rather than dates. That
failure is at least visible. The one to watch for is a column where every day
happens to be 12 or lower, which imports silently, as the wrong dates.
Then build the links
Import the second table (Clients, Suppliers, whatever the repeated columns became), then change the text column on the first table into a link field pointing at it. Matching happens on the display value — which is exactly why duplicates and spelling variants have to be cleaned in the sheet first. "Acme Ltd" and "Acme Ltd." are two records here, same as everywhere else.
Then delete the now-redundant copied columns. That deletion is the moment the sheet stops being a sheet.
What you get for the afternoon
The columns can't drift type. The client's email exists once. A view replaces every duplicated tab. Other software can read it over an API instead of screen-scraping a share link. And you can still get a CSV back out any day you like — the whole database, one file, which is the part worth confirming before you start rather than after.
If none of that sounds like your week, the sheet is still doing its job — the six signs it has stopped are the thing to watch for.