Pages: 1
- Sujet précédent - [Postgresql] créer fonction/trigger de mise à jour de multiples champs - Sujet suivant
#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
Bonjour,
toujours sur ma lancée avec l'écriture des triggers, je rencontre un nouveau souci. En effet, j'ai dans mon scriptCode:
-- 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.
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 ). 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 ). Ça a l'air de bien avancer pour le moment mais si une solution de fonction est possible.... why not?
Hors ligne
Pages: 1
- Sujet précédent - [Postgresql] créer fonction/trigger de mise à jour de multiples champs - Sujet suivant