Nous utilisons des cookies pour vous garantir la meilleure expérience sur notre site. Si vous continuez à utiliser ce dernier, nous considèrerons que vous acceptez l'utilisation des cookies. J'ai compris ! ou En savoir plus !.
banniere

Le portail francophone de la géomatique


Toujours pas inscrit ? Mot de passe oublié ?
Nom d'utilisateur    Mot de passe              Toujours pas inscrit ?   Mot de passe oublié ?

Annonce

Suite à un problème technique intervenu entre le 22 et le 23 mars, nous avons du procéder dans la soirée du 25 mars, à la restauration de la base de données du 24 mars (matinée).

En clair, nous avons perdu vos contributions et inscriptions du dimanche 24 et du lundi 25 mars.
Nous vous prions de nous excuser.

#1 Wed 30 May 2018 15:54

bruhnild
Participant actif
Lieu: Lyon
Date d'inscription: 7 Jun 2014
Messages: 130

Trigger - mise à jour de champs avec une séquence

Bonjour,

Je travaille actuellement sur la constitution d'une table adresse (t_adresse) au format gracethd.

Afin de faciliter le remplissage de la table, je crée des triggers qui viendront mettre à jour une partie de ses attributs au fur et à mesure de l'ajout de points d'adresses.

Pour commencer j'ai créé une séquence d'incrémentation pour le champs ad_code (id de t_adresse)

Code:

DROP SEQUENCE IF EXISTS ban.t_adresse_incrementation_ad_code;
CREATE SEQUENCE ban.t_adresse_incrementation_ad_code
  INCREMENT 1
  MINVALUE 000000000
  MAXVALUE 999999999
  START 1
  CACHE 1;
ALTER TABLE rbal.t_adresse OWNER TO postgres;

CREATE OR REPLACE FUNCTION
nextval_special()
RETURNS TEXT
LANGUAGE sql
AS
$$
    SELECT to_char(nextval('ban.t_adresse_incrementation_ad_code'), 'FM000000000'); 
$$;

Cette séquence a l'air de marcher puisque lorsque je fais

Code:

select concat('AD700',nextval_special()) as ad_code
from rbal.t_adresse

.

J'ai ensuite écrit un trigger qui met à jour le champs "ad_code" lors de l'insertion ou de l'update d'un nouvel objet dans la table :

Code:

CREATE OR REPLACE FUNCTION update_ad_code() RETURNS TRIGGER AS $$
BEGIN

    NEW.ad_code :=        
      concat('AD700',nextval_special()) 
      as ad_code ;
  RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';

DROP TRIGGER IF EXISTS trg_update_ad_code ON rbal.t_adresse;
CREATE TRIGGER trg_update_ad_code
BEFORE INSERT OR UPDATE OF 
geom 
ON rbal.t_adresse
FOR EACH ROW EXECUTE PROCEDURE update_ad_code();

Malheureusement lorsque je fais le test de rajouter une nouvelle entité depuis Qgis, j'obtiens une erreur de commit (voir screenshot en pj).

La fonction nextval_special() existe puisque je l'ai crée juste avant.. Je n'arrive pas à comprendre mon erreur. Pourriez vous m'aider?

Merci d'avance pour vos retours!

Marine.


Fichier(s) joint(s) :
Pour accéder aux fichiers vous devez vous inscrire.

Hors ligne

 

#2 Wed 30 May 2018 17:03

bruhnild
Participant actif
Lieu: Lyon
Date d'inscription: 7 Jun 2014
Messages: 130

Re: Trigger - mise à jour de champs avec une séquence

J'ai résolu le problème de la séquence manquante, il me semble qu'au lieu de pointer vers le schéma "rbal" je pointais vers le schéma "ban".
Entre temps j'ai une deuxième erreur...j'aurai du m'y attendre:

Code:

Impossible de valider les changements pour la couche t_adresse

Erreurs : ERREUR : 1 attribut non-ajouté.
  
Erreur du fournisseur de données :
      Erreur PostGIS lors de l'ajout d'entité : ERREUR:  la valeur d'une clé dupliquée rompt la contrainte unique « t_adresse_pk »
    DETAIL:  La clé « (ad_code)=(AD700000000004) » existe déjà.

L'incrémentation part de 0 au lieu de partir du dernier numero ad_code soit AD700000000244.
Je voudrais que mon entité ait le numéro AD700000000245.

J'ai tenté cette syntaxe sans succès :

Code:

CREATE OR REPLACE FUNCTION
nextval_special()
RETURNS TEXT
LANGUAGE sql
AS
$$
    SELECT to_char(nextval('rbal.t_adresse_incrementation_ad_code',max(ad_code)), 'FM000000000'); 
