PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 13/10/2022 22:09:46

seaoss
Membre

Mise à jour clé primaire

Bonjour
J'ai une table avec une clé primaire "id" de type integer
A la suite d'un insert pour intégrer de nouvelles entités dans ma table
Je souhaiterai réorganiser les clés primaire selon un des champs

Par exemple soit une table "table"
id | Nom
1    ZZZ
2    ABA

Et une autre table à intégrer dans la "table"
id | Nom
1   AAA
2   ACA

Actuellement j'ai la ligne ZZZ qui a pour clé primaire 1
et l'entité AAA venant d'être intégré a pour clé 3

Quel code permet ceci :
id | Nom
1   AAA
2   ABA
3   ACA
4   ZZZ

J'ai essayé d'écraser les clés primaires via

UPDATE table SET id= rank 
FROM (SELECT rank() over (order by Nom) as rank FROM table)

mais "La clé primaire 1 ne peut être dupliquée"

Merci de votre aide

Hors ligne

#2 14/10/2022 03:50:08

rjuju
Administrateur

Re : Mise à jour clé primaire

Bonjour,


Pour quelle raison pensez-vous qu'une réorganisation des valeurs d'une clé technique a un intérêt ?  Même si vous le faites maintenant il est fort probable que les lignes vont continuer à avoir des valeurs dans le désordre, et essayer de maintenir un ordre quelconque sera à peu près impossible, sans compter sur les impacts tels que les clé étrangères.


La solution habituelle est d'utiliser une colonne définie comme GENERATED ALWAYS AS IDENTITY (ou serial/bigserial pour les versions plus anciennes), et ne pas assigner de valeur explicite pour la clé technique.

Hors ligne

#3 14/10/2022 20:24:42

dverite
Membre

Re : Mise à jour clé primaire

La redistribution de la clef primaire échoue via l'UPDATE du fait que Postgres ne teste pas l'unicité à la fin de l'instruction, comme indiqué ici dans la doc:

https://doc.postgresql.fr/14/sql-set-constraints.html

De plus, PostgreSQL vérifie les contraintes uniques non déferrables immédiatement, pas à la fin de l'instruction comme le standard le suggère.


Pour que l'UPDATE passe, il faudrait que la contrainte soit DEFERRABLE INITIALLY DEFERRED ou DEFERRABLE tout court et que la transaction la passe en DEFERRED.


L'autre solution est de ne pas faire un UPDATE mais de réinsérer les lignes avec DELETE+INSERT:


with d as (delete from table returning *)
 insert into table select row_number() over (order by Nom), Nom from d;

Je suggère row_number() au lieu de rank() parce que rank() créé des doublons en cas d'égalité

Dernière modification par dverite (14/10/2022 20:25:38)

Hors ligne

Pied de page des forums