shipwithjev

Blog / 24

Natural Language Database Queries: WHERE jev(people, 'could work from home')

A Postgres extension puts an AI judge inside the WHERE clause: natural language filters over real rows, 129 rows a second. How it works, where it belongs.

Most "chat with your database" products share a quiet architecture and a quiet flaw: an LLM translates your English into SQL, the SQL runs, and you pray the translation matched your intent. Text-to-SQL is genuinely useful and genuinely brittle, and it answers only questions your columns already encode. Ask it "which of these people could plausibly work from home?" and it can only shrug or guess at a proxy column, because no schema has a could_wfh boolean.

One of the strangest builds in the directory attacks the problem from the opposite end. Instead of AI writing the query, AI lives inside it: a PostgreSQL extension exposing a function that judges rows, so the filter itself understands English. The demo query is the whole pitch:

-- as demonstrated in the build; illustrative of the pattern
SELECT * FROM people WHERE jev(people, 'could work from home');

Per the author's reported numbers, it judged 129 rows in about a second (build). Each row gets shipped to Jev as a yes/no question; the boolean comes back into the query plan; SQL proceeds as if nothing philosophical just happened.

Why this works at all (and only now)

A semantic filter in a WHERE clause means one model call per row per query. With frontier pricing and latency, that sentence is a joke; a 10,000-row scan would cost dollars and minutes. At decision-model speed and reported fractions-of-a-cent verdicts, it becomes merely expensive-ish, and on hundreds-to-thousands of rows, genuinely casual. The database function is the purest possible demonstration of structured outputs: SQL will not accept an essay, so the model's native boolean is the only thing that could ever sit in that clause.

Where semantic filters actually belong

Not in your hot path, and the build's own shape tells you so. The honest placement:

Analyst queries over modest sets. "Which support tickets sound like churn risk?" across this week's table; "which signups describe a real use case?" over yesterday's batch. Human-speed questions on human-scale row counts, where a one-second, sub-cent scan replaces an export-to-spreadsheet afternoon.

Enrichment pipelines, not live filters. For anything repeated or large, run the judgment once, materialize it (ALTER TABLE ADD COLUMN wfh_plausible bool, backfill via the function, refresh on change), and let every subsequent query hit an indexed boolean for free. Semantic judgment as a batch job that produces columns, which is really AI data labeling wearing a DBA badge.

Fuzzy joins and dedup assists. "Are these two records the same merchant?" is a judge question older than the industry, and per-pair verdicts price it honestly at last.

The anti-patterns are just as clear: unbounded scans (WHERE jev(...) on ten million rows is a money-and-minutes bonfire; always bound the candidate set with cheap predicates first), user-facing latency paths, and anything where nondeterminism hurts, because a model verdict can flip on re-ask in a way WHERE age > 30 never will. Cache verdicts, version your question text, and treat the function as an oracle you consult, not an index you trust.

The bigger pattern

The Postgres build travels because it collapses a stack: no orchestration layer, no export step, no glue service, just a judgment where the data already lives. Expect the shape everywhere data sits: semantic filters in dataframes, judge steps in dbt models, verdict columns in warehouses. "The database understands English now" is oversold; "the database can ask something that does for a cent" is exactly right, and apparently that's enough.

Frequently asked questions

What are natural language database queries?

Either AI translating English into SQL (text-to-SQL) or, as here, AI judgments embedded inside queries so filters themselves evaluate meaning. The two compose: one writes the query, the other powers the fuzzy predicate.

How is this different from text-to-SQL?

Text-to-SQL only reaches what your columns encode; a semantic filter creates judgments your schema never stored. It answers "which rows mean X" rather than "which rows match X."

Isn't a model call per row expensive?

Per reported numbers, about a second and pocket change for low hundreds of rows, fine for analyst work, wrong for big scans. The professional move is judge-once-materialize-a-column, then query the column forever.

Are the results deterministic?

No; verdicts can vary across runs, unlike ordinary predicates. Pin question wording, cache results, and keep semantic filters out of anything requiring reproducible row sets, or materialize and audit like any labeled dataset.

Can I try this pattern outside Postgres?

The shape ports anywhere you can call a function per record: dataframes, ETL steps, spreadsheet scripts. Start with a few hundred rows you know well and score the verdicts, per the getting-started guide.

Numbers throughout are as reported by the build authors, not verified by shipwithjev. Code-shaped examples are pseudocode; the official docs live at docs.typesafe.ai.