PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 Re : PL/pgSQL » [Trigger] Récupérer l'ID d'une entrée soit insérée, soit sélectionnée » 14/10/2016 15:43:05

Bon, finalement je crois avoir trouvé l'ensemble des soucis que j'avais :

1/ Au départ je n'utilisais pas "id" dans la ligne d'INSERT, donc le RETURNING ne renvoyait pas l'id
2/ Plus la peine d'utiliser une sous requête si on récupère bien l'id dans "intervention_id"
3/ Ajout du ELSE par précaution
4/ Lorsque j'affecte le TRIGGER à une table, je faisais un "AFTER INSERT" et ça n'enregistrait pas la valeur dans la colonne. C'est désormais le cas. Voici l'ajout du trigger :

CREATE TRIGGER equipment_equipment_cluster
            BEFORE INSERT ON equipment_equipment_history
            FOR EACH ROW EXECUTE PROCEDURE have_place_id_field_clustering();

Maintenant que j'ai réglé ces petits soucis, il va me falloir faire de même pour plusieurs autre cas un tout petit peu plus corsés big_smile

#2 Re : PL/pgSQL » [Trigger] Récupérer l'ID d'une entrée soit insérée, soit sélectionnée » 11/10/2016 17:18:27

En effet, je n'avais pas vu cela comme ça étant donné que je ne prévoyais pas d'appeler le trigger autrement que pour un INSERT.

Je pense, mais peut-être que je me trompe, qu'un RETURN NULL devrait convenir, un peu comme ça :

                IF (TG_OP = 'INSERT') AND (NEW.intervention_id IS NULL) THEN
                    given_date := date_trunc('day', NEW.insert_datetime);
                    INSERT INTO intervention_intervention AS intervention (id, date, place_id, confirmed) VALUES (DEFAULT, given_date, NEW.place_id, False)
                        ON CONFLICT (date, place_id) DO UPDATE SET
                            confirmed = 'f'
                        RETURNING id
                    INTO intervention_id;
                    NEW.intervention_id := (SELECT id FROM intervention_intervention WHERE date = given_date AND place_id = NEW.place_id LIMIT 1);
                    RETURN NEW;
                ELSE
                    RETURN NULL;
                END IF;

Qu'en pensez-vous ?

Je n'avais pas pensé à utiliser des RAISE NOTICE dans mon trigger. Ça va me permettre de faire du debug et voir ce qui cloche, merci !

#3 PL/pgSQL » [Trigger] Récupérer l'ID d'une entrée soit insérée, soit sélectionnée » 11/10/2016 16:20:32

bl4n
Réponses : 4

Bonjour,

Étant débutant en TRIGGER, je me permet de solliciter un coup de pouce afin de résoudre ce problème qui me tracasse depuis quelques temps.

Voici un schéma résumé de ce sur quoi je travaille : http://dbpatterns.com/documents/57fceed … 3da5724af/

Ce que j'aimerais obtenir :

  • Remplir le champ intervention_id de la table equipment_history

  • Faire ce remplissage au moment de l'insertion d'une ligne dans equipment_history (MAIS je ne sais pas si je dois faire un Trigger BEFORE ou AFTER l'insertion)

Ce qu'il faut savoir sur le champ intervention_id :

  • Si une entrée existe déjà pour le couple date/place_id donnée, on utilise cet ID

  • Sinon on insère une nouvelle intervention et on utilise cet ID pour remplir le champ intervention_id

Jusqu'à maintenant j'ai tenté d'utiliser un truc comme ça :

---- TRIGGER générique qui copie les données d'une table vers sa table "_history"

CREATE OR REPLACE FUNCTION gissmo_audit()
            RETURNS trigger AS $body$
            DECLARE
                name TEXT;
            BEGIN
                IF (TG_OP = 'UPDATE') THEN
                    name := TG_TABLE_NAME::TEXT || '_history';
                    EXECUTE format('INSERT INTO %I VALUES(($1).*)', name) USING OLD;
                    RETURN NEW;
                END IF;
            EXCEPTION
                WHEN data_exception THEN
                    RAISE WARNING '[gissmo_audit] - ERROR [DATA EXCEPTION] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
                WHEN unique_violation THEN
                    RAISE WARNING '[gissmo_audit] - ERROR [UNIQUE] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
                WHEN OTHERS THEN
                    RAISE WARNING '[gissmo_audit] - ERROR [OTHER] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
                    RETURN NULL;
            END;
            $body$ LANGUAGE plpgsql;

---- Ajout du TRIGGER générique sur la table equipment_equipment

CREATE TRIGGER equipment_equipment_audit
            AFTER UPDATE ON equipment_equipment
            FOR EACH ROW EXECUTE PROCEDURE gissmo_audit();

---- TRIGGER censé remplir le champ intervention_id lors de l'insertion d'une ligne d'historique (NE FONCTIONNE PAS :'()

CREATE OR REPLACE FUNCTION have_place_id_field_clustering()
            RETURNS trigger AS $body$
            DECLARE
                intervention_id INTEGER;
                given_date DATE;
            BEGIN
                IF (TG_OP = 'INSERT') AND (NEW.intervention_id IS NULL) THEN
                    given_date := date_trunc('day', NEW.insert_datetime);
                    INSERT INTO intervention_intervention AS intervention (id, date, place_id, confirmed) VALUES (DEFAULT, given_date, NEW.place_id, False)
                        ON CONFLICT (date, place_id) DO UPDATE SET
                            confirmed = 'f'
                        RETURNING id
                    INTO intervention_id;
                    NEW.intervention_id := (SELECT id FROM intervention_intervention WHERE date = given_date AND place_id = NEW.place_id LIMIT 1);
                    RETURN NEW;
                END IF;
            EXCEPTION
                WHEN data_exception THEN
                    RAISE WARNING '[have_place_id_field_clustering] - ERROR [DATA EXCEPTION] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
                WHEN unique_violation THEN
                    RAISE WARNING '[have_place_id_field_clustering] - ERROR [UNIQUE] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
                WHEN OTHERS THEN
                    RAISE WARNING '[have_place_id_field_clustering] - ERROR - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
                    RETURN NULL;
            END;
            $body$ LANGUAGE plpgsql;

Je pense n'être pas loin du bon résultat, mais je crains d'être un peu trop simplet pour aligner les choses correctement et atteindre un résultat probant.

Je vous remercie d'avance pour toute l'aide que vous pourriez m'apporter à ce sujet et vous souhaite une agréable journée,

bl4n alias Personne.

Pied de page des forums

Propulsé par FluxBB