#1 Mon 14 August 2017 12:04
- white-shadow90
- Participant actif
- Date d'inscription: 9 Oct 2013
- Messages: 91
PostgreSQL/PostGIS - Trigger de MAJ parcelle
Bonjour,
Je cherche à concevoir un trigger de mise à jour de ma table s_parcelles_urba pour qu'elle intègre les éléments du PLU mais je rencontre une difficulté. Lorsque je modifie la géométrie de la couche s_dpur, j'obtiens dans QGIS le message d'erreur suivant :
Impossible de valider les changements pour la couche s_dpur
Erreurs : ERREUR : 1 géométrie non-modifiée.
Erreur du fournisseur de données :
Erreur PostGIS lors de la modification de géométrie : ERREUR: l'opérateur n'est pas unique : geometry <> geometry
LINE 1: SELECT (NEW.geom <> OLD.geom)
^
HINT: N'a pas pu choisir un meilleur candidat pour l'opérateur. Vous devez ajouter une
conversion explicite de type.
QUERY: SELECT (NEW.geom <> OLD.geom)
CONTEXT: fonction PL/pgsql majd_plu_parcelles(), ligne 4 à IF
En outre, est-il possible d'optimiser la phase trigger pour demander à ce que la couche s_parcelles_urba se mette à jour quelle que soit la couche du PLU qui a été modifiée. Tout mettre en seul trigger est il possible ? et souhaitable? J'ai conscience qu'à l'heure actuelle, le trigger n'est pas optimal puisque la fonction est vouée à taper sur toutes les couches du PLU alors que j'ai pour l'instant un trigger par couche du PLU.
La fonction de mise à jour
Code:
CREATE OR REPLACE FUNCTION majd_plu_parcelles() RETURNS trigger AS $BODY$ BEGIN IF (NEW.nom <> OLD.nom) THEN UPDATE urbanisme.s_parcelles_urba SET zonage = s_zonage_plu.nom FROM urbanisme.s_zonage_plu WHERE ST_INTERSECTS(s_zonage_plu.geom, s_parcelles_urba.geom); ELSIF (NEW.geom <> OLD.geom) THEN UPDATE urbanisme.s_parcelles_urba SET zonage = s_zonage_plu.nom FROM urbanisme.s_zonage_plu WHERE ST_INTERSECTS(s_zonage_plu.geom, s_parcelles_urba.geom); ELSIF (NEW.s_dpur.geom <> OLD.s_dpur.geom) THEN UPDATE urbanisme.s_parcelles_urba as t4 SET dpur = CASE WHEN (SELECT t3.intersection FROM (SELECT t2.idu_parcelle, ST_INTERSECTS(t1.geom, t2.geom) as intersection FROM urbanisme.s_dpur t1 INNER JOIN urbanisme.s_parcelles_urba t2 ON ST_INTERSECTS(t1.geom, t2.geom)) AS t3 WHERE t4.idu_parcelle = t3.idu_parcelle) THEN TRUE ELSE FALSE END; END IF; RETURN NEW; END; $BODY$ LANGUAGE PLpgSQL;
Le trigger de mise à jour quand la couche s_zonage_plu change :
Code:
CREATE TRIGGER trig_maj_plu AFTER UPDATE ON urbanisme.s_zonage_plu FOR EACH ROW EXECUTE PROCEDURE majd_plu_parcelles();
Le trigger de mise à jour quand la couche s_dpur change :
Code:
CREATE TRIGGER trig_maj_dpur AFTER UPDATE ON urbanisme.s_dpur FOR EACH ROW EXECUTE PROCEDURE majd_plu_parcelles();
Je vous remercie pour votre aide. En espérant que cet exemple puisse servir à d'autres.
Dernière modification par white-shadow90 (Mon 14 August 2017 13:38)
Hors ligne
#2 Mon 14 August 2017 14:46
- lbartoletti
- Juste Inscrit !
- Lieu: Sallanches
- Date d'inscription: 31 Jul 2016
- Messages: 9
Re: PostgreSQL/PostGIS - Trigger de MAJ parcelle
Bonjour,
Essayez manuellement vous devez essayer de mettre à jour une géométrie résultant d'un st_intersection invalide. Même si vous faites une intersection sur des polygones, le résultat de stat_intersection peut retourner des lignes ou des points. L'erreur peut venir de là.
Hors ligne
#3 Mon 14 August 2017 15:10
- white-shadow90
- Participant actif
- Date d'inscription: 9 Oct 2013
- Messages: 91
Re: PostgreSQL/PostGIS - Trigger de MAJ parcelle
Bonjour,
Lorsque j'exécute le Update du DPUR hors du trigger cela fonctionne. De ce que je comprends du message d'erreur, Postgres n'arrive pas à identifier à quoi doit correspondre le New (et j'imagine le old).
Hors ligne
#4 Mon 14 August 2017 15:36
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: PostgreSQL/PostGIS - Trigger de MAJ parcelle
Bonjour
Erreur PostGIS lors de la modification de géométrie : ERREUR: l'opérateur n'est pas unique : geometry <> geometry
Utilisez plutot st_equals (http://postgis.net/docs/ST_Equals.html) pour comparer vos géométries.
Nicolas
Hors ligne
#5 Mon 14 August 2017 16:03
- white-shadow90
- Participant actif
- Date d'inscription: 9 Oct 2013
- Messages: 91
Re: PostgreSQL/PostGIS - Trigger de MAJ parcelle
Bonjour,
J'ai donc essayé le code qui suit. Je n'ai plus de message d'erreur à l'enregistrement mais mon trigger ne semble pas s'exécuter car les champs de la colonne s_parcelles_urba.dpur n'ont pas été modifiés. Peut-être que je me trompe dans la manière de rédiger le st_equals...
Code:
CREATE OR REPLACE FUNCTION majd_plu_parcelles() RETURNS trigger AS $BODY$ BEGIN IF (NEW.nom <> OLD.nom) THEN UPDATE urbanisme.s_parcelles_urba SET zonage = s_zonage_plu.nom FROM urbanisme.s_zonage_plu WHERE ST_INTERSECTS(s_zonage_plu.geom, s_parcelles_urba.geom); ELSIF ST_EQUALS(NEW.geom,OLD.geom) IS FALSE THEN UPDATE urbanisme.s_parcelles_urba SET zonage = s_zonage_plu.nom FROM urbanisme.s_zonage_plu WHERE ST_INTERSECTS(s_zonage_plu.geom, s_parcelles_urba.geom); ELSIF ST_EQUALS(NEW.geom,OLD.geom) IS FALSE THEN UPDATE urbanisme.s_parcelles_urba as t4 SET dpur = CASE WHEN (SELECT t3.intersection FROM (SELECT t2.idu_parcelle, ST_INTERSECTS(t1.geom, t2.geom) as intersection FROM urbanisme.s_dpur t1 INNER JOIN urbanisme.s_parcelles_urba t2 ON ST_INTERSECTS(t1.geom, t2.geom)) AS t3 WHERE t4.idu_parcelle = t3.idu_parcelle) THEN TRUE ELSE FALSE END; END IF; RETURN NEW; END; $BODY$ LANGUAGE PLpgSQL;
Hors ligne
#6 Mon 14 August 2017 21:22
- tumasgiu
- Membre
- Lieu: Ajaccio
- Date d'inscription: 5 Jul 2010
- Messages: 1160
Re: PostgreSQL/PostGIS - Trigger de MAJ parcelle
Salut,
une seule branche de votre structure if sera évaluée à chaque exécution de la fonction.
Vous pouvez la considérer comme une structure CASE WHEN.
J'attire votre attention sur le fait que la seconde et la troisième branche teste la même condition.
Dernière modification par tumasgiu (Mon 14 August 2017 21:23)
Hors ligne
#7 Wed 16 August 2017 08:11
- ChristopheV
- Membre
- Lieu: Ajaccio
- Date d'inscription: 7 Sep 2005
- Messages: 3199
- Site web
Re: PostgreSQL/PostGIS - Trigger de MAJ parcelle
Bonjour,
J'attire votre attention sur le fait que
C'est de la déformation professionnelle ? lol
Christophe
L'avantage d'être une île c'est d'être une terre topologiquement close
Hors ligne
#8 Wed 16 August 2017 11:01
- white-shadow90
- Participant actif
- Date d'inscription: 9 Oct 2013
- Messages: 91
Re: PostgreSQL/PostGIS - Trigger de MAJ parcelle
Bonjour,
Pour résoudre mon problème, j'ai scindé ma fonction. Ce qui donne, à toutes fins utiles :
Code:
-- Fonction de mise à jour de la colonne zonage CREATE OR REPLACE FUNCTION urbanisme.majd_parcelle_zonage() RETURNS trigger AS $BODY$ BEGIN IF (NEW.nom <> OLD.nom) THEN UPDATE urbanisme.s_parcelles_urba SET zonage = s_zonage_plu.nom FROM urbanisme.s_zonage_plu WHERE ST_INTERSECTS(s_zonage_plu.geom, s_parcelles_urba.geom); ELSIF ST_EQUALS(NEW.geom, OLD.geom) IS FALSE THEN UPDATE urbanisme.s_parcelles_urba t5 SET zonage = (SELECT t4.zonages FROM ( SELECT t3.idu_parcelle, array_agg(t3.nom) as zonages FROM (SELECT t1.idu_parcelle, t2.nom FROM urbanisme.s_parcelles_urba t1 INNER JOIN urbanisme.s_zonage_plu t2 ON ST_INTERSECTS(t1.geom, t2.geom))t3 GROUP BY idu_parcelle) t4 WHERE t5.idu_parcelle = t4.idu_parcelle); END IF; RETURN NEW; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100; ALTER FUNCTION urbanisme.majd_parcelle_zonage() OWNER TO XXX; -- Trigger mettant en oeuvre la fonction de mise à jour de la colonne zonage CREATE TRIGGER trig_maj_zonage AFTER UPDATE ON urbanisme.s_zonage_plu FOR EACH ROW EXECUTE PROCEDURE urbanisme.majd_parcelle_zonage() ; -- Fonction de mise à jour de la colonne dpur CREATE OR REPLACE FUNCTION urbanisme.majd_parcelle_dpur() RETURNS trigger AS $BODY$ BEGIN IF ST_EQUALS(NEW.geom, OLD.geom) IS FALSE THEN UPDATE urbanisme.s_parcelles_urba as t4 SET dpur = CASE WHEN (SELECT t3.intersection FROM (SELECT t2.idu_parcelle, ST_INTERSECTS(t1.geom, t2.geom) as intersection FROM urbanisme.s_dpur t1 INNER JOIN urbanisme.s_parcelles_urba t2 ON ST_INTERSECTS(t1.geom, t2.geom)) AS t3 WHERE t4.idu_parcelle = t3.idu_parcelle) THEN TRUE ELSE FALSE END; END IF; RETURN NEW; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100; ALTER FUNCTION urbanisme.majd_parcelle_dpur() OWNER TO XXX; -- Trigger mettant en oeuvre la fonction de mise à jour de la colonne dpur CREATE TRIGGER trig_maj_dpur AFTER UPDATE ON urbanisme.s_dpur FOR EACH ROW EXECUTE PROCEDURE urbanisme.majd_parcelle_dpur();
Après, s'il existe un moyen d'éviter de créer autant de fonctions et de triggers qu'on a de table à mettre à jour, je serais intéressé.
Hors ligne