私は、主キーシーケンスがテーブル行と同期していないという問題に遭遇しました。
つまり、新しい行を挿入すると、シリアルデータ型に含まれるシーケンスが既に存在する番号を返すため、重複キーエラーが発生します。
インポート/リストアがシーケンスを正しく維持していないことが原因のようです。
-- 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;
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)はnullであるため、この形式では空のテーブルを正しく処理できません。また、シーケンスの範囲外になるため、valを0に設定することもできません。これに対する1つの回避策はALTER SEQUENCE
構文に頼ることです。
ALTER SEQUENCE table_name_id_seq RESTART WITH 1;
ALTER SEQUENCE table_name_id_seq RESTART; -- 8.4 or higher
しかし、シーケンス名とリスタート値を式にすることはできないため、ALTER SEQUENCE
の用途は限られています。
最も汎用的な解決策は、3番目のパラメータとしてfalseを指定してsetval
を呼び出すことで、「次に使用する値」を指定できるようになります。
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;
最短最速の方法:
SELECT setval('tbl_tbl_id_seq', max(tbl_id)) FROM tbl;
tbl_id
は、テーブルserial
の tbl
列で、シーケンスtbl_tbl_id_seq
(これはデフォルトの自動名です)から引き出されます。
添付シーケンスの名前がわからない場合(デフォルトの形式である必要はありません)、 pg_get_serial_sequence()
:
SELECT setval(pg_get_serial_sequence('tbl', 'tbl_id'), max(tbl_id)) FROM tbl;
ここには1つずつのエラーはありません。 ドキュメントごと:
2パラメータ形式は、シーケンスの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;
これはすべてのシーケンスをパブリックからリセットし、テーブル名やカラム名については仮定しません。バージョン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%';
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の答えと同じですが、彼の解決策には構文エラーがあります。 alter
コマンドでサブクエリ(select max()...)
を使用することはできません。そのため、固定の数値を使用するか、サブクエリの代わりに変数を使用する必要があります。
すべてのシーケンスをリセットします。各テーブルの主キーが "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';
別の修飾子を使用すると、特定のスキーマ内のシーケンスのみをリセットできます。たとえば、 "public"スキーマのシーケンスを調整したい場合は、次のようにします。
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)
そのdefault句のnextval()呼び出しには、:: regclassキャストに加えて:: textキャストがあります。私は考えるこれは古いPostgreSQLバージョンからpg_dumpされたデータベースによるものです。起こることは、上の関数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';
まだ別の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
行にコメントを付けるとリストになりますが、実際には値はリセットされません。
ここでは本当にハードコアな答えがいくつかあります。これは、この質問がされた頃は本当に悪い結果だったと思います。バージョン8.0以降の ドキュメント は、まさにこの質問に対する答えを提供します。
SELECT setval('serial', max(id)) FROM distributors;
また、大文字と小文字を区別するシーケンス名を処理する必要がある場合は、次のようにします。
SELECT setval('"Serial"', max(id)) FROM distributors;
私のバージョンはいくつかのエラーチェックで、最初のものを使用しています...
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;
私はこの解決策をpostgresのwikiに載せることを勧めます。それはあなたのテーブルのすべてのシーケンスを更新します。
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より):
例:
psql -Atq -f reset.sql -o temp
psql -f temp
rm temp
オリジナル記事(シーケンス所有権の修正もあります) はこちら
すべてを一緒に入れて
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で通常必要とされるように)。
この問題は、エンティティフレームワークを使用してデータベースを作成してからデータベースに初期データをシードするときに発生します。これにより、シーケンスが一致しなくなります。
データベースをシードした後に実行するスクリプトを作成することで解決しました。
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$
私はまだコードを試していなかった前に:私はKlaus 1と私のバージョンのほんのいくつかのほんの少しの調整で、私のPC [Postgres 8.3]の上で働いたKlausとuser457226解決策の両方のsql-codeのバージョンを投稿しますユーザー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';
初期化のためにカスタム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の答えを大文字と小文字を混在させたテーブルと列を使ってデータベースで動作させるために1時間を費やし、それからついにManuel Darveauからのコメントのおかげで解決策を見つけました。
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$
は最初の引数を意味します、そしてI
は引用符で囲みます
Klausの回答が最も役に立ちます。ちょっとしたミスを避けてください:select文にDISTINCTを追加する必要があります。
ただし、2つの異なるテーブルでテーブル名と列名が同じにならないことが確実な場合は、次のものも使用できます。
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';
これは、関心のある列名が 'ID'ではない場合のuser457226ソリューションの拡張です。
シェルマジックを使ってそれを修正する醜いハック、素晴らしい解決策ではありませんが、似たような問題を抱えている他の人を刺激するかもしれません:)
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 -
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
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;';
インデックスの再作成 を試してください。
更新:コメントで指摘されているように、これは元の質問への回答です。
スキーマとしてIDとして使用されているすべてのシーケンスを更新する方法。
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 $$;