Как сбрасывать последовательность первичных ключей postgres, когда она выпадает из синхронизации?
Я столкнулся с проблемой, что моя первичная последовательность ключей не синхронизирована с моими строками таблицы.
То есть, когда я вставляю новую строку, я получаю дублируемую ключевую ошибку, потому что последовательность, указанная в серийном типе данных, возвращает число, которое уже существует.
Кажется, что это вызвано тем, что импорт / восстановление не поддерживает последовательность должным образом.
- Как запустить PostgreSQL-сервер в Mac OS X?
- Показать таблицы в PostgreSQL
- Как подключиться к Postgres через Node.js
- Как добавить столбец, если он не существует на PostgreSQL?
- Изменения производительности запросов PostgreSQL LIKE
- Экспортировать таблицу PostgreSQL в файл CSV с заголовками
- Как я могу войти в систему и проверить подлинность Postgresql после новой установки?
- psql: FATAL: роли "postgres" не существует
- Как сделать большие неблокирующие обновления в PostgreSQL?
- Как выйти из утилиты командной строки PostgreSQL: psql
- Какой самый быстрый способ сделать массовую вставку в Postgres?
- Многострочные обновления PostgreSQL в Node.js
- Структура Entity PostgreSQL
-- Login to psql and run the following -- What is the result? SELECT MAX(id) FROM your_table; -- Then run... -- This should be higher than the last result. SELECT nextval('your_table_id_seq'); -- If it's not higher... run this set the sequence last to your highest id. -- (wise to run a quick pg_dump first...) BEGIN; -- protect against concurrent inserts while you update the counter LOCK TABLE your_table IN EXCLUSIVE MODE; -- Update the sequence SELECT setval('your_table_id_seq', COALESCE((SELECT MAX(id)+1 FROM your_table), 1), false); COMMIT;
Источник – Ruby Forum
pg_get_serial_sequence
можно использовать, чтобы избежать каких-либо неправильных предположений о имени последовательности. Это сбрасывает последовательность в один снимок:
SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), (SELECT MAX(id) FROM table_name)+1);
Или более кратко:
SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), MAX(id)) FROM table_name;
Однако эта форма не может корректно обрабатывать пустые таблицы, так как max (id) является нулевым, и вы также не можете установить значение 0, потому что оно будет вне диапазона последовательности. Одним из способов решения этой проблемы является использование синтаксиса ALTER SEQUENCE
т.е.
ALTER SEQUENCE table_name_id_seq RESTART WITH 1; ALTER SEQUENCE table_name_id_seq RESTART; -- 8.4 or higher
Но ALTER SEQUENCE
имеет ограниченное применение, поскольку имя последовательности и значение перезапуска не могут быть выражениями.
Кажется, лучшим универсальным решением является вызов setval
с false как 3-й параметр, позволяющий указать «следующее значение для использования»:
SELECT setval(pg_get_serial_sequence('t1', 'id'), coalesce(max(id),0) + 1, false) FROM t1;
Это тикает все мои боксы:
- избегает жесткого кодирования фактического имени последовательности
- правильно обрабатывает пустые таблицы
- обрабатывает таблицы с существующими данными и не оставляет отверстия в последовательности
Наконец, обратите внимание, что pg_get_serial_sequence
работает только в том случае, если последовательность принадлежит столбцу. Это будет иметь место, если увеличивающий столбец был определен как serial
тип, однако, если последовательность была добавлена вручную, необходимо убедиться, что также выполняется ALTER SEQUENCE .. OWNED BY
.
т.е. если для создания таблицы использовался serial
тип, все это должно работать:
CREATE TABLE t1 ( id serial, name varchar(20) ); SELECT pg_get_serial_sequence('t1', 'id'); -- returns 't1_id_seq' -- reset the sequence, regardless whether table has rows or not: SELECT setval(pg_get_serial_sequence('t1', 'id'), coalesce(max(id),0) + 1, false) FROM t1;
Но если последовательности были добавлены вручную:
CREATE TABLE t2 ( id integer NOT NULL, name varchar(20) ); CREATE SEQUENCE t2_custom_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; ALTER TABLE t2 ALTER COLUMN id SET DEFAULT nextval('t2_custom_id_seq'::regclass); ALTER SEQUENCE t2_custom_id_seq OWNED BY t2.id; -- required for pg_get_serial_sequence SELECT pg_get_serial_sequence('t2', 'id'); -- returns 't2_custom_id_seq' -- reset the sequence, regardless whether table has rows or not: SELECT setval(pg_get_serial_sequence('t2', 'id'), coalesce(max(id),0) + 1, false) FROM t1;
Это приведет к сбросу всех последовательностей из общедоступных без предположений о именах таблиц или столбцов. Проверено на версии 8.4
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text, sequence_name text) RETURNS "pg_catalog"."void" AS $body$ DECLARE BEGIN EXECUTE 'SELECT setval( ''' || sequence_name || ''', ' || '(SELECT MAX(' || columnname || ') FROM ' || tablename || ')' || '+1)'; END; $body$ LANGUAGE 'plpgsql'; select table_name || '_' || column_name || '_seq', reset_sequence(table_name, column_name, table_name || '_' || column_name || '_seq') from information_schema.columns where column_default like 'nextval%';
Самый короткий и быстрый способ:
SELECT setval('tbl_tbl_id_seq', max(tbl_id)) FROM tbl;
tbl_id
является serial
столбцом таблицы tbl
, tbl
из последовательности tbl_tbl_id_seq
(которая является автоматическим именем по умолчанию).
Если вы не знаете имя присоединенной последовательности (которая не должна быть в форме по умолчанию), используйте pg_get_serial_sequence()
:
SELECT setval(pg_get_serial_sequence('tbl', 'tbl_id'), max(tbl_id)) FROM tbl;
Здесь нет никакой ошибки. По документации:
Двухпараметрическая форма устанавливает поле last_value последовательности в указанное значение и устанавливает его поле
is_called
true, а это означает, что следующийnextval
будет продвигать последовательность перед возвратом значения.
Смелый акцент мой.
совпадение
Нет защиты от одновременной активности последовательности или записи в таблицу в вышеуказанных запросах. Если это актуально, вы можете заблокировать таблицу в эксклюзивном режиме. Он удерживает параллельные транзакции от записи большего числа, пока вы пытаетесь синхронизировать. (Он также временно блокирует безобидные записи, не возиться с максимальным числом.)
Но он не учитывает клиентов, которые могли бы получить порядковые номера заранее без каких-либо блокировок в основной таблице, но (что может случиться). Для этого также нужно только увеличить текущее значение последовательности, не уменьшая ее. Это может показаться параноидальным, но это согласуется с характером последовательностей и защитой от проблем параллелизма.
BEGIN; LOCK TABLE tbl IN EXCLUSIVE MODE; SELECT setval('tbl_tbl_id_seq', max(tbl_id)) FROM tbl HAVING max(tbl_id) > (SELECT last_value FROM tbl_tbl_id_seq); COMMIT;
ALTER SEQUENCE sequence_name RESTART WITH (SELECT max (id) FROM table_name); Не работает.
Скопировано из ответа @tardate:
SELECT setval(pg_get_serial_sequence('table_name', 'id'), MAX(id)) FROM table_name;
Эта команда только для изменения автоматически генерирует значение последовательности клавиш в postgresql
ALTER SEQUENCE "your_sequence_name" RESTART WITH 0;
Вместо нуля вы можете поместить любой номер, из которого вы хотите перезапустить последовательность.
имя последовательности по умолчанию будет "TableName_FieldName_seq"
. Например, если ваше имя таблицы "MyTable"
а ваше имя поля "MyID"
, ваше имя последовательности будет "MyTable_MyID_seq"
.
Ответ такой же, как и ответ @ murugesanponappan, но в его решении есть синтаксическая ошибка. вы не можете использовать вспомогательный запрос (select max()...)
в команде alter
. Так что либо вам нужно использовать фиксированное числовое значение, либо вам нужно использовать переменную вместо подзапроса.
Сбросьте все последовательности, никаких предположений об именах, кроме того, что первичный ключ каждой таблицы является «id»:
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text) RETURNS "pg_catalog"."void" AS $body$ DECLARE BEGIN EXECUTE 'SELECT setval( pg_get_serial_sequence(''' || tablename || ''', ''' || columnname || '''), (SELECT COALESCE(MAX(id)+1,1) FROM ' || tablename || '), false)'; END; $body$ LANGUAGE 'plpgsql'; select table_name || '_' || column_name || '_seq', reset_sequence(table_name, column_name) from information_schema.columns where column_default like 'nextval%';
Эти функции чреваты опасностями, когда имена последовательностей, имена колонок, имена таблиц или имена схем имеют забавные символы, такие как пробелы, знаки препинания и т. П. Я написал это:
CREATE OR REPLACE FUNCTION sequence_max_value(oid) RETURNS bigint VOLATILE STRICT LANGUAGE plpgsql AS $$ DECLARE tabrelid oid; colname name; r record; newmax bigint; BEGIN FOR tabrelid, colname IN SELECT attrelid, attname FROM pg_attribute WHERE (attrelid, attnum) IN ( SELECT adrelid::regclass,adnum FROM pg_attrdef WHERE oid IN (SELECT objid FROM pg_depend WHERE refobjid = $1 AND classid = 'pg_attrdef'::regclass ) ) LOOP FOR r IN EXECUTE 'SELECT max(' || quote_ident(colname) || ') FROM ' || tabrelid::regclass LOOP IF newmax IS NULL OR r.max > newmax THEN newmax := r.max; END IF; END LOOP; END LOOP; RETURN newmax; END; $$ ;
Вы можете вызвать его для одной последовательности, передав ему OID, и он вернет максимальное число, используемое любой таблицей, которая имеет последовательность по умолчанию; или вы можете запустить его с таким запросом, чтобы сбросить все последовательности в вашей базе данных:
select relname, setval(oid, sequence_max_value(oid)) from pg_class where relkind = 'S';
Используя другой class, вы можете сбросить только последовательность в определенной схеме и так далее. Например, если вы хотите настроить последовательности в «общедоступной» схеме:
select relname, setval(pg_class.oid, sequence_max_value(pg_class.oid)) from pg_class, pg_namespace where pg_class.relnamespace = pg_namespace.oid and nspname = 'public' and relkind = 'S';
Обратите внимание, что из-за того, как работает setval (), вам не нужно добавлять 1 к результату.
В качестве заключительной заметки я должен предупредить, что некоторые базы данных, по-видимому, имеют умолчания, связанные с последовательностями способами, которые не позволяют системным каталогам иметь полную информацию о них. Это происходит, когда вы видите такие вещи в psql \ d:
alvherre=# \d baz Tabla «public.baz» Columna | Tipo | Modificadores ---------+---------+------------------------------------------------ a | integer | default nextval(('foo_a_seq'::text)::regclass)
Обратите внимание, что вызов nextval () в этом объявлении по умолчанию имеет a :: text cast в дополнение к cast :: regclass. Я думаю, что это связано с тем, что базы данных pg_dump’ed из старых версий PostgreSQL. Что произойдет, так это то, что функция sequence_max_value () выше будет игнорировать такую таблицу. Чтобы устранить проблему, вы можете переопределить предложение DEFAULT, чтобы напрямую ссылаться на последовательность без приведения:
alvherre=# alter table baz alter a set default nextval('foo_a_seq'); ALTER TABLE
Затем psql отображает его правильно:
alvherre=# \d baz Tabla «public.baz» Columna | Tipo | Modificadores ---------+---------+---------------------------------------- a | integer | default nextval('foo_a_seq'::regclass)
Как только вы исправили это, функция работает правильно для этой таблицы, а также для всех остальных, которые могут использовать одну и ту же последовательность.
Сбросить всю последовательность из открытых
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text) RETURNS "pg_catalog"."void" AS $body$ DECLARE BEGIN EXECUTE 'SELECT setval( ''' || tablename || '_id_seq'', ' || '(SELECT id + 1 FROM "' || tablename || '" ORDER BY id DESC LIMIT 1), false)'; END; $body$ LANGUAGE 'plpgsql'; select sequence_name, reset_sequence(split_part(sequence_name, '_id_seq',1)) from information_schema.sequences where sequence_schema='public';
Моя версия использует первый, с некоторой проверкой ошибок …
BEGIN; CREATE OR REPLACE FUNCTION reset_sequence(_table_schema text, _tablename text, _columnname text, _sequence_name text) RETURNS pg_catalog.void AS $BODY$ DECLARE BEGIN PERFORM 1 FROM information_schema.sequences WHERE sequence_schema = _table_schema AND sequence_name = _sequence_name; IF FOUND THEN EXECUTE 'SELECT setval( ''' || _table_schema || '.' || _sequence_name || ''', ' || '(SELECT MAX(' || _columnname || ') FROM ' || _table_schema || '.' || _tablename || ')' || '+1)'; ELSE RAISE WARNING 'SEQUENCE NOT UPDATED ON %.%', _tablename, _columnname; END IF; END; $BODY$ LANGUAGE 'plpgsql'; SELECT reset_sequence(table_schema, table_name, column_name, table_name || '_' || column_name || '_seq') FROM information_schema.columns WHERE column_default LIKE 'nextval%'; DROP FUNCTION reset_sequence(_table_schema text, _tablename text, _columnname text, _sequence_name text) ; COMMIT;
Объединяя все это
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text) RETURNS "pg_catalog"."void" AS $body$ DECLARE BEGIN EXECUTE 'SELECT setval( pg_get_serial_sequence(''' || tablename || ''', ''id''), (SELECT COALESCE(MAX(id)+1,1) FROM ' || tablename || '), false)'; END; $body$ LANGUAGE 'plpgsql';
будет исправлять последовательность « id'
данной таблицы (как это обычно требуется, например, для django).
Некоторые действительно хардкорные ответы здесь, я предполагаю, что это было очень плохо в то время, когда это было задано, так как множество ответов отсюда не работает для версии 9.3. Документация с версии 8.0 дает ответ на этот вопрос:
SELECT setval('serial', max(id)) FROM distributors;
Кроме того, если вам нужно позаботиться о именах последовательностей, чувствительных к регистру, вот как вы это делаете:
SELECT setval('"Serial"', max(id)) FROM distributors;
Я предлагаю это решение найти на wiki postgres. Он обновляет все последовательности ваших таблиц.
SELECT 'SELECT SETVAL(' || quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) || ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1) ) FROM ' || quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';' FROM pg_class AS S, pg_depend AS D, pg_class AS T, pg_attribute AS C, pg_tables AS PGT WHERE S.relkind = 'S' AND S.oid = D.objid AND D.refobjid = T.oid AND D.refobjid = C.attrelid AND D.refobjsubid = C.attnum AND T.relname = PGT.tablename ORDER BY S.relname;
Как использовать (из postgres wiki):
- Сохраните это в файл, скажем ‘reset.sql’
- Запустите файл и сохраните его вывод таким образом, чтобы он не включал обычные заголовки, а затем запускал этот вывод. Пример:
Пример:
psql -Atq -f reset.sql -o temp psql -f temp rm temp
Оригинальная статья (также с исправлением для правопорядка) здесь
до того, как я еще не пробовал код: в следующей статье я разместил версию для SQL-кода для решений Klaus и user457226, которые работали на моем компьютере [Postgres 8.3], с некоторыми небольшими корректировками для Клауса и моей версии для пользователя457226 один.
Решение Клауса:
drop function IF EXISTS rebuilt_sequences() RESTRICT; CREATE OR REPLACE FUNCTION rebuilt_sequences() RETURNS integer as $body$ DECLARE sequencedefs RECORD; c integer ; BEGIN FOR sequencedefs IN Select constraint_column_usage.table_name as tablename, constraint_column_usage.table_name as tablename, constraint_column_usage.column_name as columnname, replace(replace(columns.column_default,'''::regclass)',''),'nextval(''','') as sequencename from information_schema.constraint_column_usage, information_schema.columns where constraint_column_usage.table_schema ='public' AND columns.table_schema = 'public' AND columns.table_name=constraint_column_usage.table_name AND constraint_column_usage.column_name = columns.column_name AND columns.column_default is not null LOOP EXECUTE 'select max('||sequencedefs.columnname||') from ' || sequencedefs.tablename INTO c; IF c is null THEN c = 0; END IF; IF c is not null THEN c = c+ 1; END IF; EXECUTE 'alter sequence ' || sequencedefs.sequencename ||' restart with ' || c; END LOOP; RETURN 1; END; $body$ LANGUAGE plpgsql; select rebuilt_sequences();
user457226 решение:
--drop function IF EXISTS reset_sequence (text,text) RESTRICT; CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text,columnname text) RETURNS bigint --"pg_catalog"."void" AS $body$ DECLARE seqname character varying; c integer; BEGIN select tablename || '_' || columnname || '_seq' into seqname; EXECUTE 'SELECT max("' || columnname || '") FROM "' || tablename || '"' into c; if c is null then c = 0; end if; c = c+1; --because of substitution of setval with "alter sequence" --EXECUTE 'SELECT setval( "' || seqname || '", ' || cast(c as character varying) || ', false)'; DOES NOT WORK!!! EXECUTE 'alter sequence ' || seqname ||' restart with ' || cast(c as character varying); RETURN nextval(seqname)-1; END; $body$ LANGUAGE 'plpgsql'; select sequence_name, PG_CLASS.relname, PG_ATTRIBUTE.attname, reset_sequence(PG_CLASS.relname,PG_ATTRIBUTE.attname) 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 || '_seq' where sequence_schema='public';
Перепроверьте всю последовательность в общедоступной схеме
CREATE OR REPLACE FUNCTION public.recheck_sequence ( ) RETURNS void AS $body$ DECLARE _table_name VARCHAR; _column_name VARCHAR; _sequence_name VARCHAR; BEGIN FOR _table_name IN SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = 'public' LOOP FOR _column_name IN SELECT column_name FROM information_schema.columns WHERE table_name = _table_name LOOP SELECT pg_get_serial_sequence(_table_name, _column_name) INTO _sequence_name; IF _sequence_name IS NOT NULL THEN EXECUTE 'SELECT setval('''||_sequence_name||''', COALESCE((SELECT MAX('||quote_ident(_column_name)||')+1 FROM '||quote_ident(_table_name)||'), 1), FALSE);'; END IF; END LOOP; END LOOP; END; $body$ LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER COST 100;
Чтобы перезапустить всю последовательность до 1, используйте:
-- Create Function CREATE OR REPLACE FUNCTION "sy_restart_seq_to_1" ( relname TEXT ) RETURNS "pg_catalog"."void" AS $BODY$ DECLARE BEGIN EXECUTE 'ALTER SEQUENCE '||relname||' RESTART WITH 1;'; END; $BODY$ LANGUAGE 'plpgsql'; -- Use Function SELECT relname ,sy_restart_seq_to_1(relname) FROM pg_class WHERE relkind = 'S';
Еще один plpgsql – сбрасывается, только если max(att) > then lastval
do --check seq not in sync $$ declare _r record; _i bigint; _m bigint; begin for _r in ( SELECT relname,nspname,d.refobjid::regclass, a.attname, refobjid FROM pg_depend d JOIN pg_attribute a ON a.attrelid = d.refobjid AND a.attnum = d.refobjsubid JOIN pg_class r on r.oid = objid JOIN pg_namespace n on n.oid = relnamespace WHERE d.refobjsubid > 0 and relkind = 'S' ) loop execute format('select last_value from %I.%I',_r.nspname,_r.relname) into _i; execute format('select max(%I) from %s',_r.attname,_r.refobjid) into _m; if coalesce(_m,0) > _i then raise info '%',concat('changed: ',_r.nspname,'.',_r.relname,' from:',_i,' to:',_m); execute format('alter sequence %I.%I restart with %s',_r.nspname,_r.relname,_m+1); end if; end loop; end; $$ ;
также комментируя строку --execute format('alter sequence
даст список, а не сбросит значение
Эта проблема возникает со мной при использовании инфраструктуры сущностей для создания базы данных, а затем засеивает базу данных с исходными данными, что делает несоответствие последовательности.
Я решил это, создав скрипт для запуска после посева базы данных:
DO $do$ DECLARE tablename text; BEGIN -- change the where statments to include or exclude whatever tables you need FOR tablename IN SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE' AND table_name != '__EFMigrationsHistory' LOOP EXECUTE format('SELECT setval(pg_get_serial_sequence(''"%s"'', ''Id''), (SELECT MAX("Id") + 1 from "%s"))', tablename, tablename); END LOOP; END $do$
Если вы видите эту ошибку при загрузке пользовательских данных SQL для инициализации, можно избежать другого:
Вместо того, чтобы писать:
INSERT INTO book (id, name, price) VALUES (1 , 'Alchemist' , 10),
Удалите id
(первичный ключ) из исходных данных
INSERT INTO book (name, price) VALUES ('Alchemist' , 10),
Это позволяет синхронизировать последовательность Postgres!
Этот ответ – копия мауро.
drop function IF EXISTS rebuilt_sequences() RESTRICT; CREATE OR REPLACE FUNCTION rebuilt_sequences() RETURNS integer as $body$ DECLARE sequencedefs RECORD; c integer ; BEGIN FOR sequencedefs IN Select DISTINCT(constraint_column_usage.table_name) as tablename, constraint_column_usage.column_name as columnname, replace(replace(columns.column_default,'''::regclass)',''),'nextval(''','') as sequencename from information_schema.constraint_column_usage, information_schema.columns where constraint_column_usage.table_schema ='public' AND columns.table_schema = 'public' AND columns.table_name=constraint_column_usage.table_name AND constraint_column_usage.column_name = columns.column_name AND columns.column_default is not null ORDER BY sequencename LOOP EXECUTE 'select max('||sequencedefs.columnname||') from ' || sequencedefs.tablename INTO c; IF c is null THEN c = 0; END IF; IF c is not null THEN c = c+ 1; END IF; EXECUTE 'alter sequence ' || sequencedefs.sequencename ||' minvalue '||c ||' start ' || c ||' restart with ' || c; END LOOP; RETURN 1; END; $body$ LANGUAGE plpgsql; select rebuilt_sequences();
Я потратил час, пытаясь получить ответ djsnowsill для работы с базой данных с использованием таблиц и столбцов смешанного случая, а затем, наконец, наткнулся на решение благодаря комментарию от Мануэля Дарво, но я думал, что смогу сделать его более понятным для всех:
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text) RETURNS "pg_catalog"."void" AS $body$ DECLARE BEGIN EXECUTE format('SELECT setval(pg_get_serial_sequence(''%1$I'', %2$L), (SELECT COALESCE(MAX(%2$I)+1,1) FROM %1$I), false)',tablename,columnname); END; $body$ LANGUAGE 'plpgsql'; SELECT format('%s_%s_seq',table_name,column_name), reset_sequence(table_name,column_name) FROM information_schema.columns WHERE column_default like 'nextval%';
Это имеет преимущество:
- не предполагая, что столбец идентификатора определен особым образом.
- не предполагая, что все таблицы имеют последовательность.
- работая для имен таблиц / столбцов смешанного случая.
- используя формат, чтобы быть более кратким.
Чтобы объяснить, проблема заключалась в том, что pg_get_serial_sequence
принимает строки для определения того, что вы имеете в виду, поэтому, если вы это сделаете:
"TableName" --it thinks it's a table or column 'TableName' --it thinks it's a string, but makes it lower case '"TableName"' --it works!
Это достигается с помощью ''%1$I''
в строке формата, ''
делает апостроф 1$
означает первый arg, а I
означает в кавычках
Ответ Клауса является наиболее полезным, просто для небольшой промахи: вы должны добавить DISTINCT в select statement.
Однако, если вы уверены, что имена таблиц и столбцов не могут быть эквивалентны для двух разных таблиц, вы также можете использовать:
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 для случая, когда некоторое имя заинтересованного столбца не является идентификатором.
Уродливое взломать, чтобы исправить это, используя магию оболочки, а не отличное решение, но может вдохновить других на подобные проблемы 🙂
pg_dump -s | grep 'CREATE TABLE' | awk '{print "SELECT setval(#" $3 "_id_seq#, (SELECT MAX(id) FROM " $3 "));"}' | sed "s/#/'/g" | psql -f -
Попробуйте reindex .
ОБНОВЛЕНИЕ: Как указано в комментариях, это было в ответ на исходный вопрос.
SELECT setval...
делает JDBC bork, так что это совместимый с 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;';