#1 Mon 04 January 2021 16:33
- tweaxy
- Participant actif
- Lieu: Abbeville
- Date d'inscription: 27 Dec 2018
- Messages: 76
Trigger suppression d'objets dans une table tierce
Bonjour,
Je souhaiterais à l'aide d'un trigger, lors d'une suppression d'un objet linéaire, supprimer également tous les objets d'une table de correspondance où une clé étrangère donne sur mon objet linéaire.
an_voie : des noms de voie.
an_section_voie : Table de correspondance entre mes linéaires et une ou plusieurs voie associée.
(Un linéaire peut en effet avoir une ou plusieurs voie liée, une association N,N dans un MCD)
geo_section_voie : Mes linéaires
A la suppression d'un linéaire de voie, je dois également supprimer tous les objets dans la table an_section_voie qui ont une valeur de mon ID de geo_section_voie.
En faisant un AFTER DELETE, je n'arrive pas à récupérer mon ID de mon linéaire.
En faisant un BEFORE DELETE, je n'ai pas non plus réussi...
Voilà mon code ci-dessous.
Ne vous préoccuper pas de la première partie, qui recalcule la longueur de la voie suite à une suppression d'objets dans la table de correspondance.
CREATE FUNCTION rva.delete_calcul_longueur_voie() RETURNS trigger AS $BODY$
DECLARE
v_long_delete real;
v_id_delete integer;
begin
IF (TG_TABLE_NAME = 'an_section_voie') THEN
SELECT longueur FROM rva.an_voie WHERE id_voie = OLD.id_voie INTO v_long_delete;
-- on recalcul la longueur avec le OLD.idvoie
v_id_delete := OLD.id_voie; -- on récupère ancien id_voie associé
v_long_delete := v_long_delete - (SELECT sum(st_length(s.geom)) FROM rva.geo_section_voie s, rva.an_section_voie sv
WHERE sv.id_sectvoi = OLD.id_sectvoi AND s.id_section = sv.id_section);
IF v_long_delete IS null THEN -- si null on met 0 (nécessaire car le null emporte sur le 0 sur l'opération v_long_old au dessus)
v_long_delete := 0;
END IF;
UPDATE rva.an_voie SET longueur = v_long_delete WHERE id_voie = v_id_delete;
END IF;
-- marche pas ça...
IF (TG_TABLE_NAME = 'geo_section_voie') THEN
DELETE FROM rva.an_section_voie WHERE id_section = OLD.id_section;
END IF;
return NEW;
end;
$BODY$ LANGUAGE plpgsql;
Et les triggers associés à cette fonction :
CREATE TRIGGER tr_calc_voies3 BEFORE DELETE ON rva.an_section_voie
FOR EACH ROW EXECUTE PROCEDURE rva.delete_calcul_longueur_voie();
-- lui ne marche pas..
CREATE TRIGGER tr_calc_voies4 BEFORE DELETE ON rva.geo_section_voie
FOR EACH ROW EXECUTE PROCEDURE rva.delete_calcul_longueur_voie();
Visiblement un besoin simple, que je n'arrive pas à faire....
Egalement, si je supprime les objets dans cette table de correpondance, est-ce que ma première partie de ma fonction trigger va se réaliser (sachant que pour chaque suppression d'objets dans la table an_section_voie, je lance cette procédure) ?
En espérant avoir été compréhensible dans ma demande
Merci d'avance
Léandre
Hors ligne
#2 Mon 04 January 2021 22:28
Re: Trigger suppression d'objets dans une table tierce
Bonsoir,
Pas besoin de trigger, il faut simplement utiliser l'option ON DELETE CASCADE dans la définition de la colonne contenant la clé étrangère :
Code:
CREATE TABLE an_section_voie( id serial PRIMARY KEY, id_section integer REFERENCES geo_section_voie ON DELETE CASCADE, id_voie integer REFERENCES an_voie ON DELETE CASCADE );
Tout enregistrement de la table de correspondance an_section_voie sera ainsi supprimé si la voie ou le linéaire auquel il fait référence est supprimé.
Le "ON DELETE CASCADE" sur id_voie n'était pas dans le besoin exprimé mais évite les "orphelins de voie".
Jean-Marie
Azimut
Hors ligne
#3 Tue 05 January 2021 08:47
- tweaxy
- Participant actif
- Lieu: Abbeville
- Date d'inscription: 27 Dec 2018
- Messages: 76
Re: Trigger suppression d'objets dans une table tierce
Bonjour,
C'est ce que j'avais initialement tenté avec le code ci-dessous, mais si je supprime un objet linéaire de ma table geo_section_voie, ça ne supprime pas les objets dans an_section_voie là où cette section était liée...
ALTER TABLE rva.geo_section_voie
ADD CONSTRAINT source_section_fkey FOREIGN KEY (source)
REFERENCES rva.lt_source_section (code) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE rva.an_section_voie
ADD CONSTRAINT id_section_fkey FOREIGN KEY (id_section)
REFERENCES rva.geo_section_voie (id_section) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT id_voie_fkey FOREIGN KEY (id_voie)
REFERENCES rva.an_voie (id_voie) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT cote_voie_fkey FOREIGN KEY (cote_voie)
REFERENCES rva.lt_cote_voie (code) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE;
Si je comprends bien, le ON DELETE CASCADE, si mis sur l'attribut id_voie de la table an_section_voie, si je supprime la voie dans ma table an_voie, ça va supprimer tous les objets liés dans la table an_section_voie, ou est-ce l'inverse, c'est-à-dire que si je supprime un objet dans an_section_voie, où le id_voie était 12 par exemple, ça va supprimer la voie dans an_voie ?
Merci à vous
Léandre
Hors ligne
#4 Tue 05 January 2021 08:54
- tweaxy
- Participant actif
- Lieu: Abbeville
- Date d'inscription: 27 Dec 2018
- Messages: 76
Re: Trigger suppression d'objets dans une table tierce
Après lecture de cette doc, https://www.postgresqltutorial.com/post … reign-key/
comme vous le dites, ça devrait fonctionner, mais lorsque je tente de supprimer un objet, via QGIS ou même via une requête SQL, ça ne supprime rien..
Léandre
Dernière modification par tweaxy (Tue 05 January 2021 09:01)
Hors ligne
#5 Tue 05 January 2021 10:07
- tweaxy
- Participant actif
- Lieu: Abbeville
- Date d'inscription: 27 Dec 2018
- Messages: 76
Re: Trigger suppression d'objets dans une table tierce
Bonjour,
Après quelques tests, sans les triggers mis en place pour d'autres besoins, le ON DELETE CASCADE fonctionne très bien...
J'ai donc un problème dans l'un des triggers généré.
Le problème vient de cette fonction trigger :
-- an_voie : longueur de la voie
CREATE FUNCTION rva.delete_calcul_longueur_voie() RETURNS trigger AS $BODY$
DECLARE
v_long_delete real;
v_id_delete integer;
begin
IF (TG_TABLE_NAME = 'an_section_voie') THEN
SELECT longueur FROM rva.an_voie WHERE id_voie = OLD.id_voie INTO v_long_delete;
-- on recalcul la longueur avec le OLD.idvoie
v_id_delete := OLD.id_voie; -- on récupère ancien id_voie associé
v_long_delete := v_long_delete - (SELECT sum(st_length(s.geom)) FROM rva.geo_section_voie s, rva.an_section_voie sv
WHERE sv.id_sectvoi = OLD.id_sectvoi AND s.id_section = sv.id_section);
IF v_long_delete IS null THEN -- si null on met 0 (nécessaire car le null emporte sur le 0 sur l'opération v_long_old au dessus)
v_long_delete := 0;
END IF;
UPDATE rva.an_voie SET longueur = v_long_delete WHERE id_voie = v_id_delete;
END IF;
-- marche pas ça...
/*IF (TG_TABLE_NAME = 'geo_section_voie') THEN
DELETE FROM rva.an_section_voie WHERE id_section = OLD.id_section;
END IF;*/
return NEW;
end;
$BODY$ LANGUAGE plpgsql;
CREATE TRIGGER tr_calc_voies3 BEFORE DELETE ON rva.an_section_voie
FOR EACH ROW EXECUTE PROCEDURE rva.delete_calcul_longueur_voie();
Celle-ci empêche visiblement la suppression de mes objets qui étaient liées à ma section de voie..
Il s'agit pourtant d'un BEFORE DELETE, afin de recalculer la longueur de mes voies en faisant la somme des longueurs des sections associées à la voie..
Merci
Léandre
Hors ligne
#6 Tue 05 January 2021 13:06
Re: Trigger suppression d'objets dans une table tierce
Bonjour,
Ce serait plutôt (non testé) :
Code:
CREATE FUNCTION rva.set_longueur_voie() RETURNS trigger AS $BODY$ BEGIN UPDATE rva.an_voie SET longueur = (SELECT sum(st_length(geom)) FROM rva.geo_section_voie WHERE id_section IN ( SELECT id_section FROM rva.an_section_voie WHERE id_voie = OLD.id_voie ) ) WHERE id_voie = OLD.id_voie; return OLD; END; $BODY$ LANGUAGE plpgsql;
NB: la valeur de retour du trigger AFTER est ignorée
Code:
CREATE TRIGGER tr_update_longueur_voie AFTER DELETE ON rva.an_section_voie FOR EACH ROW EXECUTE PROCEDURE rva.set_longueur_voie();
Dernière modification par jmarsac (Wed 06 January 2021 18:13)
Jean-Marie
Azimut
Hors ligne
#7 Wed 06 January 2021 11:21
- tweaxy
- Participant actif
- Lieu: Abbeville
- Date d'inscription: 27 Dec 2018
- Messages: 76
Re: Trigger suppression d'objets dans une table tierce
Bonjour,
Après tests ce matin, ça fonctionne effectivement.
Je vous remercie.
Etant novice sur l'utilisation des triggers, si j'ai bien compris la logique, même sur un AFTER DELETE, on peut récupérer la valeur OLD d'un attribut de l'objet ? On doit par contre renvoyer le return OLD pour pouvoir effectuer d'autres triggers ???
Cordialement,
Léandre
Hors ligne
#8 Wed 06 January 2021 18:12
Re: Trigger suppression d'objets dans une table tierce
Etant novice sur l'utilisation des triggers, si j'ai bien compris la logique, même sur un AFTER DELETE, on peut récupérer la valeur OLD d'un attribut de l'objet ?
oui
On doit par contre renvoyer le return OLD pour pouvoir effectuer d'autres triggers ???
non (je rectifie) la valeur retournée par un trigger AFTER est toujours ignorée. Donc, si vous définissez plusieurs triggers AFTER sur une table, ils seront tous exécutés à moins de lever une erreur
Jean-Marie
Azimut
Hors ligne
#9 Fri 08 January 2021 09:43
- tweaxy
- Participant actif
- Lieu: Abbeville
- Date d'inscription: 27 Dec 2018
- Messages: 76
Re: Trigger suppression d'objets dans une table tierce
Bonjour,
Je vous remercie pour ces précisions.
Cordialement,
Léandre
Hors ligne