J'ai rencontré le problème que ma séquence de clé principale n'est pas synchronisée avec les lignes de ma table.
C'est-à-dire que lorsque j'insère une nouvelle ligne, une erreur de clé dupliquée apparaît, car la séquence implicite dans le type de données série renvoie un nombre déjà existant.
Cela semble être dû à une importation/restauration qui ne maintient pas la séquence correctement.
-- 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
peut être utilisé pour éviter toute hypothèse incorrecte sur le nom de la séquence. Cela réinitialise la séquence en un seul coup:
_SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), (SELECT MAX(id) FROM table_name)+1);
_
Ou plus concement:
_SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), MAX(id)) FROM table_name;
_
Toutefois, ce formulaire ne peut pas gérer correctement les tables vides, car max (id) est null et vous ne pouvez pas non plus définir la valeur 0 car il serait en dehors de la plage de la séquence. Une solution consiste à recourir à la syntaxe _ALTER SEQUENCE
_, c.-à-d.
_ALTER SEQUENCE table_name_id_seq RESTART WITH 1;
ALTER SEQUENCE table_name_id_seq RESTART; -- 8.4 or higher
_
Mais _ALTER SEQUENCE
_ est d'une utilité limitée car le nom de séquence et la valeur de reprise ne peuvent pas être des expressions.
Il semble que la meilleure solution polyvalente consiste à appeler setval
avec false en tant que troisième paramètre, ce qui permet de spécifier la "prochaine valeur à utiliser":
_SELECT setval(pg_get_serial_sequence('t1', 'id'), coalesce(max(id),0) + 1, false) FROM t1;
_
Cela coche toutes mes cases:
Enfin, notez que _pg_get_serial_sequence
_ ne fonctionne que si la séquence appartient à la colonne. Ce sera le cas si la colonne d'incrémentation a été définie en tant que type serial
. Toutefois, si la séquence a été ajoutée manuellement, il est nécessaire de s'assurer que _ALTER SEQUENCE .. OWNED BY
_ est également exécuté.
c'est-à-dire que si le type serial
a été utilisé pour la création de la table, tout devrait fonctionner:
_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;
_
Mais si les séquences ont été ajoutées manuellement:
_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;
_
Le le plus court et le plus rapide :
SELECT setval('tbl_tbl_id_seq', max(tbl_id)) FROM tbl;
tbl_id
étant la colonne serial
de la table tbl
, puisée dans la séquence tbl_tbl_id_seq
(nom automatique par défaut).
Si vous ne connaissez pas le nom de la séquence attachée (qui ne doit pas obligatoirement être sous la forme par défaut), utilisez pg_get_serial_sequence()
:
SELECT setval(pg_get_serial_sequence('tbl', 'tbl_id'), max(tbl_id)) FROM tbl;
Il n'y a pas d'erreur par un ici. Par documentation:
La forme à deux paramètres définit le champ
last_value
de la séquence sur la valeur spécifiée et définit son champis_called
sur true, ce qui signifie que le suivantnextval
fera avancer la séquence avant de renvoyer une valeur.
Gras accent mien.
Si la table peut être vide et pour réellement commencer à 1 dans ce cas:
SELECT setval(pg_get_serial_sequence('tbl', 'tbl_id')
, COALESCE(max(tbl_id) + 1, 1)
, false)
FROM tbl;
Nous ne pouvons pas simplement utiliser la forme à deux partenaires et commencer par 0
parce que la limite inférieure des séquences est 1 par défaut (sauf personnalisation).
Il n'y a pas encore de défense contre l'activité de séquence simultanée ou l'écriture dans la table dans les requêtes ci-dessus. Si cela est pertinent, vous pouvez verrouiller la table en mode exclusif. Il empêche les transactions simultanées d'écrire un nombre plus élevé pendant que vous essayez d'être synchronisé. (Il bloque également temporairement les écritures inoffensives sans toucher au nombre maximal.)
Mais cela ne prend pas en compte les clients qui ont peut-être déjà récupéré des numéros de séquence sans aucun verrou sur la table principale (ce qui peut arriver). Pour permettre cela aussi, seulement augmente la valeur actuelle de la séquence, ne la diminue jamais. Cela peut sembler paranoïaque, mais cela correspond à la nature des séquences et à la défense contre les problèmes de concurrence.
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;
Cela réinitialisera toutes les séquences du public en ne faisant aucune hypothèse sur les noms de table ou de colonne. Testé sur la version 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 nom_séquence RESTART WITH (SELECT max (id) FROM nom_table); Ça ne marche pas.
Copié de la réponse @tardate:
SELECT setval(pg_get_serial_sequence('table_name', 'id'), MAX(id)) FROM table_name;
Cette commande ne modifie que la valeur de la séquence de clé générée automatiquement dans postgresql
_ALTER SEQUENCE "your_sequence_name" RESTART WITH 0;
_
Au lieu de zéro, vous pouvez mettre n'importe quel nombre à partir duquel vous voulez redémarrer la séquence.
le nom de séquence par défaut sera _"TableName_FieldName_seq"
_. Par exemple, si votre nom de table est _"MyTable"
_ et votre nom de champ est _"MyID"
_, votre nom de séquence sera alors "MyTable_MyID_seq"
.
Cette réponse est identique à la réponse de @ murugesanponappan, mais sa solution comporte une erreur de syntaxe. vous ne pouvez pas utiliser la sous-requête _(select max()...)
_ dans la commande alter
. Vous devez donc utiliser une valeur numérique fixe ou une variable à la place d'une sous-requête.
Réinitialiser toutes les séquences, pas de suppositions sur les noms sauf que la clé primaire de chaque table est "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%';
Ces fonctions présentent des risques lorsque les noms de séquence, noms de colonne, noms de table ou noms de schéma comportent des caractères amusants tels que des espaces, des signes de ponctuation, etc. J'ai écrit ceci:
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; $$ ;
Vous pouvez l'appeler pour une seule séquence en lui passant le OID et il renverra le nombre le plus élevé utilisé par toute table ayant la séquence par défaut; ou vous pouvez l'exécuter avec une requête comme celle-ci, pour réinitialiser toutes les séquences de votre base de données:
select relname, setval(oid, sequence_max_value(oid))
from pg_class
where relkind = 'S';
En utilisant un qual différent, vous pouvez réinitialiser uniquement la séquence d'un certain schéma, et ainsi de suite. Par exemple, si vous souhaitez ajuster les séquences dans le schéma "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';
Notez qu'en raison du fonctionnement de setval (), vous n'avez pas besoin d'ajouter 1 au résultat.
En guise de conclusion, je dois avertir que certaines bases de données semblent avoir des valeurs par défaut reliées à des séquences de manière à ne pas laisser les catalogues système en avoir une information complète. Cela se produit lorsque vous voyez des choses comme celles-ci dans\d:
alvherre=# \d baz
Tabla «public.baz»
Columna | Tipo | Modificadores
---------+---------+------------------------------------------------
a | integer | default nextval(('foo_a_seq'::text)::regclass)
Notez que l'appel nextval () dans cette clause default a un transtypage :: text en plus du transclass :: regclass. Je pense cela est dû aux bases de données pg_dump'ed des anciennes versions de PostgreSQL. Qu'est-ce qui se passera est que la fonction sequence_max_value () ci-dessus ignorera une telle table. Pour résoudre le problème, vous pouvez redéfinir la clause DEFAULT pour faire référence à la séquence directement sans la conversion:
alvherre=# alter table baz alter a set default nextval('foo_a_seq');
ALTER TABLE
Ensuite, psql l'affiche correctement:
alvherre=# \d baz
Tabla «public.baz»
Columna | Tipo | Modificadores
---------+---------+----------------------------------------
a | integer | default nextval('foo_a_seq'::regclass)
Dès que vous avez corrigé cela, la fonction fonctionne correctement pour cette table ainsi que pour toutes les autres qui pourraient utiliser la même séquence.
Réinitialiser toutes les séquences du public
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';
Je suggère cette solution trouvée sur le wiki postgres. Il met à jour toutes les séquences de vos tables.
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;
Comment utiliser (à partir du wiki postgres):
Exemple:
psql -Atq -f reset.sql -o temp
psql -f temp
rm temp
Article original (également avec correctif pour la propriété de la séquence) ici
Encore un autre plpgsql - réinitialise que si 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;
$$
;
commentant également la ligne --execute format('alter sequence
donnera la liste, pas en réinitialisant la valeur
Ce problème survient lorsque j'utilise un cadre d'entité pour créer la base de données, puis ensemencer la base de données avec les données initiales, ce qui rend la séquence incohérente.
Je l'ai résolu en créant un script à exécuter après l'ensemencement de la base de données:
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$
Certaines réponses vraiment difficiles ici, je suppose que c'était très mauvais à peu près au moment où cela a été demandé, car beaucoup de réponses d'ici ne fonctionnent pas pour la version 9.3. La documentation depuis la version 8.0 apporte une réponse à cette question:
SELECT setval('serial', max(id)) FROM distributors;
En outre, si vous devez vous occuper des noms de séquence sensibles à la casse, procédez comme suit:
SELECT setval('"Serial"', max(id)) FROM distributors;
Ma version utilise la première, avec quelques erreurs de vérification ...
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;
Mettre tous ensemble
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';
corrigera la séquence 'id'
de la table donnée (comme cela est généralement nécessaire avec Django par exemple).
avant, je n'avais pas encore essayé le code: dans ce qui suit, je publie la version pour le code SQL pour les solutions Klaus et user457226 qui fonctionnait sur mon ordinateur [Postgres 8.3], avec juste quelques ajustements pour ceux de Klaus et de ma version. pour le user457226 un.
Solution Klaus:
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();
solution 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';
Revérifier toutes les séquences dans la fonction de schéma 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;
Pour relancer toute séquence à 1, utilisez:
-- 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';
Si vous voyez cette erreur lorsque vous chargez des données SQL personnalisées pour l'initialisation, un autre moyen d'éviter cela est:
Au lieu d'écrire:
INSERT INTO book (id, name, price) VALUES (1 , 'Alchemist' , 10),
Supprimer la id
(clé primaire) des données initiales
INSERT INTO book (name, price) VALUES ('Alchemist' , 10),
Ceci maintient la séquence de Postgres synchronisée!
Cette réponse est une copie de mauro.
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();
J'ai passé une heure à essayer d'obtenir que la réponse de djsnowsill fonctionne avec une base de données utilisant des tables et des colonnes de cas mixtes, puis je suis tombé sur la solution grâce à un commentaire de Manuel Darveau, mais je pensais pouvoir le rendre un peu plus clair pour tout le monde:
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%';
Cela a l'avantage de:
Pour expliquer, le problème était que pg_get_serial_sequence
prend des chaînes pour comprendre de quoi vous parlez, alors si vous le faites:
"TableName" --it thinks it's a table or column
'TableName' --it thinks it's a string, but makes it lower case
'"TableName"' --it works!
Ceci est réalisé en utilisant ''%1$I''
dans la chaîne de format, ''
crée une apostrophe 1$
signifie premier argument, et I
signifie entre guillemets
La réponse de Klaus est la plus utile, à part une petite erreur: vous devez ajouter DISTINCT dans une instruction select.
Cependant, si vous êtes certain qu'aucun nom de table + colonne ne peut être équivalent pour deux tables différentes, vous pouvez également utiliser:
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';
qui est une extension de la solution user457226 pour le cas où un nom de colonne intéressé n'est pas 'ID'.
Le bidouillage laid pour résoudre ce problème en utilisant une certaine magie de Shell, ce n'est pas une bonne solution mais pourrait inspirer d'autres avec des problèmes similaires :)
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...
fait JDBC bork, alors voici une méthode compatible avec 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;';
Essayez reindex .
UPDATE: Comme indiqué dans les commentaires, cela répondait à la question initiale.
Une méthode pour mettre à jour toutes les séquences de votre schéma utilisées comme identifiant:
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 $$;