Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour,
Est-ce qu’il existe une méthode qui permet de créer dynamiquement un trigger ou de modifier le nom de la table d’un trigger donnée (existant)
En fait J’ai plusieurs tables qui sont modifiable à partir d’une application, j’ai besoin de suivre dynamiquement les modification des données (insertion, supp et update), je pourrais faire ça par création d’un trigger pour chque table statiquement mais c’est pas un solution fiable
Cordialement
Hors ligne
Bonjour,
pas des solutions!!
Hors ligne
Bonjour,
j'ai mis en place une fonctionnalité assez similaire il y a quelques années (si j'ai bien compris ton problème).
Ca passait par la création de trigger via une fonction développée en PL/SQL que l'on appelait à partir de PB.
Je construisais le code de création du trigger dynamiquement et je provoquais sa création via des EXECUTE IMMEDIATE en PL/SQL.
Si tu penses que ça peut t'aider, je peux faire des fouilles pour t'en dire plus.
Geo
Hors ligne
Bonjour,
oui c'est exactement ça mais j'ai pas pu faire ça
Hors ligne
Hors ligne
Bonjour,
ça a été développé en Oracle 8 (on est en 10 maintenant mais ce n'est plus utilisé, je ne sais donc pas si ça marche en 10).
Il faut déclarer la fonction et ses paramètres (à adapter à tes besoins) comme suit (avec AUTHID CURRENT_USER, c'est important) :
CREATE OR REPLACE FUNCTION SHEMA.swe_trigger_mk_avec_user_FU (p_a_i_table IN VARCHAR2, p_a_i_champs IN VARCHAR2, p_a_i_colonne IN VARCHAR2, p_a_i_table_mk IN VARCHAR2) RETURN VARCHAR2 AUTHID CURRENT_USER IS -- Déclarer une variable pour la syntaxe du trigger p_v_syntaxe_trigger_I VARCHAR2(5000); -- Syntaxe du CREATE TRIGGER pour l'INSERT -- Initialiser le script de création du trigger p_v_syntaxe_trigger_I := 'CREATE OR REPLACE TRIGGER SHEMA.'||p_a_i_table||'_MK_AI_TR_1 '||chr(10)|| 'AFTER INSERT ON SHEMAS.'||p_a_i_table||' '||chr(10)|| 'REFERENCING OLD AS OLD NEW AS NEW '||chr(10)|| 'FOR EACH ROW '||chr(10)|| 'DECLARE '||chr(10)|| ' p_v_id_table_old NUMBER; -- ID OLD de la table '||chr(10)|| ' p_v_id_table_new NUMBER; -- ID NEW de la table '||chr(10)|| 'BEGIN '||chr(10)|| ' p_v_id_table_old := :OLD.'||p_a_i_colonne||';'||chr(10)|| ' p_v_id_table_new := :NEW.'||p_a_i_colonne||';'||chr(10); -- Ton traitement p_v_syntaxe_trigger_I := p_v_syntaxe_trigger_I||chr(10)|| ' -- Ton traitement ICI'||chr(10)|| -- Fin p_v_syntaxe_trigger_I := p_v_syntaxe_trigger_I||chr(10)|| 'END;'; -- Finalement la création EXECUTE IMMEDIATE(p_v_syntaxe_trigger_I);
Il faut que le user ait les droits de création des triggers au niveau DB lors de l'appel.
J'espère que ça t'aidera
Conseil : fais des tests via un outil (TOAD par ex) pour la mise au point et commence par un trigger simple pour bien mettre en place tout ça. Appel via PB seulement après.
Bonne chance
Geo
Dernière modification par Geo (23-01-2012 16:17:57)
Hors ligne
Bonjour,
Merci pour vos réponses,
Mon besoin est d’exécuter la procédure envoyé "Geo" chaque fois q’une requête update est envoyée à la base, càd je dois trouver une méthode qui permet le suivi de toutes les requêtes update comme le principe des triggers DDL mais le contrôle doit se faire sur les requêtes update au lieu de alter.
Le système devrait analyser les requête envoyer à la base, s’il trouve un requête update il doit appeler la procédure suivante pour créer un trigger sur la table interrogée dans la req de mise à jour.
Hors ligne
La procédure n'est à utiliser qu'une fois pour créer le trigger sur une table donnée...
Il suffit de mettre AFTER UPDATE à la place de AFTER INSERT
Hors ligne
C’est pas ça le problème, peut ètre j’ai pas bien expliqué le besoin,
J’ai une application qui contient plus que 90 tables pour suivre l’historique de modif de chaque table je veux pas utiliser plus que 90 trigger.
Je pensais à créer dynamiquement les trigger et j’ai fait comme Geo à fait mais l’autre problème est comment exécuter cette procédure automatiquement chaque fois que l’utilisateur exécute une requête update.
Une telle idée permet d’utiliser seulement une procédure stockée et un script sql qui permet d’exécuter automatiquement la procédure chaque fois que le système détecte une requête update sur n’importe quelle table.
Ce script doit premièrement être exécuté que si on envoie une requête update à la base et deuxièmement doit trouver le nom de la table interrogée pour le passer à la procédure stockée.
Hors ligne
je pense qu'il faut que tu révises la notion de trigger
c'est justement le principe d'un trigger de faire quelque chose après chaque insert/update/delete sur une table donnée
Hors ligne
Bonjour,
t'as pas compris encors le problème
comment je peux trouver le nom de la table quia été interrogée pour que je puisse créer le trigger avec ce nom.
le problème semble un peu au principe des trigger DDL
par exemple le trigger ddl detecte automatiquemt les modifications des structure par exemple alter sur table pour ajouter un colonne et tu pourrais recuperer dynamiquement le nom de la table.
moi je veux suivre le mème principe pour les requetes de mise à jours, je veux recuperer dynamiquement le nom de la table interrogée ensuite l'etape de création des trigger qui est trés facile.
Hors ligne
il faut que tu crées un trigger par table/champ...
Code: sql
SET SERVEROUTPUT ON SIZE 1000000 SET VERIFY OFF SET TRIMSPOOL ON DECLARE v_owner VARCHAR2(30) := UPPER('&1'); v_table VARCHAR2(30) := UPPER('&2'); CURSOR c_columns IS SELECT column_name FROM all_tab_columns WHERE owner = v_owner AND table_name = v_table; BEGIN DBMS_OUTPUT.PUT_LINE('CREATE OR REPLACE TRIGGER ' || v_table || '_aiudr_trg'); DBMS_OUTPUT.PUT_LINE('AFTER INSERT OR UPDATE OR DELETE ON ' || v_table); DBMS_OUTPUT.PUT_LINE('FOR EACH ROW'); DBMS_OUTPUT.PUT_LINE('DECLARE'); DBMS_OUTPUT.PUT_LINE(' PRAGMA AUTONOMOUS_TRANSACTION;'); DBMS_OUTPUT.PUT_LINE(' v_action VARCHAR2(30) := ''NONE'';'); DBMS_OUTPUT.PUT_LINE('BEGIN'); DBMS_OUTPUT.PUT_LINE(' IF INSERTING THEN'); DBMS_OUTPUT.PUT_LINE(' v_action := ''INSERT'';'); DBMS_OUTPUT.PUT_LINE(' ELSIF UPDATING THEN'); DBMS_OUTPUT.PUT_LINE(' v_action := ''UPDATE'';'); DBMS_OUTPUT.PUT_LINE(' ELSIF DELETING THEN'); DBMS_OUTPUT.PUT_LINE(' v_action := ''DELETE'';'); DBMS_OUTPUT.PUT_LINE(' END IF;'); DBMS_OUTPUT.PUT_LINE(' tsh_audit.insert_log ('); DBMS_OUTPUT.PUT_LINE(' SYS_CONTEXT(''USERENV'',''CLIENT_IDENTIFIER''),'); DBMS_OUTPUT.PUT_LINE(' ''' || v_table || ''','); DBMS_OUTPUT.PUT_LINE(' v_action,'); FOR cur_rec IN c_columns LOOP IF c_columns%ROWCOUNT > 1 THEN DBMS_OUTPUT.PUT_LINE('||'); END IF; DBMS_OUTPUT.PUT(' ''NEW.' || cur_rec.column_name || '=['' || :NEW.' || cur_rec.column_name || ' || ''] ' || 'OLD.' || cur_rec.column_name || '=['' || :OLD.' || cur_rec.column_name || ' || '']'' '); END LOOP; DBMS_OUTPUT.NEW_LINE; DBMS_OUTPUT.PUT_LINE(' );'); DBMS_OUTPUT.PUT_LINE(' COMMIT;'); DBMS_OUTPUT.PUT_LINE('END;'); DBMS_OUTPUT.PUT_LINE('/'); DBMS_OUTPUT.PUT_LINE('SHOW ERRORS'); END; /
The script should be saved on the filesystem as audit_trigger.sql and called as follows.Code: sql
SQL> @audit_trigger my_schema my_table
Hors ligne
Merci admin je vais essayer d’adapter ta proposition à mon besoin mais j’ai deux questions
Tu veux dire par filesystem (le repertoire ou j’ai installé l’oracle dans \bin) ?
Je dois mette quoi exactement dans la chaine my_schema et my_table
Hors ligne
infopower a écrit:
Tu veux dire par filesystem (le repertoire ou j’ai installé l’oracle dans \bin) ?
filesystem = système de fichiers, en gros ton disque dur...
(c'est pas moi qui le dit, hein!)
infopower a écrit:
Je dois mette quoi exactement dans la chaine my_schema et my_table
bah le nom de ton schéma et la table sur laquelle tu veux créer les triggers d'audit de chaque colonne
Hors ligne