You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 1b5e9d7
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/queries.md
+82-16Lines changed: 82 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -429,13 +429,19 @@ named after its column. A value that contains an uncast placeholder, such as
429
429
430
430
### Upsert with `ON CONFLICT`
431
431
432
-
An `INSERT` may end with one conflict clause whose target is a parenthesized
433
-
list of plain column names of the inserted table, followed by one action:
432
+
An `INSERT` may end with one conflict clause that names which conflict it
433
+
handles, followed by one action:
434
+
435
+
| Target | Accepted shape |
436
+
| --- | --- |
437
+
| none | accepted with `DO NOTHING`, which needs no target; `DO UPDATE` requires one |
438
+
| a column list | a parenthesized list of plain column names of the inserted table, with an optional predicate, as in `ON CONFLICT (code) WHERE active`|
439
+
|`ON CONSTRAINT name`| accepted with either action; the name is resolved by PostgreSQL |
434
440
435
441
| Action | Accepted shape |
436
442
| --- | --- |
437
443
|`DO NOTHING`| no assignment, so the statement binds only its `VALUES` row |
438
-
|`DO UPDATE SET`| assignments analyzed exactly as `UPDATE` assignments are, where a value may also be `EXCLUDED.column`|
444
+
|`DO UPDATE SET`| assignments analyzed exactly as `UPDATE` assignments are, where a value may also be `EXCLUDED.column`, with an optional `WHERE` predicate|
439
445
440
446
```sql
441
447
-- name: UpsertAuthor :one
@@ -462,17 +468,57 @@ wherever a cast appears inside the assigned value.
462
468
`EXCLUDED.column` reads the proposed row, and that column must exist in the
463
469
inserted table. An `EXCLUDED` reference inside a larger expression is not
464
470
resolved, as no other computed write value is, so PostgreSQL checks it. sqlcj
465
-
does not match the conflict target against a unique index; PostgreSQL does.
471
+
matches neither the conflict target against a unique index nor a constraint
472
+
name against the schema; PostgreSQL resolves both.
473
+
474
+
Either predicate uses the read predicate forms, and a placeholder in one is
475
+
typed exactly as the same comparison types it in a `WHERE` clause:
476
+
477
+
```sql
478
+
-- name: PublishAuthorIfNewer :optional
479
+
INSERT INTO authors (id, name, version)
480
+
VALUES ($1, $2, $3)
481
+
ON CONFLICT (name) WHERE active DO UPDATE
482
+
SET version =EXCLUDED.version
483
+
WHEREauthors.version<EXCLUDED.version
484
+
ANDauthors.name<> $4
485
+
RETURNING id, name, version;
486
+
```
487
+
488
+
The two predicates read different sources:
489
+
490
+
- a conflict-target predicate reads the inserted table alone, under the name
491
+
that table exposes, which is its alias when the `INSERT` writes one, as in
492
+
`INSERT INTO authors AS a`;
493
+
- a `DO UPDATE ... WHERE` predicate reads both the stored row, under the same
494
+
exposed name, and the proposed row as `EXCLUDED`. Both carry the same
495
+
columns, so an unqualified column compared with a placeholder there is
496
+
ambiguous, as PostgreSQL also reports it; write `authors.version` or
497
+
`EXCLUDED.version`.
498
+
499
+
A placeholder in a conflict-target predicate is typed and bound like any other,
500
+
but PostgreSQL chooses the arbiter index when it plans the statement rather than
501
+
when it runs it, so a parameterized target predicate stops matching a partial
502
+
unique index once the statement is executed under a generic plan and the insert
503
+
then fails. Write a target predicate with literals that imply the index's own
504
+
predicate, as in `WHERE active` or `WHERE active = TRUE`, and keep the
505
+
placeholders in the `DO UPDATE ... WHERE` predicate.
506
+
507
+
Every conflict placeholder binds in the textual order the query writes it, so
508
+
`ON CONFLICT (name) WHERE active DO UPDATE SET bio = $4 WHERE authors.version < $3`
509
+
on a two-value insert binds `$1`, `$2`, `$4`, and `$3` in that order, while each
510
+
generated method parameter keeps its own index.
466
511
467
512
A `DO NOTHING` action writes no row when a conflict occurs, so
468
513
`DO NOTHING ... RETURNING` returns no row on conflict and suits `:optional` or
469
-
`:many` rather than `:one`. A `DO UPDATE ... RETURNING` always returns the row
470
-
it inserted or updated.
514
+
`:many` rather than `:one`. A `DO UPDATE ... WHERE` whose predicate does not
515
+
hold writes no row either, so it returns none as well. A `DO UPDATE` without a
516
+
predicate always returns the row it inserted or updated.
471
517
472
518
Every other conflict form is rejected on every insert, whether `:exec` or
473
-
returning: a missing target, `ON CONFLICT ON CONSTRAINT`, a target element that
474
-
is an expression or carries a collation or an operator class, a conflict-target
475
-
predicate, and `DO UPDATE ... WHERE`.
519
+
returning: a `DO UPDATE` without a target, which is rejected naming the two
520
+
targets it accepts, and a target element that is an expression or carries a
521
+
collation or an operator class.
476
522
477
523
### `RETURNING`
478
524
@@ -863,12 +909,14 @@ name, and its header line.
863
909
as `SET (name, active) = ('a', TRUE)`; and a written column that the table does
864
910
not declare.
865
911
- A conflict clause outside the accepted upsert shape, on an `:exec` and on a
866
-
returning insert alike: `ON CONFLICT` without a target, `ON CONFLICT ON
867
-
CONSTRAINT`, a target element that is an expression or carries a collation or
868
-
an operator class, a conflict-target predicate such as
869
-
`ON CONFLICT (id) WHERE active`, and `DO UPDATE ... WHERE`. A `DO UPDATE`
912
+
returning insert alike: a `DO UPDATE` without a conflict target, which is
913
+
rejected naming the two targets it accepts, and a target element that is an
914
+
expression or carries a collation or an operator class. A `DO UPDATE`
870
915
assignment that sets a column list, and an unknown target, assigned, or
871
-
`EXCLUDED` column, are rejected as the write forms above are.
916
+
`EXCLUDED` column, are rejected as the write forms above are, and so is an
917
+
unqualified conflict-predicate column that both the inserted table and
918
+
`EXCLUDED` carry, or a predicate column qualified with a name its own
919
+
predicate does not read, such as `EXCLUDED` in a conflict-target predicate.
872
920
- An aliased, computed, qualified-wildcard, or unknown `RETURNING` item;
873
921
`RETURNING` on `:exec`; and `UPDATE ... FROM`, `DELETE ... USING`, or a common
874
922
table expression in a returning write.
@@ -889,8 +937,10 @@ them:
889
937
than a placeholder, such as `id = ANY('{1,2}')`,
890
938
- common table expressions, and subqueries outside the `FROM` item,
891
939
-`UPDATE ... FROM` and `DELETE ... USING` on a non-returning `:exec` write,
892
-
- the unique index an accepted `ON CONFLICT` target matches, and the column
893
-
references of an `EXCLUDED` value that is not exactly `EXCLUDED.column`.
940
+
- the unique index an accepted `ON CONFLICT` target matches, the constraint an
941
+
`ON CONSTRAINT` target names, the column references of an `EXCLUDED` value
942
+
that is not exactly `EXCLUDED.column`, and a conflict-predicate column that
943
+
no placeholder is compared with, as in a `WHERE` clause.
894
944
895
945
A clause that is not analyzed still binds the placeholders a cast types inside
896
946
it, in textual order, and nothing else of it is checked. A cast placeholder in a
@@ -1159,6 +1209,22 @@ Writes and `RETURNING`:
1159
1209
executes a `DO NOTHING` and a `DO UPDATE` action, each with and without
1160
1210
`RETURNING`, over a new row and then a conflicting one against
0 commit comments