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 :

2 updates consécutifs, ordre d'exécution aléatoire..


Sujet :

PL/SQL Oracle

  1. #1
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    457
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 457
    Par défaut 2 updates consécutifs, ordre d'exécution aléatoire..
    Bonjour à tous,

    Je vous expose mon soucis :
    J'ai dû reprendre le code d'une autre personne.
    C'est une procédure stockée sous oracle 10g où 2 updates sont effectués sur la même ligne.
    Le premier sert à mettre la ligne à vide afin de s'assurer que les données soient réinitialisées si aucune nouvelle donnée n'est disponible.
    La deuxième permet de mettre à jour les bonnes données s'il y en a.

    Le problème est que, parfois, le deuxième update s'exécute avant le premier !
    On a donc les données qui sont bien updatées mais ensuite, la ligne est remise à null !
    J'ai même tenté de mettre un commit après le premier update mais sans succès.
    Lorsque je regarde l'heure et la date à laquelle chacune a été exécutée, elles ont toutes les deux EXACTEMENT le même timestamp.

    Voici la procédure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
     Procedure MyProc()
     AS
      myField1 number,
      myField2 number,
      myField3 number,
      myField4 number,
      CURSOR MYCURSOR IS   
        select  c1,c2,c3,c4
        from TableA  where c4 IS NOT NULL;
     BEGIN
     
      update SCHEMA.TableB  
            set   
                f1 = null,   
                f2 = null,   
                f3 = null;   
     
     
            OPEN MYCURSOR;   
     
            LOOP   
     
            FETCH MYCURSOR INTO myField1,   
                    myField2,   
                    myField3,
    				myField4;   
     
            EXIT WHEN MYCURSOR%NOTFOUND;   
        update SCHEMA.TableB   
            set   
                f1 = myField1,   
                f2 = myField2,   
                f3 = myField3 
            where idField = c4;   
     
        END LOOP;   
     
            CLOSE MYCURSOR;   
     
     END MyProc;
    Je ne désire pas trouver de solution altérnative ou de code optimisé, c'est déjà fait.
    Je cherche juste à comprendre le pourquoi du comment


    Merci d'avance.

  2. #2
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 454
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 454
    Par défaut
    Non impossible, ça se fait dans l'ordre.
    Si les données restent à null, c'est que le curseur renvoie null.

    Et non ce code n'est pas optimisé, c'est même plutôt très mauvais.

  3. #3
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    457
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 457
    Par défaut
    non non, j'ai une table d'audit sur cette table, je peux assurer que le curseur ne renvoit pas null.. On voit les valeurs passer de X à null ou de null à X

  4. #4
    Expert confirmé Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Par défaut
    Le première update mets à jour tout la table, le deuxième seulement certaines lignes. Ce n'est pas que ce code n'est pas optimisé c'est que c'est du grand n'importe quoi.

  5. #5
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    457
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 457
    Par défaut
    Non non, il y a un autre update plus haut.
    Les deux updates mettent à jour exactement le même nombre de lignes.
    ça fonctionne c'est en place depuis des années donc ce n'est pas du si grand n'importe quoi que ça.

    Là n'était pas la question.. J'avais prévenu mais je me doutais que des commentaires pareils arriveraient.

  6. #6
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Comment peux tu dire que tu mets à jour le même nombre de lignes
    Ton code est équivalent à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    UPDATE SCHEMA.TableB  
    SET f1 = NULL, f2 = NULL, f3 = NULL;   
     
     
    UPDATE SCHEMA.TableB   
    SET  (f1, f2, f3) =  (SELECT c1,c2,c3
                          FROM TableA a
                          WHERE a.c4 IS NOT NULL
                          AND a.c4 = b.idField
                          AND ROWNUM = 1)
    WHERE EXISTS 
        (SELECT  1 
        FROM TableA a
        WHERE a.c4 IS NOT NULL
        AND a.c4 = b.idField);
    Si tu as 2 lignes de TableA avec le même c4 mais que l'une des lignes a c1,c2,c3 de NULL et que ton curseur la fait passer en second (aucun tri, c'est aléatoire), et bien tu remets à NULL les champs f1 déjà renseigné par la ligne d'avant.

    ça fonctionne c'est en place depuis des années donc ce n'est pas du si grand n'importe quoi que ça.
    justement, plus le code est vieux, plus il a de chances d'être obsolète

  7. #7
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    457
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 457
    Par défaut
    Comme je l'ai dit, ma question n'était pas de savoir comment optimiser le code, mais bien de comprendre pourquoi deux instructions ne s'exécutent pas dans l'ordre attendu ^^

    Une première requête synchronise la table A avec le table B, on est certain de n'avoir dans celle-ci que les enregistrements de même identifiant à Table B. Mais c'est toute une autre histoire en dehors du scope de cette discussion

    Je suis tout à fait d'accord que le code n'est pas clair et propre.
    Malgré le fait qu'il ait été revu et modifié, j'aime comprendre les choses qui m'échappent ! d'où ce post

    Bien à vous!

  8. #8
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Une première requête synchronise la table A avec le table B, on est certain de n'avoir dans celle-ci que les enregistrements de même identifiant à Table B. Mais c'est toute une autre histoire en dehors du scope de cette discussion
    Le problème c'est que tu nous demandes une explication, et tu ne donnes pas tout ce qu'il faut pour qu'on comprenne ton code. Ce n'est pas en dehors du scope, car mon explication précédente est possible, tout dépend de TableA.
    Le code que j'ai mis n'est pas donné pour optimiser, mais pour avoir un code plus clair.


    mais bien de comprendre pourquoi deux instructions ne s'exécutent pas dans l'ordre attendu ^^
    Tu as OBLIGATOIREMENT le premier update qui met à NULL les champs qui passe.
    Et ensuite ton curseur qui met à jour.
    En aucun cas, l'update du début ne peut passer après l'update du curseur.

    Donc, donne nous le code complet avec les PK et Index uniques de tes 2 tables.

  9. #9
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    457
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 457
    Par défaut
    TableA : c1,c2,c3 fk vers TableB = fk
    TableB : f1,f2,f3 pk = cID

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
     Procedure MyProc()
     AS
      myField1 number,
      myField2 number,
      myField3 number,
      myIDField number,
      CURSOR MYCURSOR IS   
        select  c1,c2,c3,fk
        from TableA  where fk IS NOT NULL;
     BEGIN
     
      update tableA tA   
            set   
            fk = (select min(cID) from tableB
            where trim(tableB.somefield) = trim(tA.somefield));   
     
      update SCHEMA.TableB  
            set   
                f1 = null,   
                f2 = null,   
                f3 = null;   
     
     
            OPEN MYCURSOR;   
     
            LOOP   
     
            FETCH MYCURSOR INTO myField1,   
                    myField2,   
                    myField3,
    								myIDField;   
     
            EXIT WHEN MYCURSOR%NOTFOUND;   
        update SCHEMA.TableB   
            set   
                f1 = myField1,   
                f2 = myField2,   
                f3 = myField3 
            where cID = myIDField;   
     
        END LOOP;   
     
            CLOSE MYCURSOR;   
     
     END MyProc;
    C'est ce que j'aurais dit aussi, si je n'étais pas d'accord avec toi, je ne serais pas en train de poster cette question..
    Je ne comprends vraiment pas le pourquoi mais les faits sont là !

  10. #10
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 454
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 454
    Par défaut
    Vous ne faites pas des exécutions parallèles de votre procédure ?

  11. #11
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Que donne cette requete (Liste des clés qui ont des données NULL et des données NOT NULL) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    select fk FROM tableA tA   
    GROUP BY fk
    having min( NVL(c1 || c2 || c3, chr(2))) <> max( NVL(c1 || c2 || c3, chr(2)))
    and min( NVL(c1 || c2 || c3, chr(2))) = chr(2)

  12. #12
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    457
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 457
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Vous ne faites pas des exécutions parallèles de votre procédure ?
    Qu'est-ce que vous entendez par là ?
    Je pense qu'elle est exécutée X fois d'affilée..

  13. #13
    Expert confirmé Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Par défaut
    Citation Envoyé par libuma Voir le message
    non non, j'ai une table d'audit sur cette table, je peux assurer que le curseur ne renvoit pas null.. On voit les valeurs passer de X à null ou de null à X
    Donc vous avez des triggers aussi sur ces tables ?

  14. #14
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    457
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 457
    Par défaut
    Citation Envoyé par McM Voir le message
    Que donne cette requete (Liste des clés qui ont des données NULL et des données NOT NULL) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    select fk FROM tableA tA   
    GROUP BY fk
    having min( NVL(c1 || c2 || c3, chr(2))) <> max( NVL(c1 || c2 || c3, chr(2)))
    and min( NVL(c1 || c2 || c3, chr(2))) = chr(2)
    Aucune ligne sélectionnée.

  15. #15
    Membre éclairé
    Inscrit en
    Février 2008
    Messages
    457
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 457
    Par défaut
    Citation Envoyé par mnitu Voir le message
    Donc vous avez des triggers aussi sur ces tables ?
    Oui mais qui n'agit pas sur cette table

  16. #16
    Expert confirmé Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Par défaut
    Citation Envoyé par libuma Voir le message
    Oui mais qui n'agit pas sur cette table
    Pouvons-nous les voir ?

Discussions similaires

  1. [PDO] Pdo : bind update avec :var et ? ( ordre d'exécution)
    Par Valkirion dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 19/03/2012, 17h53
  2. Réponses: 4
    Dernier message: 18/11/2011, 09h12
  3. Ordre d'exécution de la requête
    Par raf_gug dans le forum Requêtes
    Réponses: 4
    Dernier message: 19/04/2006, 10h30
  4. [MySQL] update qui ne s'exécute uniquement la deuxième fois !
    Par isa150183 dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 29/01/2006, 09h58
  5. Ordre d'exécution dans une jointure externe
    Par Pero dans le forum Langage SQL
    Réponses: 17
    Dernier message: 20/09/2005, 12h22

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