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 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)

En 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

 

Pied de page des forums

Powered by FluxBB