The reason PostgreSQL doesn't do this is related to how it implements constraints and validation. When a constraint fails it causes a transaction abort. The transaction is in an unclean state and cannot be resumed.
It is possible to create a new subtransaction for each row but this is very slow and defeats the purpose of using COPY
in the first place, so it isn't supported by PostgreSQL in COPY
at this time. You can do it yourself in PL/PgSQL with a BEGIN ... EXCEPTION
block inside a LOOP
over a select from the data copied into a temporary table. This works fairly well but can be slow.
It's better, if possible, to use SQL to check the constraints before doing any insert that violates them. That way you can just:
CREATE TEMPORARY TABLE stagingtable(...);
\copy stagingtable FROM 'somefile.csv'
INSERT INTO realtable
SELECT * FROM stagingtable
WHERE check_constraints_here;
Do keep concurrency issues in mind though. If you're trying to do a merge/upsert via COPY
you must LOCK TABLE realtable;
at the start of your transaction or you will still have the potential for errors. It looks like that's what you're trying to do - a copy if not exists
. If so, skipping errors is absolutely the wrong approach. See:
... this is a much-discussed issue.