问题
Suppose I have the following table:
CREATE TABLE tags (
id int PK,
name varchar(255),
CONSTRAINT name_unique UNIQUE(name)
)
I need a query that will insert tags that do not exists and return ids for all requested tags. Consider the following:
INSERT INTO tags (name) values ('tag10'), ('tag6'), ('tag11') ON CONFLICT DO NOTHING returning id, name
The output of this query is:
+---------------+
| id | name |
|---------------|
| 208 | tag10 |
|---------------|
| 209 | tag11 |
+---------------+
What I need is to have tag6 in the output.
回答1:
A bit verbose, but I can't think of anything else:
with all_tags (name) as (
values ('tag10'), ('tag6'), ('tag11')
), inserted (id, name) as (
INSERT INTO tags (name)
select name
from all_tags
ON CONFLICT DO NOTHING
returning id, name
)
select t.id, t.name, 'already there'
from tags t
join all_tags at on at.name = t.name
union all
select id, name, 'inserted'
from inserted;
The outer select from tags sees the snapshot of the table as it was before the new tags were inserted. The third column with the constant is only there to test the query so that one can identify which rows were inserted and which not.
回答2:
With this table:
CREATE TABLE tags (
id serial PRIMARY KEY,
name text UNIQUE
);
As long as the values inside the query is unique a workaround for this is:
INSERT INTO tags (name)
VALUES ('tag10'), ('tag6'), ('tag11')
ON CONFLICT DO UPDATE name = EXCLUDED.name RETURNING id, name;
来源:https://stackoverflow.com/questions/35265453/use-insert-on-conflict-do-nothing-returning-failed-rows