2016-12-08 1 views
1

Ich mache eine Masseneinfügung von doppelten Werten (Duplikat Typ und Uuid) mit der folgenden Postgres-Abfrage.Warum löst das Einfügen doppelter Werte diesen Fehler in Postgres auf einer Rails 5-Anwendung aus?

Ich sehe ein Fehler in meinen Logs wie ActiveRecord::StatementInvalid: PG::CardinalityViolation: ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time HINT: Ensure that no rows proposed for insertion within the same command have duplicate constrained values.

Warum funktioniert diese Konfliktlösung nicht?

ActiveRecord::Base.connection.execute <<-POSTGRESQL 
    INSERT INTO #{Movie.table_name} (#{headers}) 
    VALUES #{values} 
    ON CONFLICT (uuid, type) DO UPDATE SET video_id = EXCLUDED.video_id, 
    status = 1, 
    category = EXCLUDED.category, updated_at = EXCLUDED.updated_at 
POSTGRESQL 


CREATE TABLE movies (
    id integer NOT NULL, 
    video_id integer NOT NULL, 
    category integer NOT NULL, 
    uuid character varying NOT NULL, 
    data json DEFAULT '{}'::json, 
    created_at timestamp without time zone NOT NULL, 
    updated_at timestamp without time zone NOT NULL, 
    type character varying DEFAULT 'FeatureLengthVideo'::character varying, 
    status integer DEFAULT 0 NOT NULL, 
); 

Antwort

0

Diese ziemlich gut in src/backend/executor/nodeModifyTable.c erklärt:

/* 
* This can occur when a just inserted tuple is updated again in 
* the same command. E.g. because multiple rows with the same 
* conflicting key values are inserted. 
* 
* This is somewhat similar to the ExecUpdate() 
* HeapTupleSelfUpdated case. We do not want to proceed because 
* it would lead to the same row being updated a second time in 
* some unspecified order, and in contrast to plain UPDATEs 
* there's no historical behavior to break. 
* 
* It is the user's responsibility to prevent this situation from 
* occurring. These problems are why SQL-2003 similarly specifies 
* that for SQL MERGE, an exception must be raised in the event of 
* an attempt to update the same row twice. 
*/ 
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple.t_data))) 
    ereport(ERROR, 
      (errcode(ERRCODE_CARDINALITY_VIOLATION), 
      errmsg("ON CONFLICT DO UPDATE command cannot affect row a second time"), 
      errhint("Ensure that no rows proposed for insertion within the same command have duplicate constrained values."))); 

Also müssen Sie sicherstellen, dass Sie die gleichen primären oder eindeutige Schlüssel zweimal in derselben Anweisung nicht fügen.

+0

Danke, also, wenn der Primärschlüssel "ID" genannt wurde, konnte ich es beheben, indem ich 'id = EXCLUDED.id' hinzufügen? – Nona

+0

Nein - Sie müssen die Daten korrigieren, so dass sie nicht zweimal dieselbe ID enthalten. –

Verwandte Themen