$$;

Hors ligne

 

#3 Wed 30 May 2018 17:59

jmarsac
Participant assidu
Lieu: NICE
Date d'inscription: 26 Oct 2005
Messages: 566
Site web

Re: Trigger - mise à jour de champs avec une séquence

Bonjour,
Je trouve que vous vous compliquez la vie, la fonction nextval_special() n'a pas d'intérêt.
Je ferai plutôt :

Code:

CREATE OR REPLACE FUNCTION update_ad_code() RETURNS TRIGGER AS $$
BEGIN

    NEW.ad_code :=  'AD700' || to_char(nextval('ban.t_adresse_incrementation_ad_code'), 'FM000000000');
   RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';

Si la numérotation n'est pas correcte, il faut vérifier la dernière valeur de la séquence avec

Code:

select last_value from ban.t_adresse_incrementation_ad_code;

et la comparer à la dernière clé obtenue.


Jean-Marie
Azimut

Hors ligne

 

#4 Wed 30 May 2018 18:00

tumasgiu
Membre
Lieu: Ajaccio
Date d'inscription: 5 Jul 2010
Messages: 1129

Re: Trigger - mise à jour de champs avec une séquence

Bonjour,

si j'ai compris vous souhaitez concaténer
des colonnes pour répondre à un format précis,
dans ce cas pourquoi ne pas créer une vue
qui présentera les colonnes normalisées ?

Code:

CREATE TABLE adresse (
id serial -- ,d'autre attributs
);

CREATE VIEW adresse_gracethd AS
(
SELECT
'AD700' || to_char(id, 'FM000000000') AS ad_code
--, mes autres attributs
FROM adresse
);

Les triggers de mise à jour de champ sont généralement considérés
comme une mauvaise pratique dans le monde des SGBDR,
on leur préfère des champs calculés ou des vues

Dernière modification par tumasgiu (Wed 30 May 2018 18:27)

Hors ligne

 

#5 Mon 04 June 2018 11:18

bruhnild
Participant actif
Lieu: Lyon
Date d'inscription: 7 Jun 2014
Messages: 130

Re: Trigger - mise à jour de champs avec une séquence

Bonjour,

Merci à tous les deux pour vos réponses.

Jmarsac, votre solution ne me permet pas d'incrémenter la séquence à partir de la dernière valeur (max) de ad_code se trouvant dans la table rbal.t_adresse.
A la place j'ai réécris la fonction comme ceci et ça tourne :

Code:

CREATE OR REPLACE FUNCTION fn_update_ad_code() RETURNS TRIGGER AS $$
BEGIN

    NEW.ad_code :=  'AD' ||mAX(CAST(REPLACE(REPLACE(ad_code, 'AD', ''), '', '') as numeric)+1)from rbal.t_adresse;
   RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';

Et voici le trigger :

Code:

DROP TRIGGER IF EXISTS trg_update_ad_code ON rbal.t_adresse;
CREATE TRIGGER trg_update_ad_code
BEFORE INSERT OR UPDATE OF 
geom 
ON rbal.t_adresse
FOR EACH ROW EXECUTE PROCEDURE fn_update_ad_code();

Voir en PJ pour le résultat visuel de la table attributaire.

Tumasgiu, je concatène effectivement des colonnes pour créer ma séquence dans la table rbal.t_adresse mais j'ai besoin de créer une table et non une vue car celle ci sera alimentée manuellement pour certains champs par la suite.


Fichier(s) joint(s) :
Pour accéder aux fichiers vous devez vous inscrire.

Hors ligne

 

#6 Mon 04 June 2018 11:29

tumasgiu
Membre
Lieu: Ajaccio
Date d'inscription: 5 Jul 2010
Messages: 1129

Re: Trigger - mise à jour de champs avec une séquence

bruhnild a écrit:

Tumasgiu, je concatène effectivement des colonnes pour créer ma séquence dans la table rbal.t_adresse mais j'ai besoin de créer une table et non une vue car celle ci sera alimentée manuellement pour certains champs par la suite.


Vous pouvez très bien utiliser la table pour les modifications,
et la vue pour la consultation/export.

Mais sinon PostgreSQL possède un mécanisme qui permet d'avoir des vues "modifiables".
Concrètement, vous créez des triggers utilisant l'évènement INSTEAD OF sur votre vue,
qui redirigent les mises à jours vers la table source.
Un petit exemple :
https://vibhorkumar.blog/2011/10/28/instead-of-trigger/

Dernière modification par tumasgiu (Mon 04 June 2018 11:45)

Hors ligne

 

Pied de page des forums

Powered by FluxBB