Skip to main content
Plexara
Philosophy9 min read

501 - The last mile of data is a spreadsheet

The join was never the expensive part of using an outside file. Loading it was, and loading was staffed: a ticket for the table, an engineer for the load, an integration platform somebody had to keep. A chat agent does not close that gap on its own, because a large file does not fit its context and the scripts it writes vanish with the session. This lesson sets out the gap, the registration model that closes it (a table over the file where it sits, nothing copied), and the size rule for when a file needs no table at all.

What you will take away from this lesson

Once a month a supplier emails a price sheet. It has four hundred rows: a SKU, a unit cost, a minimum order quantity, an effective date. Every number in it matters only next to something you already have. What did we pay last month, what do we sell it for, how many did we move. The join is the whole point, and the join is easy. What has never been easy is getting the file into a place where the join can happen.

This lesson is about that gap. It is the most expensive step in everyday data work, it is staffed by people who are not the person holding the file, and an AI agent in a chat window does not close it on its own. The rest of the series is about what closes it.

Learning Objectives

  1. 01Recognize that the cost of an outside file was never the join; it was the loading, and the loading was staffed.
  2. 02Describe the traditional path from a file in an inbox to a table in the warehouse (a ticket, a table, a load job, an integration platform, weeks) and the expertise each step requires.
  3. 03Explain why a chat agent does not close the gap on its own: the file does not fit its context, it needs the file on a local disk, the scripts it writes vanish with the session, and nothing reaches the rest of the team.
  4. 04State the registration model: a table created over the file where it sits, nothing copied, the header row becoming the columns.
  5. 05Apply the size rule: a few hundred keys join inline through a VALUES list; registration is for the file that is too big for that.

What arrives by email

Most of the data a business runs on is in its warehouse. A surprising share of the data it decides on is not. It arrives as an attachment: a price sheet from a supplier, a lease schedule from the real-estate team, a list from an agency, a rebate schedule from a vendor. These files are small, they come on a cadence, and they were produced by somebody else’s system, which is why they are not already in yours.

They have one thing in common. On their own they say almost nothing. A unit cost means something only next to the cost of record and the shelf price; a lease means something only next to the store’s revenue. The file is valuable exactly when it is joined, and it is stranded exactly because joining it was somebody else’s job.

Files that are valuable exactly when joined

A supplier price sheet, monthly, by SKU
The product catalog’s cost of record and shelf price, and the month’s unit sales.
A lease schedule from the real-estate team, by store
Store revenue, so occupancy cost can be read as a share of sales.
A marketing list from an agency, by customer email
The customer file and loyalty tier, so a campaign can be measured against spend.
A vendor rebate list, by store and quarter
Purchase volume by store, so the rebate can be checked before it is paid.

None of these files is interesting on its own. Each one answers a question only when it is next to a warehouse table, and each one usually stays in the inbox because putting it next to that table was a project.

The staffed path

The conventional way to get an outside file next to a warehouse table is to make it a warehouse table. That is a project with a cast: a database administrator to create the table and decide its types, an engineer to write the load and handle the file’s quirks, and, for anything that recurs, an integration platform (Workato, n8n, and Apache NiFi are the category) that automates the flow and needs a platform expert to build and keep it. Each step is reasonable. Each step is also a handoff, and the analyst who received the file waits on all of them.

For a feed that arrives every hour and has to be typed, validated, and monitored, that investment is correct. For a monthly sheet with four hundred rows it never pays back, so the sheet does not get loaded. It gets joined by hand in a spreadsheet, the answer lives on one laptop, and next month the same person does it again.

Two ways an outside file reaches the warehouse

Who is involved
The staffed pathThe analyst files a ticket. A database administrator creates the table. An engineer writes the load. A platform expert builds and keeps the flow in the integration platform.
RegistrationThe person holding the file, and their agent. Nobody else is needed, and nobody else is waiting on.
What is built
The staffed pathA destination table with declared column types, a staging area, a load job, a schedule, and monitoring for when the file’s shape changes.
RegistrationA table over the file where it already sits. Nothing is copied, nothing is loaded, and the header row supplies the columns.
Elapsed time
The staffed pathDays to weeks, most of it waiting for the next person in the chain.
RegistrationMinutes, in the same session the file was uploaded.
When the file changes shape
The staffed pathThe load breaks, and the ticket is reopened.
RegistrationRegister the new file. The columns are read from its header again.
Who can use the result
The staffed pathEveryone, once it lands. It rarely lands for a one-off file.
RegistrationEveryone granted the connection, from the moment it is registered, by name in ordinary SQL.

