2011-03-30 4 views
1

Comment est-ce que je supprime le «id» dans cette table d'incrémenter quand une erreur se produit?incrémentation sur les erreurs

db=> CREATE TABLE test (id serial primary key, info text, UNIQUE(info)); 
NOTICE: CREATE TABLE will create implicit sequence "test_id_seq" for serial column "test.id" 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "test_pkey" for table "test" 
NOTICE: CREATE TABLE/UNIQUE will create implicit index "test_info_key" for table "test" 
CREATE TABLE 

db=> INSERT INTO test (info) VALUES ('hello') ; 
INSERT 0 1 

db=> INSERT INTO test (info) VALUES ('hello') ; 
ERROR: duplicate key violates unique constraint "test_info_key" 

db=> INSERT INTO test (info) VALUES ('hello') ; 
ERROR: duplicate key violates unique constraint "test_info_key" 

db=> INSERT INTO test (info) VALUES ('goodbye') ; 
INSERT 0 1 

db=> SELECT * from test; SELECT last_value from test_id_seq; 

id | info 
----+--------- 
    1 | hello 
    4 | goodbye 
(2 rows) 

last_value 
------------ 
      4 
(1 row) 
+0

Pouvez-vous expliquer pourquoi cela est un problème pour vous? – intgr

+0

J'ai remarqué le saut dans la séquence d'id lorsque je vidais une base de données distante plus petite dans une base de données master plus grande. Initialement, j'ai omis le 'id' dans la table et je me suis appuyé uniquement sur –

+0

... Initialement, j'ai omis le 'id' dans la table et je me suis appuyé uniquement sur la valeur de la clé UNIQUE. Cela a empêché la création de lignes dupliquées lors de l'insertion des mêmes lignes. –

Répondre

0

Je l'ai compris.

J'avais besoin d'écrire une fonction wrapper autour de mon instruction INSERT.

La base de données aura normalement un utilisateur à la fois, de sorte que la condition 'course vers l'ID suivant' est rare. Ce qui m'inquiétait, c'était lorsque ma fonction (non annotée) «tirer les lignes de la table de base de données distante» essayait de réinsérer la table de base de données distante grandissante dans la table de base de données master. J'affiche les identifiants de ligne et je ne voulais pas que les utilisateurs voient le manque de numérotation comme des données manquantes.

Quoi qu'il en soit, voici ma solution:

CREATE FUNCTION testInsert (test.info%TYPE) RETURNS void AS ' 
BEGIN 
    PERFORM info FROM test WHERE info=$1; 
    IF NOT FOUND THEN 
    INSERT INTO test (info) VALUES ($1); 
    END IF; 
END;' LANGUAGE plpgsql; 
5

Vous ne pouvez pas supprimer cela - et il n'y a rien de mal à avoir des trous dans vos valeurs d'ID.

La clé primaire est une valeur totalement dénuée de sens qui est utilisée uniquement pour identifier de façon unique une ligne dans une table.

Vous ne pouvez pas compter sur l'ID pour ne jamais avoir de trous - pensez à ce qui se passe si vous supprimez une ligne.

ignorent tout simplement - rien est faux

Modifier
Je voulais juste mentionner que ce comportement est aussi clairement indiqué dans le manuel:

Pour éviter de bloquer des transactions concurrentes qui obtiennent des numéros à partir de la même séquence, une opération nextval n'est jamais annulée

http://www.postgresql.org/docs/current/static/functions-sequence.html
(défilement vers le bas)

+0

Merci pour la clarification. Je percevais l'instruction INSERT comme une transaction atomique qui s'incrémenterait sur une insertion réussie. –

+0

Les espaces de numérotation sont bénins pour mon code. –

+0

@John Wasinger: l'INSERT lui-même ** est ** atomique, seule la génération des numéros de séquence est non transactionnelle et donc non atomique (btw: c'est la même chose dans tous les SGBD qui supportent les séquences) –

1

Imaginez deux transactions différentes vont à insérer. La transaction A obtient id = 1 La transaction B obtient id = 2. La transaction B est validée. La transaction A revient en arrière. Maintenant, que faisons-nous? Comment pourrions-nous annuler la séquence de A sans affecter B ou les transactions ultérieures?

+0

+1 pour un très bon illustration de l'une des raisons pour lesquelles les séquences ne sont pas annulées et pourquoi on ne devrait jamais insister/s'appuyer sur une séquence "sans-gabarit". –