You need to table-qualify the column where it would be otherwise ambiguous.
Use the virtual table name excluded
to refer to the input row. But you probably want to refer to the target column, so qualify with the name of the target table:
INSERT INTO test.test_counter (id)
VALUES ('id-0')
ON CONFLICT (id) DO UPDATE
SET count = test_counter.count + 1 -- here
RETURNING count;
The manual:
Note that the special excluded
table is used to reference values originally proposed for insertion.
The single row from the virtual input table excluded
contains all columns of the target table, even if not listed in the target column list of the INSERT
or the VALUES
expression. So the ambiguity you encountered is always there, whether count
is targeted explicitly or not.
Aside: Columns omitted in the target column list default to their respective column DEFAULT
value, which is NULL
by default (NULL
being the default column DEFAULT
). I.e., it would default to NULL
in your setup and 1
in my improved setup below. And row-level triggers BEFORE INSERT
(if any) are applied.
But neither of that applies for the example as it refers to the target column after all.
Notably, the other two instances of the column name count
are unambiguous (and thus do not require table-qualification) as those can only refer to the target table.
Your setup can easily break while the column count
isn't defined NOT NULL
, as NULL + 1
is still NULL
. This setup would make more sense:
CREATE TABLE test.test_counter (
id text PRIMARY KEY
, count integer NOT NULL DEFAULT 1
);
Also not using quoted CaMeL-case names in my example. See: