Как сбросить последовательность первичных ключей postgres, если они не синхронизированы? - PullRequest
453 голосов
/ 28 октября 2008

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

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

Кажется, это вызвано тем, что импорт / восстановление не поддерживает последовательность должным образом.

Ответы [ 27 ]

2 голосов
/ 23 мая 2014

Если вы видите эту ошибку при загрузке пользовательских данных SQL для инициализации, есть еще один способ избежать этого:

Вместо записи:

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

Удалить id (первичный ключ) из исходных данных

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

Это синхронизирует последовательность Postgres!

1 голос
/ 28 мая 2013

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

pg_dump -s <DATABASE> | grep 'CREATE TABLE' | awk '{print "SELECT setval(#" $3 "_id_seq#, (SELECT MAX(id) FROM " $3 "));"}' | sed "s/#/'/g" | psql <DATABASE> -f -
1 голос
/ 10 марта 2011

Ответ Клауса - самый полезный, за исключением небольшого промаха: вы необходимо добавить DISTINCT в оператор выбора.

Однако, если вы уверены, что никакие таблицы + имена столбцов не могут быть эквивалентны для двух разных таблиц вы также можете использовать:

select sequence_name, --PG_CLASS.relname, PG_ATTRIBUTE.attname
       reset_sequence(split_part(sequence_name, '_id_seq',1))
from PG_CLASS
join PG_ATTRIBUTE on PG_ATTRIBUTE.attrelid = PG_CLASS.oid
join information_schema.sequences
     on information_schema.sequences.sequence_name = PG_CLASS.relname || '_' || PG_ATTRIBUTE.attname
where sequence_schema='public';

, который является расширением решения user457226 для случая, когда интересующее имя столбца не 'ID'.

1 голос
/ 10 марта 2019
select 'SELECT SETVAL(' || seq [ 1] || ', COALESCE(MAX('||column_name||')+1, 1) ) FROM '||table_name||';'
from (
       SELECT table_name, column_name, column_default, regexp_match(column_default, '''.*''') as seq
       from information_schema.columns
       where column_default ilike 'nextval%'
     ) as sequense_query
0 голосов
/ 21 мая 2015

SELECT setval... делает JDBC несущественным, поэтому вот Java-совместимый способ сделать это:

-- work around JDBC 'A result was returned when none was expected.'
-- fix broken nextval due to poorly written 20140320100000_CreateAdminUserRoleTables.sql
DO 'BEGIN PERFORM setval(pg_get_serial_sequence(''admin_user_role_groups'', ''id''), 1 + COALESCE(MAX(id), 0), FALSE) FROM admin_user_role_groups; END;';
0 голосов
/ 15 мая 2019

Метод для обновления всех последовательностей в вашей схеме, которые используются в качестве идентификатора:

DO $$ DECLARE
  r RECORD;
BEGIN
FOR r IN (SELECT tablename, pg_get_serial_sequence(tablename, 'id') as sequencename
          FROM pg_catalog.pg_tables
          WHERE schemaname='YOUR_SCHEMA'
          AND tablename IN (SELECT table_name 
                            FROM information_schema.columns 
                            WHERE table_name=tablename and column_name='id')
          order by tablename)
LOOP
EXECUTE
        'SELECT setval(''' || r.sequencename || ''', COALESCE(MAX(id), 1), MAX(id) IS NOT null)
         FROM ' || r.tablename || ';';
END LOOP;
END $$;
0 голосов
/ 28 октября 2008

Попробуйте reindex .

ОБНОВЛЕНИЕ: Как указано в комментариях, это было в ответ на первоначальный вопрос.

...