После импорта данных в PostgreSQL дублирующее значение ключа нарушает уникальное ограничение

Недавно я перенесла приложение rails в PostgreSQL, чтобы использовать полнотекстовый поиск.

Поскольку миграция совпала с переходом на новый веб-хост, шаги для миграции были следующими:

  • Развертывание приложения и db: create/db: schema: загрузка на новый сервер с соответствующим файлом database.yml
  • данные mysqldump только из существующей базы данных MySQL MySQL
  • импортировать данные в базу данных PostgreSQL

Приложение работает успешно, но проблема возникает при попытке добавить новый контент в базу данных. Например, когда я запускаю задачу rake для обновления моего твиттера:

PG::Error: ERROR:  duplicate key value violates unique constraint "twitter_feeds_pkey" DETAIL:  Key (id)=(3) already exists.

Это также происходит для всех других моделей, создания новых статей, пользователей и т.д. В разработке я вижу, что публикация инструкции insert n + 1 раз успешно сохранит запись без ошибок.

Мой вопрос: Как сообщить PostgreSQL о том, чтобы начать индексирование последовательно из существующих данных?

Я прочитал страницу REINDEX, но не думаю, что это действительно операция, которую я ищу.

Ответ 1

Если схема содержит последовательные или последовательные столбцы, вы должны reset их до максимального значения, которое встречается в соответствующем столбце. (обычно вам не нужно импортировать сериалы из файла, но дать им свободу автоинкремента.)

Для всех импортированных таблиц необходимо определить поля последовательности и запустить на них следующий код. (замените имя схемы для "sch", ваше имя таблицы для "mytable" и ваше имя столбца id для "id" )

WITH mx AS ( SELECT MAX(id) AS id FROM sch.mytable)
SELECT setval('sch.mytable_id_seq', mx.id) AS curseq
FROM mx
        ;

Ответ 2

В Rails вы можете использовать команду

ActiveRecord::Base.connection.reset_pk_sequence!('users')

чтобы снова добавить индекс первичного ключа для таблицы пользователя.

Ответ 3

Вы можете автоматизировать решение wildplasser, чтобы все последовательности были синхронизированы с текущим максимальным значением соответствующего столбца:

do
$block$
declare 
  r        record;
  stmt     text;
  max_id   integer;
begin
  for r in (
              select *
              from (
                select table_schema, 
                       table_name, 
                       column_name, 
                       pg_get_serial_sequence(table_schema||'.'||table_name, column_name) as col_sequence
                from information_schema.columns
                where table_schema not in ('pg_catalog', 'information_schema')
              ) t
              where col_sequence is not null
        ) 
  loop
    stmt := 'select coalesce(max('||r.column_name||'), 0) + 1 from '||r.table_schema||'.'||r.table_name;
    execute stmt into max_id;
    raise notice 'Next ID for %.%.% is %', r.table_schema, r.table_name, r.column_name, max_id;
    perform setval(r.col_sequence, max_id); 
  end loop;
end;
$block$

Обратите внимание, что это будет работать, только если столбцы были определены как serial, bigserial или были сделаны "владельцем" последовательности.

Ответ 4

Другой способ - удалить первичный ключ (id) из столбцов (или не сбрасывать идентификатор). Таким образом, ваши данные будут выглядеть как

INSERT INTO book (name, price) VALUES ('Alchemist' , 10);

вместо

INSERT INTO book (id, name, price) VALUES (1 , 'Alchemist' , 10);

Таким образом, после загрузки исходных данных вам не придется reset первичный ключ