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

Rencontres QGIS 2025

L'appel à participation est ouvert jusqu'au 19 janvier 2025!

#1 Mon 04 February 2013 15:37

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3945

[Postgresql] créer fonction/trigger de mise à jour de multiples champs

Bonjour,

j'ai trois tables "entite", "commune" et "zonage" et j'essaie de remplir automatiquement des champs de la table "entite" avec des données de "commune" d'une part et de "zonage" de l'autre, lors de l'insertion (notamment dans QGIS).

Le fait est que, lors de la création de l'entité sous QGIS, pour différentes raisons, il peut arriver que le créateur de la donnée remplisse lui-même certains champs (dont ceux automatisés). Donc il faut éviter que la saisie ne plante. J'ai donc créé la fonction

Code:

CREATE OR REPLACE FUNCTION foncier.insert_commune()
  RETURNS trigger AS
$BODY$

BEGIN

-- on ajoute le libellé de la commune du nouvel objet si le champ n'a pas été préalablement rempli    
    if new.commune is null  or new.commune='' then
        select into new.commune libelle from cadastre.commune where st_within(new.geom, geom);
        return new ;
-- si le champ est rempli, on conserve la saisie faite
    else return new;
    end if;
    
END;
 $BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION foncier.insert_commune()
  OWNER TO postgres;

Puis je crée un trigger sur ma couche entite

Code:

CREATE TRIGGER insert
  BEFORE INSERT OR UPDATE
  ON foncier.entite
  FOR EACH ROW
  EXECUTE PROCEDURE foncier.insert_commune();

De la même façon, pour récupérer le zonage, j'ai une fonction et un trigger qui m'assurent le résultat escompté.

Ma question est: n'est-il pas possible de créer une seule procédure/trigger qui me permettent de faire ces deux remplissages de champs et de ne donc pas démultiplier les procédures/triggers en autant de champs que j'aurai besoin de renseigner (en tout, quatre sur cette table)? Mettre les instructions bout à bout n'exécute que la première commande, comme si le end if (ou le return new?) arrêtait la procédure et je ne trouve pas comment contourner cet arrêt de l'instruction.
Des pistes, svp ?
Merci d'avance

Hors ligne

 

#2 Mon 04 February 2013 15:50

Cornet Jérémie
Participant assidu
Lieu: Nouméa
Date d'inscription: 6 Apr 2008
Messages: 229

Re: [Postgresql] créer fonction/trigger de mise à jour de multiples champs

Hello,
C'est le return qui envoie le résultat de la fonction et donc stoppe celle ci.
Tu le mets uniquement après les blocs if et ca devrait marcher.

A+

Code:

if new.commune is null  or new.commune='' then
    select into new.commune libelle from cadastre.commune where st_within(new.geom, geom);
end if;
if new.zonage is null  or new.zonage='' then
    --
end if;
return new;

Dernière modification par Cornet Jérémie (Mon 04 February 2013 15:50)

Hors ligne

 

#3 Mon 04 February 2013 15:59

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3945

Re: [Postgresql] créer fonction/trigger de mise à jour de multiples champs

Bonjour Jérémie,

Merci. C'était effectivement ça!

Hors ligne

 

#4 Wed 06 February 2013 16:07

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3945

Re: [Postgresql] créer fonction/trigger de mise à jour de multiples champs

Bonjour,

toujours sur ma lancée avec l'écriture des triggers, je rencontre un nouveau souci. En effet, j'ai dans mon script

Code:

-- on ajoute le libellé de zone d'urba au sein de laquelle se trouve le nouvel objet s'il n'est pas rempli    
    if new.zonage is null or new.zonage='' then
        select into new.zonage libelle from planification.zone where st_within(new.geom, geom);
    end if;
        return new;

