#30489·Prisma

SQL builder: an update cannot set a column from a subquery or a joined table, so filling a foreign key in a data migration must be raw SQL

Author: wmadden-electricCreated Sep 29, 2026Updated Sep 29, 2026
Labelskind/bug

What happened

A data migration needs to fill a new foreign-key column from a lookup: UPDATE ask SET "provenanceActorRef" = (SELECT id FROM actor WHERE actor."contactId" = ask."provenanceActorId" AND actor.kind = 'human'). The typed SQL builder cannot express it, either as a scalar subquery in SET or as UPDATE ... FROM.

Reproduction

Versions: @prisma/orm-postgres 8.0.0-rc.12. Checked against the source of main at d136137 (2026-09-28).

typescript
sql.public.ask.update((f) => ({
  provenanceActorRef: sql.public.actor
    .select('id')
    .where((a, fns) => fns.and(fns.eq(a.kind, 'human'), fns.eq(a.contactId, f.provenanceActorId))),
}));

tsc fails: TS2769: No overload matches this call, Property 'returnType' is missing in type 'SelectQuery<...>'. A select is not an expression.

typescript
sql.public.ask.update({ provenanceActorRef: null }).from(sql.public.actor);

tsc fails: TS2339: Property 'from' does not exist on type 'UpdateQuery<...>'.

Cause

  • UpdateAst.set in packages/2-sql/4-lanes/relational-core/src/ast/types.ts is Record<string, AnyExpression>, and SubqueryExpr is already an Expression in the same file. fns.in builds one (sql-builder/src/runtime/functions.ts), and relation ordering renders correlated scalar subqueries (ADR 255). So the AST can carry a scalar subquery in SET; the builder has no public function that turns a one-column select into a value expression.
  • UpdateQuery in sql-builder/src/types/mutation-query.ts has no from.

What was expected

One of: a function such as fns.scalar(select) that makes a one-column, at-most-one-row select into an expression typed by that column, usable in update and where; or UpdateQuery.from(table) with the joined table's fields in scope of set and where.

Why it matters

Filling a new foreign key from existing text is the common case of a data migration. Without this it has to be raw SQL, which the migration guide says not to write, because nothing checks it against the contract.