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 PL/pgSQL » Vue modifiable sur vue matérialisée pour compléter autre table général » 28/12/2022 13:55:58

sab31
Réponses : 2

Bonjour à tous,

Je voudrais savoir s'il est possible de modifier une table 'A' avec les données provenant d'une vue modifiable 'v1' , elle même issue d'une vue matérialisée 'v_mat_1' , elle même issue de la table 'A'.

Je précise ma demande :
- j'ai une table 'A' de 2 millions de lignes d'entités géographiques de type 'linestring'
- j'ai un certains nombres d'utilisateurs ( U1,U2, U3,...) qui doivent modifier les données de cette table via QGIS en fonction des entités présentent sur leur territoire
- j'ai une table de territoire pour chaque utilisateur mais une entité peut intersecter deux territoires différents donc les deux utilisateurs doivent pouvoir la modifier

sur QGIS l'utilisation de la table A en totalité est un enfer car beaucoup trop lourde et je préfère proposer à l'utilisateur une couche ne représentant que ses entités à modifier en fonction de son territoire.
Je veux éviter de découper la table A en plusieurs tables, je préfère diviser les données dans des vues modifiables et que celles-ci puissent recompléter la table A.

J'ai testé une vue modifiable pour un utilisateur qui intersecte les entités de la table 'A' directement avec son territoire ==> la vue met beaucoup trop de temps à se charger sur QGIS et à l'utilisation également
j'ai besoin de gagner en performance pour la modification de ces données sur QGIS pour chaque utilisateur


J'ai donc pensé diviser ma table 'A' en vues matérialisées  'v_mat_1',  'v_mat_2', ....  et faire des vues modifiables sur ces vues matérialisées.

J'ai donc créé une fonction sur ma vue modifiable et un trigger sur cette vue


-- FUNCTION:schema1.fn_edit_v1_utilisateur1()

-- DROP FUNCTION IF EXISTS schema1.fn_edit_v1_utilisateur1();

CREATE OR REPLACE FUNCTION schema1.fn_edit_v1_utilisateur1()
    RETURNS trigger
    LANGUAGE 'plpgsql

   BEGIN
      IF TG_OP = 'UPDATE' THEN

      -- modifier la table A 

		UPDATE schema_1.table_A SET
				
			nom=NEW.nom ,
			classe=NEW.classe , 
			categorie=NEW.categorie ,
			gestionnaire=NEW.gestionnaire ,
			type_gestion=NEW.type_gestion , 			
			affichage=NEW.affichage , 
			ordre=NEW.ordre

	WHERE  schema_1.table_A.id=OLD.id ;
    
    RETURN NEW;

    -- mettre à jour la vue matérialisée
    
    REFRESH MATERIALIZED VIEW schema_1.v_mat_1_utilisateur1; 
	
	
	END IF;
	END;
	$BODY$;
    
    
-- Trigger: tg_edit_v1_utilisateur1 -- sur vue modifiable

DROP TRIGGER IF EXISTS tg_edit_v1_utilisateur1 ON schema1.v1_utilisateur1;

CREATE TRIGGER tg_edit_v1_utilisateur1
    INSTEAD OF UPDATE 
    ON schema1.v1_utilisateur1
    FOR EACH ROW
    EXECUTE FUNCTION fdppma_19.fn_edit_v_cours_eau_fd19_oui();

Lorsque je modifie la vue 'v1' pour test, je n'ai aucun message d'erreur, la modification n'est pas prise en compte sur la vue ( je suppose car elle récupère les données de la vue matérialisée qui elle même n'est pas mise à jour ).

Quelqu'un a t'il une idée sur la façon de procéder pour faire ces déclenchements les uns à la suite des autres..si cela est possible

Merci d'avance de vos lumières

#2 Re : PL/pgSQL » Nom colonne dans fonction de suivi de modification de table » 14/12/2022 13:24:00

Bonjour, merci Daniel pour ta solution JSONB, j'ai chercher un moment comment l'utiliser car je ne maîtrise pas encore le JSON mais je suis ravie du résultat.
J'ai cherché compliqué alors qu'il fallait l'utiliser comme elle était mais ça m'a fait découvrir ce type de données que je trouve très pratique.

Du coup voici ma fonction modifiée :

BEGIN

IF (TG_OP = 'UPDATE') THEN

identifiant := OLD.id_tableA;

