Nao000のぶろぐ

蝶を追っている少年になりたい

【elixir】ecto でpostgresqlにinsertしたら"constraint error when attempting to insert struct:"エラーが出た

目次

  1. 症状
  2. 原因
  3. 対応

症状

最近、ブログに記事投稿機能を追加しました。しかし、投稿画面から投稿する際に以下のエラーが発生しました。

    constraint error when attempting to insert struct:
        * blogs_pkey (unique_constraint)

    If you would like to stop this constraint violation from raising an
    exception and instead add it as an error to your changeset, please
    call `unique_constraint/3` on your changeset with the constraint
    `:name` as an option.

    The changeset defined the following constraints:

        * blogs_url_title_key (unique_constraint)
        * PRIMARY (unique_constraint)

原因

自動採番されるIDカラムの値を含めたinsertを手動実行していたことが原因でした。本番データに同期したさいに本番DBからエクスポートしたデータを手動実行していました。SQLにはIDカラムの値も含まれています。

postgresの自動採番を確認するとIDカラムの値 nextval がズレていることが確認できました。

シーケンス一覧を表示。

    nao000dotcom=# SELECT c.relname FROM pg_class c LEFT join pg_user u ON c.relowner = u.usesysid WHERE c.relkind = 'S';
            relname
    -----------------------
     blogcategories_id_seq
     blogs_id_seq
    (2 rows)

今回起きたエラーは blogs_id_seq の値のズレでした。 next_val の値を確認します。

    nao000dotcom=# select * from blogs_id_seq;
     last_value | log_cnt | is_called
    ------------+---------+-----------
             22 |      32 | t
    (1 row)

last_value の値が自動採番の最後の値を示します。この状態でテーブルにIDカラムの値に23を指定してinsertしていました。再び next_val の値を確認すると先程と変わりありません。

    nao000dotcom=# select * from blogs_id_seq;
     last_value | log_cnt | is_called
    ------------+---------+-----------
             22 |      32 | t
    (1 row)

この状態で記事投稿画面から投稿するとエラーが発生します。投稿画面からの投稿にはID値を含めていません。

対応

last_valueを再設定する以下のSQLを実行します。手動追加した分のID値を設定します。

    select setval ('blogs_id_seq', 23);

これで投稿画面からの投稿でエラーがでなくなりました。普通のことかもしれないですが、個人的に沼でした。ググっても出てこなかったので。