Skip to main content
Plexara
Field notes / product

The spreadsheet that joins your warehouse

Ad-hoc CSVs are the most common data silo in business: valuable exactly when joined, stranded in inboxes because loading them was a project. Plexara registers an uploaded CSV, or one an agent built, as a queryable table over the file where it sits, so the join runs in the warehouse instead of the context window.

9-minute readProduct

The most common silo in business

The vendor sends a rebate schedule by email every quarter. The real-estate team keeps the lease costs for every location in a spreadsheet. An agency delivers a target list as an attachment, and a SaaS tool nobody ever integrated offers its records only as an export. Every business runs on files like these, and each becomes useful when it is joined against the data the company already has.

Getting the file somewhere joinable has always been the obstacle. The standard path ran through a request to data engineering, a staging table, and a loader that somebody now owns for a file that changes quarterly, or once. For a file needed one time, nobody files that ticket. So the analysis happens by hand in a spreadsheet, against an export that was stale before the lookup finished, or it does not happen.

Plenty of software accepts a CSV upload, which is how the problem usually hides. A BI tool takes the file and makes it a dataset its own dashboards can see. A campaign tool takes it and makes it an audience. The upload succeeds, and the silo has moved into a different product. What none of that produces is the file sitting beside the warehouse as a peer: one more table, in the same SQL, under the same governance.

What an agent does with a CSV, without help

Hand the same file to an AI agent and its first instinct is to read it. Reading means the whole file passes through the context window, so a three-hundred-row spreadsheet costs thousands of tokens before the first question is asked, and a fifty-thousand-row vendor file does not fit at all. Whatever the agent concludes, the spend repeats next session, because nothing durable came of it.

The workarounds are worse. An agent can fetch both sides and match rows in prose, which performs the join inside the model itself, token by token, with an error rate that grows with the row count. Or it can dribble the file into a database as batches of INSERT statements, which is slow, needs write access to somewhere, and leaves a half-loaded table when the session ends early.

A short list of keys needs no table at all: a handful of pasted ids joins inline as a VALUES clause through an ordinary read-only query, and Plexara tells the agent so. Registration is for files with hundreds or hundreds of thousands of rows, where the join belongs in a query engine.

CSV handling, with and without a registered table

Whole file in context

The file goes through the context window

  • The agent reads the whole file into context, spending tokens on every row
  • Joins happen agent-side: fetch both sides, match them in prose
  • A fifty-thousand-row file does not fit at all
  • The work is not repeatable: next session, same parsing, same spend

Register once, query by name

The file becomes a table

  • One registration makes the file queryable where it sits
  • The join runs in the query engine, and only the answer reaches the agent
  • Row count stops mattering: 300 rows or 300,000 query the same way
  • Search returns the table name and a sample join on the file from then on

Registration, not ingestion

Files reach Plexara two ways. A person uploads reference material into the portal, where it becomes a managed resource with versions, scoping, and usage tracking. Or an agent saves something it built as a portal asset: an export from a warehouse query, a dataset assembled from gateway API calls, a working file another tool produced. Either kind of CSV can be registered as a table.

Registration is deliberately not ingestion. The platform reads the file, takes column names from its header row, and creates an external table over the object where it already sits, in a scratch schema set aside for working tables. Nothing is copied, no pipeline is scheduled, and no storage is doubled. Under the surface this is Trino reading CSV through its Hive support, directly against the same object store that holds the platform’s files; to the person or agent doing the registering, it is one action with a table name as the answer.

From that moment the file and the table are linked. A search that finds the file returns the registered table’s name and a sample join on the same hit, so an agent that finds the file later starts from SQL rather than from the loading problem. And because the table reads the object in place, a vendor drop that overwrites its file changes the next query’s answer with no further action from anyone.

Registration flow

1 · A file lands

A person uploads it to the resource library

Or an agent saves one it built as an asset

store_lease_costs_fy2026.csv

store_id,annual_base_rent_usd,annual_cam_usd,lease_end

1,78900,11800,2026-04-01

2,50700,8500,2027-05-01

3,65100,14100,2030-01-01

2 · One registration

The platform reads the file, takes column names from its header, and creates an external table over the object where it already sits. Nothing is copied and no pipeline runs.

  • Columns come from the header row
  • The table name carries your persona
  • An audit event records who and what

3 · Queryable beside everything

scratch.uploads.store_lease_costs

JOIN · ON store_id

warehouse.public.stores
warehouse.public.transactions

The file reads as rows in the same SQL surface as the warehouse, so the join is one statement and only its answer spends tokens.

A registration is a pointer and a name, not an import. The object never moves: the table reads the file where it lives, so a vendor drop that overwrites its file changes the next query's answer with no further action.

A worked example: lease costs against revenue

Everything in this section ran on a live Plexara deployment, the demo environment seeded with a 303-store retail chain, while the article was being written. The file is the classic case: a FY2026 lease schedule, one row per store, carrying annual base rent, common-area maintenance charges, and the lease end date. It is exactly the spreadsheet a real-estate team keeps and a warehouse never sees.

The agent saved the schedule as a portal asset and registered it with a single call. The response below is complete: the table name, the columns read from the header, and the one fact worth knowing before writing SQL, which is that a CSV’s columns arrive as VARCHAR and join to typed warehouse columns through a cast.

Registration call and response

manage_table action=register reference=mcp:asset:eda2a7a0… connection=scratch