The staffed path is the right one for a feed that arrives every hour and has to be typed, validated, and monitored. A one-off file, or a monthly sheet with four hundred rows, never earns that setup, so it gets joined by hand in a spreadsheet instead, and the answer stays on one laptop.

The agent without help

It is tempting to assume an AI agent makes this problem go away. It does not, not on its own. A conversation is a poor place to keep a file, a worse place to load one, and no place at all to run a join against seven million line items. The workarounds people reach for reproduce the old problem in a new form: the file goes on a laptop, the agent writes a script to parse it, the script runs once and is gone.

Why a chat agent does not close the gap on its own

  • The file does not fit

    A 100 MB CSV is millions of tokens. It cannot be pasted into a conversation, and an agent that reads it in pieces cannot hold enough of it at once to join it against anything.

  • The work happens on a laptop and vanishes

    The usual workaround is to give the agent the file on local disk and permission to write scripts that parse it. The scripts are temporary. They run once, under one person’s credentials, and disappear with the session, so next month starts from zero.

  • Nobody else gets anything

    A colleague who needs the same join tomorrow cannot find the file, the script, or the answer. What one person taught their agent stays with that person.

The agent is not the problem. It is being asked to be the storage, the loader, and the query engine at once, and a conversation is the wrong shape for all three.

Registration, not ingestion

The fix is to stop treating the file as something to be moved. Upload it once, to a library where it has an owner, a description, and a version history, and then register it: ask the platform to create a table over the file where it already sits. The header row becomes the column list. From that moment the file is a table in ordinary SQL, beside the warehouse, for everyone granted the connection.

The agent does the registering in one call, and the platform answers with the table’s name, its columns, and a sample statement. There is nothing to design and nothing to schedule. A file that would have waited weeks on the staffed path is joinable in the session it arrived in.

The size rule

Not every outside list needs a table. A handful of store ids somebody pasted into the chat, or a few hundred SKUs from an email, join inline: the agent writes them into a VALUES list and runs one statement. That is faster than registering anything, and it leaves nothing behind to clean up.

Registration is for the file that is too big for that: the one where writing the rows into a statement would be slow, would fill the conversation with data instead of reasoning, and would have to be done again by every person who needed the same join.

The size rule: a short list needs no table

SELECT s.store_id, s.store_name, r.rebate_pct
FROM warehouse.public.stores s
JOIN (VALUES ('412', '2.5'), ('418', '3.0'), ('433', '2.5')) AS r (store_id, rebate_pct)
  ON CAST(s.store_id AS varchar) = r.store_id

A handful of ids, or a few hundred, join inline: the agent writes them into a VALUES list and runs one query. Registration is for the file that is too big for that, where writing the rows into a statement would be slow and would burn the conversation’s context on data. The four-hundred-row price sheet is at the boundary; a fifty-thousand-row one is well past it.

What the series covers

The next four lessons follow one file through its life: uploaded and registered, explained to the agent, joined and turned into a shared dashboard, and replaced when the next month’s version arrives. Every figure in them comes from a real run on the demo tenant.

Key terms

Five terms carry the series. Two name the kinds of stored file, and three describe what registering one does.

Key Terms

Managed resource
A file a person uploads to the resource library: a price sheet, a template, a reference document. It has a description, a category, tags, a version history, and a scope that decides who sees it.
Asset
A file the agent saved: a dashboard, a report, an exported CSV. Covered in the 300 series. A CSV asset registers as a table the same way a CSV resource does.
Registration
The act of making a stored CSV queryable: the platform reads the header row, creates a table over the file where it sits, and records who registered what on which connection. A pointer and a name, not a copy.
Scratch schemascratch.uploads
The shared working schema on the connection named scratch where registered tables live. Everyone granted the connection can read every table in it, and table names carry the registering persona as a prefix.
External table
A table whose data is not stored by the query engine but read from files at a location the engine is pointed at. A registered table is one; dropping it removes the catalog entry and leaves the file untouched.