IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PL/SQL Oracle Discussion :

Trigger qui traite un ensemble de lignes


Sujet :

PL/SQL Oracle

  1. #1
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 170
    Points : 7 422
    Points
    7 422
    Billets dans le blog
    1
    Par défaut Trigger qui traite un ensemble de lignes
    Bonjour,

    Après une discussion il y a quelques temps avec SQL Pro sur la section SQL Server, j'ai été convaincu qu'un trigger ne doit pas traiter les lignes modifiées "une à une", mais toutes ensembles en une seule fois.

    Pour rappel, dans SQL Server "for each row" n'existe pas, et en lieu et place, il faut faire un curseur, ce qui est contre-performant.

    Donc, pour un trigger sur la table "produit" sur la suppression, on va faire par exemple :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    create trigger mon_trigger
    on produit
    before delete
    as
    begin
       delete prix where product_id in (select id from deleted);
    end;

    Donc pour 1000 produits supprimés par exemple, une seule instruction DELETE sur la table prix pour supprimer l'ensemble des lignes.

    Comment faire avec Oracle ?

    Car jusqu'à présent, je n'ai pas trouvé de doc qui explique comment faire.

    A chaque fois (y compris sur le site de la doc officielle) soit je trouve des exemple "for each row", soit des exemples où on n'a pas accès aux tables virtuelles inserted et deleted.

    C'est possible ou si je dois me résigner ?

    Je pose cette question car j'ai un DEV à faire où je vais potentiellement avoir des dizaines de milliers de lignes à traiter dans un trigger, et l'opération étant très simple, j'aurais préféré pouvoir faire la modification en masse plutôt que ligne à ligne.

  2. #2
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 170
    Points : 7 422
    Points
    7 422
    Billets dans le blog
    1
    Par défaut
    Grmpf

    Je croyais avoir trouvé la solution en utilisant l'assistant de SQL Developer, mais visiblement il me manque un truc...

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     CREATE OR REPLACE TRIGGER GD_T_TAL_AFT_D 
    AFTER DELETE ON TAL 
    REFERENCING OLD AS deleted 
    BEGIN
      update zod
      set valzod = ' '
      where zod.typzod = 'PRO'
      and zod.numzod = 997
      and (zod.codsoc, zod.clezod) in (select deleted.codsoc, deleted.codpro from deleted inner join tal on tal.codsoc = deleted.codsoc and tal.numelabo = deleted.numelabo and tal.achvte = deleted.achvte and tal.typenr = 'E' where deleted.typenr = 'L' and deleted.achvte = 'V' and tal.typela = 'PER');
    END;
    => Il me dit que la table "deleted" n'existe pas, marlgré le "referencing"...

    Aussi, je me rends compte que je vais me bouffer un souci de table mutating dans la tête non ? Vu que je tente de faire une jointure avec la table sur laquelle porte le trigger...

  3. #3
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 950
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 950
    Points : 5 849
    Points
    5 849
    Par défaut
    Il faut bien comprendre que la gestion de la concurrence d'accès d'oracle (MVCC) et celle de sqlserver en mode classique (non snapshot même si très différent de l'implémentation d'oracle) sont totalement différentes.

    Chaque implémentation a ses avantages et ses inconvénients.
    L'architecture MVCC (en général et en particulier celle d'oracle) évite les problèmes d'escalade de verrous, en contre partie par exemple l'écriture des triggers est plus complexe, souvent moins performantes car il n'existe pas de table inserted et autre. Donc on ne peut généralement pas travailler en mode ensembliste dans un trigger oracle.

    D'ailleurs certains experts recommandent d'éviter les triggers à cause de la difficulté pour gérer la concurrence d'accès correctement, notamment quand le développeur ne maitrise pas bien le concept de lecture consistante.

    Votre premier trigger s'écrirait de façon classique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    CREATE TRIGGER mon_trigger 
    before DELETE ON produit 
    for each row
    begin
       DELETE prix WHERE product_id = :old.id;
    end;
    Cependant à partir de la 11GR2 vous pouvez développer des COMPOUND TRIGGERS qui permettent de lever certaines restrictions et d'améliorer la performance en travaillant de façon plus ensembliste.

    Je vous laisse regarder les exemples, revenez avec un test case compilable en cas de soucis dans l'implémentation du dit trigger.

  4. #4
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 950
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 950
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    Je pose cette question car j'ai un DEV à faire où je vais potentiellement avoir des dizaines de milliers de lignes à traiter dans un trigger, et l'opération étant très simple, j'aurais préféré pouvoir faire la modification en masse plutôt que ligne à ligne.
    Utiliser un trigger pour faire des milliers de modifications est effectivement une approche douteuse sur oracle.
    Pourquoi ne pas faire ces modifications dans la transaction elle même ? (à moins que pas la main sur le code de l'appli)

  5. #5
    Rédacteur

    Homme Profil pro
    Consultant / formateur Oracle et SQL Server
    Inscrit en
    Décembre 2002
    Messages
    3 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant / formateur Oracle et SQL Server

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 461
    Points : 8 079
    Points
    8 079
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    ...REFERENCING OLD AS deleted...
    La clause REFERENCING n'a de sens que dans le contexte d'un déclencheur de niveau ligne, le fameux FOR EACH ROW. De plus, elle ne sert qu'à donner un nom personnalisé aux pseudo variables :NEW et :OLD.
    NEW et OLD, ou tout autre nom que vous leur donnerez à travers la clause REFERENCING, sont des variables monolignes (équivalent d'un %ROWTYPE) qui contiennent les valeurs de la ligne en cours de traitement respectivement après et avant la modification.
    NEW et OLD ne sont en aucun cas des variables multilignes.

    D'ailleurs, la clause REFERENCING, en toute généralité, n'a aucun intérêt pratique.

  6. #6
    Expert éminent
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Points : 6 446
    Points
    6 446
    Billets dans le blog
    1
    Par défaut
    Bonjour,
    Quel est le besoin initial ? Ce n'est probablement pas un trigger qui est la bonne solution sous Oracle.
    Si c'est pour faire un delete cascade, c'est possible via contrainte d'intégrité.
    Cordialement,
    Franck.

Discussions similaires

  1. Macro qui compile l'ensemble des lignes rouges des onglets précédents
    Par Manu8586 dans le forum Macros et VBA Excel
    Réponses: 9
    Dernier message: 13/02/2015, 23h27
  2. [XL-2010] Macro qui compile l'ensemble des lignes rouges des onglets précédents
    Par mama35_8 dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 28/01/2015, 19h32
  3. Réponses: 0
    Dernier message: 28/03/2012, 11h11
  4. Regex qui traite les sauts de lignes
    Par sampaiX dans le forum Entrée/Sortie
    Réponses: 5
    Dernier message: 26/06/2010, 12h04
  5. Réponses: 0
    Dernier message: 17/12/2009, 10h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo