HiveBrain v1.2.0
Get Started
← Back to all entries
patternsqlMinor

Constraint in ON CONFLICT clause has no associated index

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
constrainthasassociatedconflictindexclause

Problem

I have this simple setup using PostgreSQL 13, latest dockerized:

CREATE TABLE stop (
      id INT UNIQUE,
      name TEXT,
      PRIMARY KEY(id)
    );

    CREATE TABLE line (
      id INT UNIQUE,
      name TEXT,
      PRIMARY KEY(id)
    );

    CREATE TABLE line_stops_sequence(
      id SERIAL PRIMARY KEY,
      line INT,
      stop INT,
      CONSTRAINT fk_line FOREIGN KEY(line) REFERENCES line(id),
      CONSTRAINT fk_stop FOREIGN KEY(stop) REFERENCES stop(id)
    );


When I launch the following sentence

INSERT INTO line(id, name) VALUES (1, 'Line 1');
INSERT INTO stop(id, name) VALUES (2, 'Stop 2');
INSERT INTO line_stops_sequence(line, stop) VALUES (1,1), (1,2) ON CONFLICT ON CONSTRAINT fk_stop DO NOTHING;


I get constraint in ON CONFLICT clause has no associated index;

I know I'm inserting an stop id that is not included in the stop table. The idea is that I want to ignore the INSERTs that have conflicts. In the example it is just two items, but I'm inserting bulk data.

How can I do it without having to manually check the result of the query? Is there anyway to do it with the SQL sentence?

Solution

The ON CONFLICT clause is strictly for handling unique violation and exclusion constraint violation errors, as documented in the manual. There is no similar syntax allowing you to handle foreign key violation errors.

You can ignore invalid references by incorporating checks into your insert statement, although you will need to switch from INSERT...VALUES to INSERT...SELECT to be able to do that. Here is one way:

INSERT INTO
  line_stops_sequence(line, stop)
SELECT
  new.line, new.stop
FROM
  (VALUES (1,1), (1,2)) AS new (line, stop)
WHERE
  new.line IN (SELECT id FROM line)
  AND
  new.stop IN (SELECT id FROM stop)
;

Code Snippets

INSERT INTO
  line_stops_sequence(line, stop)
SELECT
  new.line, new.stop
FROM
  (VALUES (1,1), (1,2)) AS new (line, stop)
WHERE
  new.line IN (SELECT id FROM line)
  AND
  new.stop IN (SELECT id FROM stop)
;

Context

StackExchange Database Administrators Q#294026, answer score: 8

Revisions (0)

No revisions yet.