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 :

Problème de synchronisation entre deux tables sans clef primaire


Sujet :

PL/SQL Oracle

  1. #1
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Points : 7 083
    Points
    7 083
    Par défaut Problème de synchronisation entre deux tables sans clef primaire
    Bonjour à tous,


    J'ai un petit soucis concernant une bête synchronisation entre deux tables en utilisant BULK COLLECT / FORALL.
    Mes enregistrements n'ont pas de clé primaire et se composent uniquement de "clés" dont l'une des valeurs peut-être null.
    Exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    CREATE TABLE FOO(
      A VARCHAR2(250) NOT NULL,
      B VARCHAR2(250),
      C VARCHAR2(250) NOT NULL);
    Pour gérer la suppression des données périmées, j'ai un code du style:
    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
    DECLARE
      FOO_ARRAY_TYPE IS TABLE OF FOO%ROWTYPE;
      FOO_ARRAY FOO_ARRAY_TYPE;
      FOO_DEL_CURSOR IS
        SELECT old.A, old.B, old.C FROM FOO old
        MINUS
        SELECT new.A, new.B, new.C FROM BAR new;
    BEGIN
      OPEN FOO_DEL_CURSOR;
      LOOP
        FETCH FOO_DEL_CURSOR BULK COLLECT INTO FOO_ARRAY LIMIT 50000;
        FORALL i IN FOO_ARRAY.FIRST ... FOO_ARRAY.LAST
          DELETE FOO WHERE ???;
        COMMIT;
        EXIT WHEN FOO_DEL_CURSOR%NOTFOUND;
      END LOOP;
    END;
    Pour mes autres tables, je mettais le MINUS dans une sous-vue et je récupérai que les clés primaires. Et pour le delete je mettais les clés primaires dans le WHERE.
    Ma question est comment faire sans clé primaire ?
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  2. #2
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 814
    Points
    17 814
    Par défaut
    Citation Envoyé par Nemek Voir le message
    Ma question est comment faire sans clé primaire ?
    Vous pouvez utiliser la pseudo-colonne ROWID, et le PL/SQL n'est pas obligatoire ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    DELETE FROM FOO
     WHERE rowid in (select rowid
                       from FOO
                      where (A, B, C) in (select A, B, C from FOO
                                           minus
                                          select A, B, C from BAR));

  3. #3
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Points : 7 083
    Points
    7 083
    Par défaut
    1. Le IN ne fonctionne pas (valeur NULLable)
    2. PL/SQL obligatoire pour utiliser BULK COLLECT / FORALL LIMIT. Que j'utilise sinon j'explose mon UNDO. Plusieurs centaines millions d'enregistrements impactés.
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  4. #4
    Expert éminent sénior 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
    Points : 11 252
    Points
    11 252
    Par défaut
    Utilisez Nvl pour les "valeurs" nulles.

    </Edit>
    Et quelle est la volumétrie de la table après le delete ?

  5. #5
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 814
    Points
    17 814
    Par défaut
    Citation Envoyé par Nemek Voir le message
    Le IN ne fonctionne pas (valeur NULLable)
    En effet, mais vous pouvez toujours utiliser un EXISTS.
    Edit : ou un nvl oui.

    Citation Envoyé par Nemek Voir le message
    PL/SQL obligatoire pour utiliser BULK COLLECT / FORALL LIMIT
    C'est une bonne raison, mais la logique reste la même : récupérez la liste des rowid qui ne sont plus valide et supprimez dessus.

    Sinon, si c'est pour remettre à l'identique une table par rapport à une autre, avez-vous envisagé ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    truncate table foo;
     
    insert /*+ append */ into foo select a,b,c from bar;
    Même si je suis conscient que la faisabilité dépend du reste des traitements, des volumétries des données modifiées et sûrement d'autres paramètres.

  6. #6
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Points : 7 083
    Points
    7 083
    Par défaut
    Je rajoute comme contrainte que les données de FOO doivent rester consultable Et toutes les données de FOO ne sont pas à supprimer. J'ai en fait plusieurs sources de données chacune étant responsable de ses données.

    D'ailleurs le principe c'est de construire la table BAR qui sera une image partielle de FOO et de synchroniser qu'un sous-ensemble de FOO.

    Sinon je vois pas en quoi NVL va régler mon problème

    Finalement j'ai trouvé ma solution toute bête !
    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
    DECLARE
      FOO_A_TYPE IS TABLE OF FOO.A%TYPE;
      FOO_A FOO_A_TYPE;
      FOO_B_TYPE IS TABLE OF FOO.B%TYPE;
      FOO_B FOO_B_TYPE;
      FOO_C_TYPE IS TABLE OF FOO.C%TYPE;
      FOO_C FOO_C_TYPE;
      FOO_DEL_CURSOR IS
        SELECT old.A, old.B, old.C FROM FOO old
        MINUS
        SELECT new.A, new.B, new.C FROM BAR new;
    BEGIN
      OPEN FOO_DEL_CURSOR;
      LOOP
        FETCH FOO_DEL_CURSOR BULK COLLECT INTO FOO_A, FOO_B, FOO_C LIMIT 50000;
        FORALL i IN FOO_A.FIRST ... FOO_A.LAST
          DELETE FOO WHERE A=FOO_A(i) AND C=FOO_C(i) AND ((B IS NULL AND FOO_B(i) IS NULL) OR B=FOO_B(i));
        COMMIT;
        EXIT WHEN FOO_DEL_CURSOR%NOTFOUND;
      END LOOP;
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  7. #7
    Expert éminent sénior 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
    Points : 11 252
    Points
    11 252
    Par défaut
    Citation Envoyé par Nemek Voir le message
    ...
    Sinon je vois pas en quoi NVL va régler mon problème
    ...
    Vous pouvez écrire à la place de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    AND ((B IS NULL AND FOO_B(i) IS NULL) OR B=FOO_B(i));
    Ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    AND Nvl(B, 'VALEUR IMPOSSIBLE') = Nvl(FOO_B(i), 'VALEUR_IMPOSSIBLE')

  8. #8
    Expert éminent sénior 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
    Points : 11 252
    Points
    11 252
    Par défaut
    Citation Envoyé par Nemek Voir le message
    Je rajoute comme contrainte que les données de FOO doivent rester consultable Et toutes les données de FOO ne sont pas à supprimer. J'ai en fait plusieurs sources de données chacune étant responsable de ses données.

    D'ailleurs le principe c'est de construire la table BAR qui sera une image partielle de FOO et de synchroniser qu'un sous-ensemble de FOO.
    ...
    Ca a l’air d’une usine à gaz mais bon peut être que je n’ai pas tout compris.

  9. #9
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Points : 7 083
    Points
    7 083
    Par défaut
    Citation Envoyé par mnitu Voir le message
    Vous pouvez écrire à la place de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    AND ((B IS NULL AND FOO_B(i) IS NULL) OR B=FOO_B(i));
    Ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    AND Nvl(B, 'VALEUR IMPOSSIBLE') = Nvl(FOO_B(i), 'VALEUR_IMPOSSIBLE')
    J'aime pas trop l'idée, surtout que ca peut être n'importe quoi dans ce champ c'est une sorte de label.

    Citation Envoyé par mnitu Voir le message
    Ca a l’air d’une usine à gaz mais bon peut être que je n’ai pas tout compris.
    Bof. Le principe est simple, je met à jour mes données via des fichiers ou des bases de données externes. J'ai un champ qui m'indique la source et elle fait partie de la clé (ex: le champ A).

    Ensuite, j'ai une application qui a un taux de disponibilité de 98% panne incluse, soit 100% hors panne. Donc mes données doivent toujours être consultables.

    Le principe est donc de construire des images du résultat attendu (ou une partie dans mon cas) dans une table temporaire, enfin de synchroniser les deux tables. C'est un problème tout à fait classique !
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  10. #10
    Expert éminent sénior 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
    Points : 11 252
    Points
    11 252
    Par défaut
    Fichier implique table externe.
    Autre source implique Oracle database gateways.
    Et pour le reste Oracle sait gérer, pas le besoin de tout stocker dans des tables temporaires.

    Mais bon le monde est souvent imparfait et des autres solutions sous-optimales s’imposent en pratique.

  11. #11
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Points : 7 083
    Points
    7 083
    Par défaut
    Merci pour ces infos.

    Citation Envoyé par mnitu Voir le message
    Fichier implique table externe.
    Déjà ca suppose qu'il s'agit d'un fichier plat. C'est bon c'est mon cas.
    Ca suppose que le fichier soit au même format que la table, là ca coince. Ca suppose également que les données ne necessite pas de caclul complexe, pas bon non plus. Ni même qu'on est besoin d'index encore, ca va pas non plus. Ca implique également d'avoir un accès physique au serveur de BD, ce n'est pas non plus mon cas.
    Je prefère avoir une table et la chargé avec SQL*Loader. C'est ce que je fais d'ailleurs pour ces fichiers plats.

    Citation Envoyé par mnitu Voir le message
    Autre source implique Oracle database gateways
    Ou un bon vieux DB link. Cependant j'ai toujours le même problème de format de donner et d'index. Et je parle pas du taux de disponibilité ...

    Citation Envoyé par mnitu Voir le message
    Et pour le reste Oracle sait gérer, pas le besoin de tout stocker dans des tables temporaires.
    Sauf qu'un UNDO tablepace inutile de 20Go (uniquement avec un échantillon), je préfère m'en passer. Et j'ai pas regarde la taille du TEMP pour mes calculs
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [MySQL] Probléme de jointure entre deux tables
    Par super-java dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 12/06/2008, 15h49
  2. Réponses: 4
    Dernier message: 09/11/2007, 19h08
  3. [XI] Problème de lien entre deux tables
    Par campia dans le forum SAP Crystal Reports
    Réponses: 6
    Dernier message: 29/09/2007, 05h49
  4. [DEBUTANT]Problème de relation entre deux tables
    Par Yomane dans le forum Schéma
    Réponses: 2
    Dernier message: 20/10/2006, 02h30
  5. Problème de relation entre deux tables + autre chose
    Par Goth_sensei dans le forum Langage SQL
    Réponses: 7
    Dernier message: 30/03/2006, 21h49

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