INSERT INTO  test_suivi_tables.suivi_modif_tables (
   
    nom_schema ,
    nom_table ,
    utilisateur ,
    action ,
    id_objet_modifie ,
    date_derniere_modif,
    colonne_modif

    )

    VALUES (
        TG_TABLE_SCHEMA::TEXT,
        TG_TABLE_NAME::TEXT,
        session_user::TEXT,
        substring(TG_OP,1,1),
        identifiant,
        now(),
        ((  select (array_agg(k2)) nom_colonne
            from (select * from jsonb_each_text(row_to_json(OLD)::jsonb)) as r1(k1,v1)
            join (select * from jsonb_each_text(row_to_json(NEW)::jsonb)) as r2(k2,v2)
            on k1=k2
            where v1 is distinct from v2)::TEXT) 
        
    );
    -- pour enlever les parenthèses qui restent après changement de format de type JSON en TEXT
update tables_de_suivi.suivi_modif_tables 
      set colonne_modif = trim(both '{}' FROM "colonne_modif");
       
    );

J'ai effectué le test avec plusieurs champs modifiés sur la même ligne, je récupère bien tous les noms des champs modifiés séparés par une virgule et sans les parenthèses

#3 Re : PL/pgSQL » Nom colonne dans fonction de suivi de modification de table » 16/11/2022 10:57:10

Bonjour,

merci pour vos réponses je vais tester vos solutions.

#4 PL/pgSQL » Nom colonne dans fonction de suivi de modification de table » 14/11/2022 18:27:38

sab31
Réponses : 4

Bonjour à tous,

J'ai créé une table de suivi 'suivi_modif_tables' dans un schéma 'test_suivi' pour suivre les modifications de plusieurs autres tables lors d'INSERT, UPDATE et DELETE.

J'ai créé la fonction ci-dessous qui fonctionne très bien  et j'ai créé le trigger également sans souci.

Le problème se pose quand j'ai voulu ajouté le champ 'nom_colonne_modif' dans la table de suivi et dans la fonction car j'aimerais avoir le nom de la colonne qui a été modifiée lors de la maj.

Du coup j'ai des messages d'erreur car il ne trouve pas la colonne 'column_name'

Est-ce que quelqu'un a une idée pour compléter ma fonction ?

Merci d'avance de votre aide




CREATE OR REPLACE FUNCTION test_suivi_tables.fn_suivi_modif_tables()
    RETURNS trigger
    LANGUAGE 'plpgsql'

AS $BODY$

DECLARE

identifiant TEXT;


BEGIN

IF (TG_OP = 'UPDATE') THEN

identifiant := OLD.id_tableA;

INSERT INTO  test_suivi_tables.suivi_modif_tables (
   
    nom_schema ,
    nom_table ,
    utilisateur ,
    action ,
    id_objet_modifie ,
    date_derniere_modif,
    nom_colonne_modif

    )

    VALUES (
        TG_TABLE_SCHEMA::TEXT,
        TG_TABLE_NAME::TEXT,
        session_user::TEXT,
        substring(TG_OP,1,1),
        identifiant,
        now(),
        column_name
       
    );
       
RETURN NEW;

ELSIF (TG_OP = 'DELETE') THEN

identifiant := OLD.id_tableA;

INSERT INTO  test_suivi_tables.suivi_modif_tables (
   
    nom_schema ,
    nom_table ,
    utilisateur ,
    action ,
    id_objet_modifie,
    date_derniere_modif,
    nom_colonne_modif

    )

    VALUES (
        TG_TABLE_SCHEMA::TEXT,
        TG_TABLE_NAME::TEXT,
        session_user::TEXT,
        substring(TG_OP,1,1),
        identifiant,
        now(),
        column_name
    );

RETURN OLD;

ELSIF (TG_OP = 'INSERT') THEN

identifiant := NEW.id_tableA;

INSERT INTO  test_suivi_tables.suivi_modif_tables (
   
    nom_schema ,
    nom_table ,
    utilisateur ,
    action ,
    id_objet_modifie,
    date_derniere_modif,
    nom_colonne_modif
   

    )

    VALUES (
        TG_TABLE_SCHEMA::TEXT,
        TG_TABLE_NAME::TEXT,
        session_user::TEXT,
        substring(TG_OP,1,1),
        identifiant,
        now(),
        column_name
     
   
    );

RETURN NEW;

ELSE

RAISE WARNING '[test_suivi_tables.fn_suivi_modif_tables] - Other action occurred: %, at %', TG_OP,now();

RETURN NULL;

END IF;

END;

$BODY$

Pied de page des forums

Propulsé par FluxBB