query_table
scratch.uploads.admin_store_lease_costs
columns
store_id · annual_base_rent_usd · annual_cam_usd · lease_end
connection
scratch
stale
false
note
Every column is VARCHAR, so a join to a typed column needs a CAST.
The actual response from a registration made on the Plexara demo deployment on 2026-08-23. The 303-row lease schedule had been saved as a portal asset moments earlier; this was the only call between the saved file and SQL. The name carries the registering persona, because the scratch schema is shared.
Plexara asset viewer showing a CSV asset with its Query as a table panel: the registered table, its columns, and the control to drop it
The same surface in the portal. A CSV asset's page carries a Query as a table panel: pick a connection, optionally name the table, and the columns come back with the registration. The panel also shows what is already registered and who registered it.

The join

The file exists to answer one question: which stores pay rent out of proportion to what they sell. That is a three-way join, lease costs against the store dimension against a year of transactions, and with the registration in place it is one statement.

The chain’s median store spends 12.8 percent of revenue on occupancy. Twenty stores sit above 25 percent, five above 30, and the worst, a Springfield, California store, pays $143,800 in occupancy against $340,536 in revenue, 42.2 percent, with the lease up for renewal in June 2026.

Two things did not happen: the file never entered the context window, and the agent never read the source rows. It read eight result rows, because the query engine did the work and only the answer traveled. The statement is recorded, the result was saved as an asset with its provenance attached, and when next quarter’s schedule arrives, the same join runs against it.

The join

WITH revenue AS (
  SELECT store_id, SUM(total) AS revenue_2025
  FROM warehouse.public.transactions
  WHERE transaction_date >= DATE '2025-01-01'
    AND transaction_date <  DATE '2026-01-01'
  GROUP BY store_id
)
SELECT s.store_name, s.city, s.state,
       CAST(l.annual_base_rent_usd AS integer)
     + CAST(l.annual_cam_usd AS integer) AS occupancy_cost,
       ROUND(100.0 * (CAST(l.annual_base_rent_usd AS integer)
     + CAST(l.annual_cam_usd AS integer)) / r.revenue_2025, 1) AS occupancy_pct
FROM scratch.uploads.admin_store_lease_costs l
JOIN warehouse.public.stores s ON s.store_id = CAST(l.store_id AS integer)
JOIN revenue r ON r.store_id = s.store_id
ORDER BY occupancy_pct DESC
Store2025 revenueOccupancy costShareLease ends

Store #36

Springfield, CA

$340,536$143,80042.2%Jun 2026

Store #292

Ashland, WA

$362,966$149,60041.2%May 2028

Store #211

Manchester, OH

$415,759$152,60036.7%Nov 2026

Store #138

Kingston, MA

$462,066$145,60031.5%Oct 2029

Store #128

Bristol, MD

$304,314$95,70031.5%Nov 2029
The statement and its worst five rows, run live against the demo deployment on 2026-08-23. Registered columns arrive as VARCHAR, a rule of the storage format, so joins to typed columns cast; the registration response includes a sample join showing the cast.
303

Rows in the lease spreadsheet, registered as a table in a single call

One file, one registration

12.8%

Median share of revenue the chain pays in rent and common-area charges

Registered CSV joined to 2025 revenue

5

Stores whose annual rent and CAM exceed 30 percent of 2025 revenue

Registered CSV joined to 2025 revenue

Versions, staleness, and refused files

A registered table serves the content that was current when it was registered. Every edit to a portal asset and every revision of a managed resource writes a new version, and a table that silently followed the newest version would change the results of any report built on it. So the table stays put, and everywhere the registration appears, the portal panel, the file’s search hit, the agent’s own listing, it is flagged as stale until someone registers again, which takes the table forward in one step. A file overwritten in place, the shape of a recurring vendor drop, needs no re-registration at all.

Registration also refuses files a line-based query engine would misread. A spreadsheet export with line breaks inside quoted cells is legal CSV under RFC 4180 and parses cleanly in every ordinary reader, but a line-based reader would tear each such row into fragments and return them as rows without any error. Plexara reads the whole file before creating anything, names the specific problem, and offers a correction: one control that writes a repaired version through the file’s own version trail, with the original preserved beneath it, and registers the result.

The governance is the same as everywhere else on the platform. Every registration writes an audit event, including the failed attempts. Registering requires the authority to change the file, not merely read it, because a registered table is readable by everyone granted the connection; the table name carries the registering persona so a shared schema stays legible; and dropping a table belongs to the person who registered it, or an administrator. Deleting the file takes every table registered over it along.

Plexara resource dialog showing a registered table marked stale because the file has a newer revision than the one the table serves
A registration the file has moved on from. The table keeps answering with the revision it was registered against, which is correct SQL and still behind, so every surface that shows the registration says so. Registering again, same connection and name, moves it forward. Nothing moves it forward silently.
Plexara resource dialog refusing to register a CSV whose cells contain line breaks, naming the affected rows and offering a one-control correction
A CSV the query engine cannot read as stored: line breaks inside quoted cells would tear rows into fragments in a table that reported no error. Registration reads the whole file first, refuses with the specific problem, and offers the correction, which writes a fixed version through the file's own version trail and registers that.

The gap this closes

The gap sits between the warehouse and the agent, where ad-hoc data lives: the attachments, the exports, the schedules, the lists. Those files used to face a choice between an engineering project and a silo. Now the path is upload, register, join, and it works in both directions, for the spreadsheet a person brings to the platform and for the dataset an agent assembles out of API calls and saves as an asset.

This does not replace pipelines, and is not trying to. Data that arrives on schedule at volume belongs in the warehouse proper, modeled and owned. The scratch schema is a working space, not a modeling layer: it is where a quarter’s analysis meets a quarter’s file. What it replaces is the ticket that was never worth filing, the one-off loader nobody wanted to own, and the analyst afternoon lost to a lookup formula.

A registered table is a pointer and a name. It puts the most common file in business on the same governed, queryable surface as everything else, the day the file arrives.