I'm assuming your question is about the query that generates the error message. Please edit your question and make clear what you are asking about if this is not the case, and provide a Minimal, Complete, and Verifiable Example.
To address the query error, define the CTEs in the top level and not in the sub-select:
with s as (
select id, column1, column2
from tag
where column1 = 'key1' and column2 = 'value1'
), i as (
insert into tag (column1, column2)
select 'key1', 'value1'
where not exists (select 1 from s)
returning id
)
insert into tag_attributes (id, hot1, hot2, hot3)
select id, 'var1', 'var1', 'var1'
from i
union all
select id, 'var1', 'var1', 'var1'
from s;
Reference: https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-MODIFYING
That said, for your schema to work as described, tag_attributes.id
should be defined as bigint
and not bigserial
. If, for some reason, you need to add rows to tag_attributes
that don't have a matching row in tag
, change tag.id
to bigint
, create a separate sequence with CREATE SEQUENCE
, and use that to generate IDs for both tables. Otherwise the sequences will collide and chaos will ensue.
EDIT 1
So you want to upsert on tag_attributes
if id
already exists? Just add ON CONFLICT DO UPDATE
to your final INSERT
:
with s as (
select id, column1, column2
from tag
where column1 = 'key1' and column2 = 'value1'
), i as (
insert into tag (column1, column2)
select 'key1', 'value1'
where not exists (select 1 from s)
returning id
)
insert into tag_attributes (id, hot1, hot2, hot3)
select id, 'var1', 'var1', 'var1'
from i
union all
select id, 'var1', 'var1', 'var1'
from s
on conflict (id) do update
set hot1=EXCLUDED.hot1, hot2=EXCLUDED.hot2, hot3=EXCLUDED.hot3;
EXCLUDED
is a magic table name that has the new data, and (id)
specifies which constraint triggers the DO
action (in this case the primary key).
Reference: https://www.postgresql.org/docs/current/sql-insert.html#SQL-ON-CONFLICT