Oracle · error reference

ORA-01790 on a multi-row MERGE with bind variables

ORA-01790: expression must have same datatype as corresponding expression

Oracle cannot infer a type for a bind variable inside a UNION ALL branch, so a batched MERGE fails on values that all look identical. Why batching causes it and single rows do not.

What the database is telling you

In a UNION ALL, Oracle requires the corresponding columns of every branch to share a datatype. A naked bind variable has no declared type, so Oracle infers one from context — and when the only context is other binds, different branches can be assigned different types. The comparison then fails even though every value you passed was the same kind of thing.

Why it shows up in a migration

It only appears once you batch. Oracle has no ON CONFLICT and no INSERT IGNORE, so a skip-or-upsert load has to be expressed as MERGE, and a multi-row MERGE means USING (SELECT ? FROM dual UNION ALL SELECT ? FROM dual ...). That UNION of bind-only SELECTs is the exact shape that trips the error — which is why the same data loads fine one row at a time and dies in batches of 500.

Common causes

  • A multi-row MERGE whose USING clause is a UNION ALL of bind-only SELECTs.
  • NULL passed in one branch and a value in another for the same column.
  • A mix of str and bytes, or int and Decimal, bound to one column across a batch.

How to fix it

  1. 1

    Cast the binds so every branch has a declared type. Verbose, but it removes the inference entirely.

    USING (SELECT CAST(? AS NUMBER) id, CAST(? AS VARCHAR2(200)) name FROM dual
           UNION ALL
           SELECT CAST(? AS NUMBER), CAST(? AS VARCHAR2(200)) FROM dual) s
  2. 2

    Or keep MERGE single-row and batch with a plain INSERT, falling back to per-row handling only on conflict.

  3. 3

    Normalise values before binding so one column never receives two different types across a batch.

What DBShifts does about it

DBShifts takes the MERGE path only for single-row calls on Oracle. A multi-row batch uses a plain INSERT; if that hits a duplicate key the batch is retried row by row, and each of those single-row calls goes through MERGE and applies the skip or upsert correctly. Full migrations truncate the target first, so the common case stays on the fast path.

Bulk transfer engine

Migrating between engines?

DBShifts converts the schema, moves the data, and then proves the two sides match with a type-aware checksum per table — not just a row count. Errors like this one are handled on the way, and the ones that cannot be handled are reported rather than logged and forgotten.

Related errors

← All database errors