qui me permet de récupérer dans le champ "zonage", le libellé de zone lorsque l'entité créée est contenue dedans. Or il s'avère que certains objets sont à cheval sur deux voire trois zones; cette fonction ne renvoie donc rien.
Le st_overlaps (new.geom, geom) ne récupère bien évidemment qu'une seule valeur (et je ne sais pas non plus quelle est la logique de sélection : peut-être la première zone trouvée).
Comment pourrais-je lui signifier que je voudrais récupérer tous les libellés de toutes les zones concernées dans le seul champ "zonage" (séparés par une virgule)? Comment formaliser la concaténation des valeurs possibles dans ce seul champ?

Autre question: Quelle variable peut-on utiliser dans une fonction lorsqu'on veut récupérer le nom de la table des objets qu'on vient de copier (afin d'identifier à l'avenir de quelle table provient chacun des objets de ma nouvelle table)?

Merci

Hors ligne

 

#5 Wed 06 February 2013 16:28

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1554

Re: [Postgresql] créer fonction/trigger de mise à jour de multiples champs

SANTANNA a écrit:

Bonjour,

toujours sur ma lancée avec l'écriture des triggers, je rencontre un nouveau souci. En effet, j'ai dans mon script

Code:

-- on ajoute le libellé de zone d'urba au sein de laquelle se trouve le nouvel objet s'il n'est pas rempli    
    if new.zonage is null or new.zonage='' then
        select into new.zonage libelle from planification.zone where st_within(new.geom, geom);
    end if;
        return new;

qui me permet de récupérer dans le champ "zonage", le libellé de zone lorsque l'entité créée est contenue dedans. Or il s'avère que certains objets sont à cheval sur deux voire trois zones; cette fonction ne renvoie donc rien.
Le st_overlaps (new.geom, geom) ne récupère bien évidemment qu'une seule valeur (et je ne sais pas non plus quelle est la logique de sélection : peut-être la première zone trouvée).
Comment pourrais-je lui signifier que je voudrais récupérer tous les libellés de toutes les zones concernées dans le seul champ "zonage" (séparés par une virgule)? Comment formaliser la concaténation des valeurs possibles dans ce seul champ?


Bonjour,

la fonction d'agrégat string_agg permet de faire ca.
Si vous etes sur une vieille version de Postgresql (avant 8.4), vous devrez creer une surchage pour la fonction SUM qui prend en parametre un type TEXT:

Code:

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

Autre question: Quelle variable peut-on utiliser dans une fonction lorsqu'on veut récupérer le nom de la table des objets qu'on vient de copier (afin d'identifier à l'avenir de quelle table provient chacun des objets de ma nouvelle table)?

Merci


Vous pouvez regarder du coté des variables disponibles avec les triggers: http://www.postgresql.org/docs/9.1/stat … gger.html, sinon, une requete sur les tables de catalogue peut vous donner cette info (par exemple dans le catalogue "information_schema", qui est normé)

Nicolas

Hors ligne

 

#6 Thu 07 February 2013 07:35

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3945

Re: [Postgresql] créer fonction/trigger de mise à jour de multiples champs

Bonjour,
et merci Nicolas pour le tuyau. Je suis sous Postgis2.0 donc j'ai pu réécrire :

Code:

-- on ajoute le libellé de zone d'urba au sein de laquelle se trouve le nouvel objet s'il n'est pas rempli    
    if new.zonage is null or new.zonage='' then
--     on aggrège le libellé des zones que chevauche le nouvel objet ou qui le contiennent
        select into new.zonage string_agg(libelle,',' order by libelle) from planification.zone 
        where st_overlaps(new.geom, geom) or st_within(new.geom, geom);
       end if;

Et j'obtiens exactement ce que je veux.
Pour le nom de table par contre, j'ai beau relire la doc et fouiller dans PGAdmin ou le web, j'arrive pas à trouver la syntaxe. Il me semble que je devrais faire appel à table_name mais je n'arrive pas plus à avancer.
Donc toute aide reste toujours la bienvenue. big_smile

Dernière modification par SANTANNA (Thu 07 February 2013 07:37)

Hors ligne

 

