POSTGRES - empêche l'incrémentation en série avec ON CONFLICT DO NOTHING [duplicate]
duplicata de cette question
Disons que j'ai le tableau suivant. Je veux des noms uniques dans le tableau afin qu'il n'y ait pas de doublons. Le processus qui insère un objet ne devrait pas avoir besoin de vérifier si un objet portant ce nom est déjà présent.
CREATE TABLE things(
id SMALLSERIAL PRIMARY KEY,
name varchar UNIQUE
);
Lorsque j'insère des valeurs comme celle-ci, cela fonctionne. Si «desk» est déjà dans les choses, il ne sera pas inséré.
INSERT INTO things (name)
VALUES ('desk')
ON CONFLICT DO NOTHING;
Le seul problème est ON CONFLICT NE RIEN ne fait vraiment rien. Il incrémente toujours la séquence du champ id.
Si cela se produit trop souvent, la séquence d'identifiants finit par devenir trop grande pour le type de champ.
Y a-t-il un moyen d'empêcher que cela se produise?
Réponses
En utilisant insert ... on conflict, vous ne pouvez pas empêcher l' serialincrémentation automatique en cas de conflit. Postgres (tout comme les autres bases de données) ne garantit pas que les séries soient séquentielles, comme expliqué dans la documentation :
Parce que
smallserial,serialetbigserialsont implémentés à l'aide de séquences, il peut y avoir des «trous» ou des lacunes dans la séquence de valeurs qui apparaît dans la colonne, même si aucune ligne n'est jamais supprimée. Une valeur allouée à partir de la séquence est toujours «épuisée» même si une ligne contenant cette valeur n'est jamais correctement insérée dans la colonne du tableau. Cela peut se produire, par exemple, si la transaction d'insertion est annulée.
Si vous en exécutez beaucoup insertqui finissent en conflit, une façon de limiter le bleading serait de changer la syntaxe en not exists:
insert into things (name)
select name
from (values ('desk')) v(name)
where not exists (select 1 from things t1 where t1.name = v.name)
Notez que cela ne garantit toujours pas que les publications en série seront séquentielles (reportez-vous à la citation ci-dessus de la documentation).