patternsqlMajor
UPSERT with ON CONFLICT using values from source table in the UPDATE part
Viewed 0 times
theupdatewithsourcepartupsertusingconflictvaluesfrom
Problem
Given:
This query:
causes the following error:
How to do the update while referring to content of
CREATE TABLE A (
PK_A INT8 NOT NULL,
A INT8,
PRIMARY KEY (PK_A)
);
CREATE TABLE B (
PK_B INT8 NOT NULL,
B INT8,
PRIMARY KEY (PK_B)
);This query:
insert into table_b (pk_b, b)
select pk_a,a from table_a
on conflict (b) do update set b=a;causes the following error:
ERROR: column "a" does not exist
LINE 1: ...elect pk_a,a from table_a on conflict (b) do update set b=a;
^
HINT: There is a column named "a" in table "*SELECT*", but it cannot be referenced from this part of the query.How to do the update while referring to content of
table_a?Solution
Multiple problems.
Your setup, extended:
This works:
Result:
The problems
-
You are confusing
Using legal, lower-case, unquoted identifiers helps to avoid confusion.
-
Like @Ziggy mentioned,
The optional
Consequently,
-
Like @Ziggy also mentioned, source table names are not visible in the
The
to the existing row using the table's name (or an alias), and to
rows proposed for insertion using the special
Bold emphasis mine.
-
You also cannot use column names of the source table in the
The manual once more:
Note that the effects of all per-row
reflected in excluded values, since those effects may have contributed
to the row being excluded from insertion.
Your setup, extended:
CREATE TABLE a (
pk_a int PRIMARY KEY
, a int
, comment text -- added column to make effect clear
);
CREATE TABLE b (
pk_b int PRIMARY KEY
, b int
, comment text
);
INSERT INTO a VALUES (1, 11, 'comment from a')
, (2, 22, 'comment from a');
INSERT INTO b VALUES (1, 77, 'comment from b');This works:
INSERT INTO b (pk_b, b, comment)
SELECT pk_a, a, comment
FROM a
ON CONFLICT (pk_b) DO UPDATE -- conflict is on the unique column
SET b = excluded.b; -- key word "excluded", refer to target columnResult:
TABLE b;
pk_b | b | comment
------+----+----------------
1 | 11 | comment from b -- updated
2 | 22 | comment from a -- insertedThe problems
-
You are confusing
table_a and A in your demo (like @Abelisto commented).Using legal, lower-case, unquoted identifiers helps to avoid confusion.
-
Like @Ziggy mentioned,
ON CONFLICT only works for actual unique or exclusion constraint violations. The manual:The optional
ON CONFLICT clause specifies an alternative action to raising a unique violation or exclusion constraint violation error.Consequently,
ON CONFLICT (b) cannot work, no constraint there. ON CONFLICT (pk_b) works.-
Like @Ziggy also mentioned, source table names are not visible in the
UPDATE part. The manual:The
SET and WHERE clauses in ON CONFLICT DO UPDATE have accessto the existing row using the table's name (or an alias), and to
rows proposed for insertion using the special
excluded table.Bold emphasis mine.
-
You also cannot use column names of the source table in the
UPDATE part. It must be column names of the target row. So you really want:SET b = excluded.bThe manual once more:
Note that the effects of all per-row
BEFORE INSERT triggers arereflected in excluded values, since those effects may have contributed
to the row being excluded from insertion.
Code Snippets
CREATE TABLE a (
pk_a int PRIMARY KEY
, a int
, comment text -- added column to make effect clear
);
CREATE TABLE b (
pk_b int PRIMARY KEY
, b int
, comment text
);
INSERT INTO a VALUES (1, 11, 'comment from a')
, (2, 22, 'comment from a');
INSERT INTO b VALUES (1, 77, 'comment from b');INSERT INTO b (pk_b, b, comment)
SELECT pk_a, a, comment
FROM a
ON CONFLICT (pk_b) DO UPDATE -- conflict is on the unique column
SET b = excluded.b; -- key word "excluded", refer to target columnTABLE b;
pk_b | b | comment
------+----+----------------
1 | 11 | comment from b -- updated
2 | 22 | comment from a -- insertedSET b = excluded.bContext
StackExchange Database Administrators Q#134493, answer score: 46
Revisions (0)
No revisions yet.