[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