[gull] pgsql...aaaarh

Cedric BRINER briner at infomaniak.ch
Thu Jun 16 13:22:02 CEST 2005


> Il y a deux problèmes:
> 
>    1. il faut que la colonne concernée de la table soit configurée
>       comme type SERIAL (ce qui, pour PostgreSQL, signifie que la
>       valeur par défaut de cette colonne lorsque NON spécifiée est
>       la fonction next_val('nom_colonne_seq').
> 
>    2. il faut que la valeur de la séquence soit préconfigurée à la
>       valeur désirée si pas 0.
> 
> > create table test (id serial, nom varchar(32));
> > INSERT INTO test ("nom") values ('cedric');
> > INSERT INTO test ("nom") values ('felix');
> > INSERT INTO test ("nom") values ('julien');
> > 
> > create table new_test (id serial, nom varchar(32));
> > insert into new_test SELECT * from test;
> 
> Problème: cela ne copie pas la valeur de la séquence. Symptôme:
> erreur à la première insertion suivante dans new_test, dans la
> mesure où id a bien été configuré comme UNIQUE (ou PRIMARY KEY)
> ce qui n'est pas le cas ici: d'où duplicats d'id.
> 
> On pourrait le faire avec setval().

1)
--

DROP TABLE test;
DROP TABLE new_test;
CREATE TABLE test (id serial NOT NULL UNIQUE, nom varchar(32));
INSERT INTO test ("nom") values ('cedric');
INSERT INTO test ("nom") values ('felix');
INSERT INTO test ("nom") values ('julien');

CREATE TABLE new_test (id serial NOT NULL UNIQUE, nom varchar(32));
INSERT INTO new_test SELECT * FROM test;

--- mise a jour de la sequence
SELECT setval('new_test_id_seq',3);

SELECT * from test_id_seq ;
SELECT * from new_test_id_seq ;
--- est-ce normal d'avoir une difference pour la colonne ``log_cntOB''

> 
> > ALTER TABLE test RENAME to old_test;
> > ALTER TABLE new_test RENAME to test;
> 
> regardons:
> 
>    \d test d     | integer               | not null default nextval('public.new_test_id_seq'::text)
> 
> évidemment incorrect pour les 2 raisons évoquées.
> 
> Correction (manuelle):
> 
>    ALTER TABLE test ALTER COLUMN id SET DEFAULT nextval('public.test_id_seq');
> 
> Dans ce dernier cas comme on reprend la séquence initialement crée,
> la valeur courante de la séquence est correcte.

2) j'ai tout juste tester en tenant compte de tes remarques...
--

DROP TABLE test;
DROP TABLE new_test;
CREATE TABLE test (id serial NOT NULL UNIQUE, nom varchar(32));
INSERT INTO test ("nom") values ('cedric');
INSERT INTO test ("nom") values ('felix');
INSERT INTO test ("nom") values ('julien');

CREATE TABLE new_test (id serial NOT NULL UNIQUE, nom varchar(32));
INSERT INTO new_test SELECT * FROM test;

--- recuperation de la sequence de test sur new_test
ALTER TABLE new_test ALTER COLUMN id SET DEFAULT nextval('public.test_id_seq');
DROP TABLE test;

--- renommage de la table et de ses tables associees
ALTER TABLE new_test RENAME TO test;
--- 3)   est-ce vraiment utile de faire ce genre de manipulation. Car mes scripts recupere
--- --   les erreurs du genre ``ERROR:  duplicate key violates unique constraint "test_id_key"''
---      et puisque c'est ce meme script qui a nomme cette contrainte >test_id_key<, ils peut des lors s'avoir
---      qu'elle operation entreprendre.
---      En fait, je me demandais si il n'y aurait-il moyen pas moyen depuis pypgsql (python postgresql)
---      de recuperer une sorte de description de la DB et de savoir des lors que >test_id_key< est une 
---      contrainte d'unicite sur le couple ( table:>test<, colonne:>id< )???
ALTER TABLE new_test_id_key RENAME TO test_id_key;


DROP SEQUENCE new_test_id_seq ;
--- ERROR:  cannot drop sequence new_test_id_seq because table test column id requires it
--- HINT:  You may drop table test column id instead.
--- et la j'ai une erreur de pgsql... table >test< column >id< requires it ??

--- fouillons dans test
\d test
--- ou j'ai aucune reference a ``new_test_id_seq''
--- 4)   donc je devrais avoir la possibilite de ``droper'' cette table
--- --

5) si m'a base est en prod, je devrais faire ce genre de truc entre un begin commit ?

> > commentaire: ce qui est bizarre c'est que pgsql gere tres bien les inter-dependances (foreign key) mais ne renomme pas les sequences ?
> 
> Le problème est que PostgreSQL traduit immédiatement le qualificateur SERIAL
> et ne le stocke pas. Et qu'il y a des raisons parfaitement valides pour
> utiliser une AUTRE séquence au nom quelconque!
> Voire une séquence partagée. PostgreSQL garantit que les numéros de séquence
> sont backend-private (ils peuvent avoir des trous en cas d'abort
> de transactions).
j'avais deja remarque ce genre de situation

> Ce qui suit est valide (PL/SQL) même en transactionnel.
> 
>    SELECT next_val('test_id_seq') INTO indice;
>    INSERT INTO test(id, nom) VALUES(indice, 'test');
>    INSERT INTO linked_table(truc, test_id) VALUES('truc', indice);
> 
> c'est d'ailleurs la façon recommandée pour faire ce que MySQL fait
> avec last_insert_id().  On peut en faire une procédure stockée, p.ex.
> dans une VIEW inscriptible qui répartit les données sur plusieurs
> tables avec les liaisons nécessaires.
> 
> > question: comment faire pour que la table ``test'' prenne la sequence ``test_id_seq'' ?
> 
> On peut aussi créer la nouvelle table ainsi:
> 
>    SELECT * INTO new_test FROM test;
> 
> (les contraintes ne sont pas copiées)
> 
> puis ensuite ajouter les contraintes.
6) est-ce la maniere recommendee (best practice??)

> On peut aussi faire un dump/restore texte.
je suis deja perdu !! : )


Amicalement


Ced.
P.-S. desole pour les caractere accentues qui se transforme dans mon mutt en ``?''. Probleme
de conf. peut-etre ?


-- 

Cedric BRINER



More information about the gull mailing list