#7 Thu 07 February 2013 10:28

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1554

Re: [Postgresql] créer fonction/trigger de mise à jour de multiples champs

Bonjour,

Je ne suis pas sur de comprendre ce que vous souhaitez faire avec ce table_name. Pouvez-vous m'eclairer ?

Merci

Nicolas

Hors ligne

 

#8 Thu 07 February 2013 11:05

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3945

Re: [Postgresql] créer fonction/trigger de mise à jour de multiples champs

Bonjour,

En fait, j'ai une table dans laquelle je vais devoir créer et copier un certain nombre d'entités à partir de plusieurs autres tables (une vue serait peut-être plus appropriée pour le coup mais bon...). Et donc dans cette table de destination, j'ai un champ "source" dans lequel, à chaque insertion d'une entité, je voudrais indiquer le nom de la table dont elle est issue.
"table_name" me semblait être le paramètre utilisé dans PG pour identifier les noms de table mais peut-être que je me trompe...

Hors ligne

 

#9 Wed 27 March 2013 15:44

trovez
Participant occasionnel
Lieu: Nantes
Date d'inscription: 17 Sep 2007
Messages: 24

Re: [Postgresql] créer fonction/trigger de mise à jour de multiples champs

Bonjour,

Si j'ai compris la demande, il s'agit de rajouter le nom de la table utilisée dans le select, ici  "planification".

Code:

-- on ajoute le libellé de zone d'urba au sein de laquelle se trouve le nouvel objet s'il n'est pas rempli   
    if new.zonage is null or new.zonage='' then
--     on aggrège le libellé des zones que chevauche le nouvel objet ou qui le contiennent
        select into new.zonage string_agg(libelle,',' order by libelle) from planification.zone
        where st_overlaps(new.geom, geom) or st_within(new.geom, geom);
       end if;

Si c'est le cas, rajouter :
   select into new.source 'planification';

Hors ligne

 

#10 Thu 28 March 2013 11:13

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3945

Re: [Postgresql] créer fonction/trigger de mise à jour de multiples champs

Bonjour,

En relisant mon dernier message, je remarque que je n'ai pas été bien clair. La question du nom de table était une seconde demande, pas forcément liée à ma première fonction de récupération de nom de zone. Mais il n'en reste pas moins que je cherchais comment écrire une fonction qui récupérerait les noms de table d'origine lors d'une insertion; mais à l'aveugle. je m'explique:
je veux remplir une table, via QGIS, en "copiant-collant" des entités de diverses tables, hétérogènes et touchant plusieurs thématiques. (Au diable, la topologie smile ). Dans une même table, les caractéristiques attributaires ne sont pas forcément suffisantes pour savoir si telle entité doit être récupérée ou non (des entités avec les mêmes infos attributaires ne sont pas forcément toutes prises); c'est aussi la visualisation qui tranche donc j'ai forcément besoin d'utiliser qgis pour faire mes copies.

Pour m'y retrouver dans quelques semaines/mois, il m'a paru nécessaire d'avoir un champ "source" qui me permettrait de retrouver d'où vient telle ou telle donnée (car certaines tables ont des données qui se ressemblent - le classique quand on a plusieurs producteurs sur la même donnée). Et je me demandais donc s'il y avait moyen, lors de la recopie de ces entités sous QGIS, de créer une fonction sous postgis, qui puisse me récupérer dans le champ "source" le nom de la table d'origine (tout comme il copie les attributs de champs).

Pour revenir à votre proposition de solution, finalement, c'est le genre de syntaxe sur laquelle je me suis rabattu, en créant une méga vue qui récupère les données de chacune de ces tables. Mais cela requiert au préalable que je fasse le boulot de visualisation et d'identification des entités à récupérer (ajout d'un champ codé dans certaines tables d'origine donc modification de leur structure mad). Ça a l'air de bien avancer pour le moment mais si une solution de fonction est possible.... why not?

Hors ligne

 

Pied de page des forums

Powered by FluxBB