为什么在 Rails 5 应用程序上的 Postgres 中插入重复值会触发此错误?

Non*_*ona 6 postgresql ruby-on-rails

我正在使用下面的 Postgres 查询批量插入重复值(重复类型和 uuid)。

我在日志中看到一个错误,例如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.

为什么这个冲突解决方案不起作用?

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,
);
Run Code Online (Sandbox Code Playgroud)

Lau*_*lbe 5

这在以下内容中得到了很好的解释src/backend/executor/nodeModifyTable.c

/*
 * 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.")));
Run Code Online (Sandbox Code Playgroud)

因此,您必须确保不会在同一条语句中两次插入相同的主键或唯一键。