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 08/03/2011 22:44:03

ElodieS
Membre

Remplir un champ par numérotation automatique

Bonjour à tous,

Je vous expose mon "problème":

j'ai une table que j'importe dans un schéma de ma base sans soucis (à partir d'un fichier csv). Plusieurs champs de cette table sont vides mais c'est tout à fait normal.
Je cherche à remplir un de ces champs vides par une numérotation automatique (de 1 jusqu'au nombre total de lignes).

J'ai cherché parmi les pistes "création d'une SEQUENCE", "type SERIAL" etc. mais je n'y arrive pas.
Ça ne renvoie pas d'erreur, mais mon champ reste toujours vide. Donc j'ai sûrement du rater une étape...

Merci d'avance pour votre aide.

Hors ligne

#2 09/03/2011 09:09:01

Marc Cousin
Membre

Re : Remplir un champ par numérotation automatique

C'est bien le type serial qu'il faut utiliser. Il utilise d'ailleurs une séquence comme mécanisme, ensuite.

Les champs de type serial sont auto-incrémentés si
- Vous ne précisez pas du tout de valeur pour eux. Par exemple, vous l'omettez de la liste des colonnes d'une commande INSERT
- Vous précisez la valeur DEFAULT pour la colonne au moment de l'insert.

Si vous leur donnez une valeur NULL par exemple, ils stockent NULL…


Marc.

Hors ligne

#3 10/03/2011 14:31:23

ElodieS
Membre

Re : Remplir un champ par numérotation automatique

Bonjour,

merci pour cette réponse.

Mais en fait je n'ai pas utilisé la commande INSERT...

- Dans ma table j'ai déclaré le champ à remplir a posteriori comme entier INTEGER.
(Je ne le déclare pas en type SERIAL car il ne voudra pas importer mon .csv dont la colonne en question est vide... "ERROR:  null value in column "mon_champ_à_remplir" violates not-null constraint)
- J'ai ensuite importé mes données à partir de mon .csv.
Tout fonctionne.
- J'ai ensuite créé une séquence :

CREATE SEQUENCE ma_seq START 1;

- Puis :

ALTER TABLE ma_table ALTER COLUMN mon_champ_à_remplir SET DEFAULT nextval ('ma_seq');

Après ces commandes, je vois que mon champ est devenu de type SERIAL, mais il reste vide...

Finalement je vais plutôt essayer de rajouter le champ a posteriori, ça devrait simplifier les choses.

... Phase de test ...

(...)

ça fonctionne si je veux que ma numérotation commence par 1.

Mais : si je veux qu'elle démarre à partir de la valeur de la dernière ligne d'un autre table de même format ??!

j'ai essayé en :
1. déclarant mon champ ajouté en integer et créant une séquence avec le paramètre start with puis en indiquant que la valeur par défaut de mon champ est cette séquence ;

2. déclarant mon champ ajouté en serial et en essayant de modifier a posteriori la séquence créée par défaut avec un paramètre restart puis en indiquant que la valeur par défaut de mon champ est cette séquence modifiée.

J'y arrive toujours pas.

Si quelqu'un a une idée...

Merci smile

Hors ligne

#4 10/03/2011 14:44:26

gleu
Administrateur

Re : Remplir un champ par numérotation automatique

Il serait plus simple de nous indiquer l'exemple complet qui ne fonctionne pas pour qu'on puisse vous aider.


Guillaume.

Hors ligne

#5 10/03/2011 14:46:23

Marc Cousin
Membre

Re : Remplir un champ par numérotation automatique

Comment vous-êtes vous arrangé pour que les données soient quand même incrémentées ?
Sinon, je présume que si vous avez réussi à le générer par la séquence, il suffit de la déclarer avec une autre valeur de démarrage (soit au moment du CREATE SEQUENCE, par le paramètre start, soit ALTER SEQUENCE, par le paramètre restart).


Marc.

Hors ligne

#6 10/03/2011 15:16:20

ElodieS
Membre

Re : Remplir un champ par numérotation automatique

gleu a écrit :

Il serait plus simple de nous indiquer l'exemple complet qui ne fonctionne pas pour qu'on puisse vous aider.

En effet.

J'ai donc pris un exemple pour tester mes requêtes.

Voici la table testserial, un seul champ :

champ1
____
valeur1
valeur2
valeur3
valeur4
valeur5
valeur6

DROP TABLE IF EXISTS testserial;
CREATE TABLE testserial (
     champ1 varchar (10) );
	 
COPY testserial FROM 'C:/import_data/testserial.csv' WITH DELIMITER AS ';' CSV HEADER;

ALTER TABLE  testserial ADD COLUMN id_test SERIAL; -- chercher comment placer ce champ en 1ère position dans la table

--Si id_test déclaré en INTEGER :
--DROP SEQUENCE IF EXISTS ma_seq CASCADE;
--CREATE SEQUENCE ma_seq START WITH 7;
--ALTER TABLE testserial ALTER COLUMN id_test SET DEFAULT nextval('ma_seq');
--ALTER SEQUENCE ma_seq OWNED BY obs_pvt.testserial.id_test;

--Si id_test déclaré en SERIAL :
ALTER SEQUENCE testserial_id_test_seq RESTART WITH 6;
ALTER TABLE testserial ALTER COLUMN id_test SET DEFAULT nextval('testserial_id_test_seq');

Mon champ id_test est rempli de 1 à 6 et non de 6 à 11 comme je l'aurais souhaité

Hors ligne

#7 10/03/2011 16:27:40

gleu
Administrateur

Re : Remplir un champ par numérotation automatique

chercher comment placer ce champ en 1ère position dans la table

Impossible avec PostgreSQL, à moins de recréer la table complète.

Concernant le test, vous ne pouvez pas indiquer la valeur de départ lorsque vous ajoutez une colonne de type serial. Par contre, l'exemple avec un entier peut fonctionner. Le voici au complet :

DROP TABLE IF EXISTS testserial;
CREATE TABLE testserial (champ1 varchar (10));
COPY testserial FROM '/home/guillaume/toto.csv' WITH DELIMITER AS ';' CSV HEADER;
ALTER TABLE  testserial ADD COLUMN id_test integer;
CREATE SEQUENCE ma_seq START WITH 6;
ALTER TABLE testserial ALTER COLUMN id_test SET DEFAULT nextval('ma_seq');
ALTER SEQUENCE ma_seq OWNED BY testserial.id_test;
UPDATE testserial SET id_test=nextval('ma_seq');

Si vous voulez le faire avec une colonne serial directement, voici l'exemple revu :

DROP TABLE IF EXISTS testserial;
CREATE TABLE testserial (id_test serial, champ1 varchar (10));
ALTER SEQUENCE testserial_id_test_seq RESTART WITH 6;
COPY testserial(champ1) FROM '/home/guillaume/toto.csv' WITH DELIMITER AS ';' CSV HEADER;

Et puis comme ça, ça évite d'avoir à se poser des questions sur la position des champs smile


Guillaume.

Hors ligne

#8 10/03/2011 16:32:47

Marc Cousin
Membre

Re : Remplir un champ par numérotation automatique

Une méthode un peu différente de celle de gleu (plus proche de la version originale):

DROP TABLE IF EXISTS testserial;
CREATE TABLE testserial (
     champ1 varchar (10) );
     
COPY testserial FROM 'C:/import_data/testserial.csv' WITH DELIMITER AS ';' CSV HEADER;


CREATE SEQUENCE testserial_id_test_seq START WITH 6; -- Créer la séquence. Elle démarre à 6.

ALTER TABLE testserial ADD COLUMN id_test int DEFAULT nextval('testserial_id_test_seq'); -- Ajouter la colonne. Cela numérote bien à partir de 6

ALTER SEQUENCE testserial_id_test_seq OWNED BY testserial.id_test; -- Affecter la séquence à la colonne. Cela revient à ce moment là à un type serial


Marc.

Hors ligne

#9 10/03/2011 21:19:13

ElodieS
Membre

Re : Remplir un champ par numérotation automatique

Un grand merci à vous deux.

je vais opter pour la solution où le champ id_test sera en 1ère position dans la table.

Et comme dans quelques temps j'aurai besoin de rajouter d'autres lignes dans ma table à partir d'autres .csv, je pourrai alors faire :

DROP TABLE IF EXISTS testserial;
CREATE TABLE testserial (
     id_test serial,	
     champ1 varchar (10) );

COPY testserial(champ1) FROM 'C:/import_data/testserial.csv' WITH DELIMITER AS ';' CSV HEADER; 
COPY testserial(champ1) FROM 'C:/import_data/testserial2.csv' WITH DELIMITER AS ';' CSV HEADER; 
COPY testserial(champ1) FROM 'C:/import_data/testserial3.csv' WITH DELIMITER AS ';' CSV HEADER; 
-- etc.

Ainsi ma clé primaire id_test sera bien numérotée.

(Sauf que mes tables ont plutot une cinquantaine de champs donc la parenthèse sera longue)

(...)

Je viens de faire un test avec mes grosses tables, ça fonctionne bien.

Encore merci !

Hors ligne

#10 11/03/2011 09:28:21

Marc Cousin
Membre

Re : Remplir un champ par numérotation automatique

Attention tout de même à un point: l'ordre des colonnes dans une table ne doit avoir aucune importance dans le développement de l'application (je vous dis ça parce que ça a l'air d'avoir une importance pour vous).

Il faut absolument éviter que l'ordre de définition des colonnes ait la moindre incidence sur le fonctionnement de l'application. Ça veut entre autres dire qu'il faut éviter les 'SELECT *' dans le code, et toujours préférer nommer explicitement la liste des colonnes à récupérer.


Marc.

Hors ligne

#11 11/03/2011 16:52:07

SQLpro
Membre

Re : Remplir un champ par numérotation automatique

ElodieS a écrit :

je vais opter pour la solution où le champ id_test sera en 1ère position dans la table.

C'est une idée aberrante. En effet, rien ne vous garantie que ce sera toujours le cas. Par nature dans le SGBDR il n'y a aucune notion d'ordre. Lisez ce que j'ai écrit à ce sujet :
http://sqlpro.developpez.com/cours/sqlaz/erreurs/#L6
http://blog.developpez.com/sqlpro/p5867 … -des-ense/

A +


Frédéric Brouard, alias SQLpro,  ARCHITECTE DE DONNÉES,  Expert langage SQL
Le site sur les SGBD relationnel et langage SQL   : http://sqlpro.developpez.com/
Modélisation de données, conseil, expertise, audit, optimisation, tuning, formation
* * * * *  Enseignant CNAM PACA, ISEN Toulon,  CESI Aix en Provence  * * * * *

Hors ligne

#12 21/03/2011 15:47:57

butin-matou
Membre

Re : Remplir un champ par numérotation automatique

J'ai eu un problème similaire.
Je pense que je l'ai résolu ainsi.
Me gourre-je ?

DROP TABLE IF EXISTS table_b ;
SELECT 
INTO table_b 
FROM table_a
-- Faire le tri dès maintenant
ORDER BY 
	Is_Local_address DESC ,
	UPPER(COUNTRY), 
	UPPER(POSTCODE),
	UPPER(TOWN),
	Name
;
DROP TABLE IF EXISTS table_c;
-- Drop la table avant de dropper la séquence

DROP SEQUENCE IF EXISTS Serial_number;
CREATE SEQUENCE Serial_number;

SELECT 
-- Positionner le Serial N° comme colonne 1 puis ajouter tout le rest (*)
nextval('Serial_number') AS "Serial N°" , * 
INTO table_c
FROM table_b;
;
SELECT * FROM table_c

Dernière modification par butin-matou (21/03/2011 15:48:50)

Hors ligne

#13 21/03/2011 15:52:40

Marc Cousin
Membre

Re : Remplir un champ par numérotation automatique

Ça devrait marcher (aux erreurs de syntaxe près, je n'ai pas vérifié smile ). Il y a juste une recopie de trop des données. Vous pourriez directement recopier dans la bonne table cible, plutôt que de recopier deux fois les données, je pense.


Marc.

Hors ligne

#14 21/03/2011 17:16:44

ElodieS
Membre

Re : Remplir un champ par numérotation automatique

Marc Cousin a écrit :

Attention tout de même à un point: l'ordre des colonnes dans une table ne doit avoir aucune importance dans le développement de l'application (je vous dis ça parce que ça a l'air d'avoir une importance pour vous).

Il faut absolument éviter que l'ordre de définition des colonnes ait la moindre incidence sur le fonctionnement de l'application. Ça veut entre autres dire qu'il faut éviter les 'SELECT *' dans le code, et toujours préférer nommer explicitement la liste des colonnes à récupérer.

SQLpro a écrit :

Par nature dans le SGBDR il n'y a aucune notion d'ordre.

Merci pour vos commentaires.

Il est vrai que ma logique sur ce point n'est pas très bonne (et en général j'aime assez les 'SELECT *' ...)

Mais ? L'ordre des champs a tout de même de l'importance quand on importe des données issues de tableurs ?? (ou pas?!)

--
Elodie

Hors ligne

#15 21/03/2011 17:25:51

Marc Cousin
Membre

Re : Remplir un champ par numérotation automatique

Non, même pas quand on importe d'un tableur. On peut (et il vaut mieux) préciser l'ordre des colonnes. Qu'on utilise un INSERT ou un COPY


Marc.

Hors ligne

#16 21/03/2011 17:47:33

SQLpro
Membre

Re : Remplir un champ par numérotation automatique

Le SELECT * est une chose à ne jamais utiliser en production. Il a été créé pour la mise au point des requêtes SQL lors des essais, mais il est doublement dangereux.
Quelques exemples :
- en cas de modification de la structure de la table, certaines requête vont faire planter les applications
- en cas d'ajout d'une colonne de type LOB, les performances vont devenir catastrophiques

A +


Frédéric Brouard, alias SQLpro,  ARCHITECTE DE DONNÉES,  Expert langage SQL
Le site sur les SGBD relationnel et langage SQL   : http://sqlpro.developpez.com/
Modélisation de données, conseil, expertise, audit, optimisation, tuning, formation
* * * * *  Enseignant CNAM PACA, ISEN Toulon,  CESI Aix en Provence  * * * * *

Hors ligne

#17 21/03/2011 17:51:13

butin-matou
Membre

Re : Remplir un champ par numérotation automatique

Marc Cousin a écrit :

Ça devrait marcher (aux erreurs de syntaxe près, je n'ai pas vérifié smile ). Il y a juste une recopie de trop des données. Vous pourriez directement recopier dans la bonne table cible, plutôt que de recopier deux fois les données, je pense.

Justement, c'est là le problème.
Si je fais le tout "en une seule passe" le nextval('no_serie') est inséré avant le tri.
Du coup, il est lui même trié et perd son sens : il n'est plus du tout serial.

Avec le double recopie, le serial est ajouté après le tri et correspond, dans le cas cité, au row_number().
Je ne suis pas fort en SQL, mais ça à l'air de marcher.

Hors ligne

#18 21/03/2011 17:55:50

Marc Cousin
Membre

Re : Remplir un champ par numérotation automatique

Oui, effectivement, la numérotation va être faite avant le tri.
Si c'est juste les numéroter au moment de l'insertion, et que vous avez au moins une 8.4, pas la peine d'utiliser le serial à ce moment là. Une Window Function fera l'affaire.


Marc.

Hors ligne

Pied de page des forums