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

SQL Oracle Discussion :

requete DELETE multi-tables


Sujet :

SQL Oracle

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 22
    Points : 17
    Points
    17
    Par défaut requete DELETE multi-tables
    Bonjour à tous,

    Je cherche à faire une requête de suppression multi-tables avec Oracle 10g.

    Je voudrais supprimer tous les éléments retournés par la requête suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT * FROM TAB_ARA, TAB_VIR
         WHERE TAB_ARA.ARA_NUM_COMPTE_CLI = TAB_VIR.VIR_NUM_COMPTE_EMET;
    j'ai donc naturellement lancé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    DELETE FROM TAB_ARA, TAB_VIR
         WHERE TAB_ARA.ARA_NUM_COMPTE_CLI = TAB_VIR.VIR_NUM_COMPTE_EMET);
    mais ca ne marche pas :
    DELETE FROM TAB_ARA, TAB_VIR
    ...............................*
    ERROR at line 1:
    ORA-00933: SQL command not properly ended
    du coup, j'ai essayé de faire une requête imbriquée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    DELETE FROM 
        ( SELECT * FROM TAB_ARA, TAB_VIR
         WHERE TAB_ARA.ARA_NUM_COMPTE_CLI = TAB_VIR.VIR_NUM_COMPTE_EMET);
    et ca renvoie :
    ORA-01752: cannot delete from view without exactly one key-preserved table
    La page suivant explique comment faire :
    http://dev.mysql.com/doc/refman/5.0/fr/delete.html
    mais c'est pour mysql. J'ai rien trouvé qui marcherait avec Oracle.

    Pouvez-vous m'aider ?

  2. #2
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 073
    Points
    19 073
    Par défaut
    c'est pas possible... le mieux c'est une foreign key avec DELETE CASCADE, quand tu supprimes le père ça supprime les fils

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 22
    Points : 17
    Points
    17
    Par défaut
    Merci pour la réponse mais il me semble qu'avec une foreign key, on doit avoir une colonne qui contient strictement les mêmes données dans les 2 tables ?

    moi je cherche à supprimer les lignes qui sont identiques, pour ne traiter que les cas problématiques.

    j'ai fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CREATE TABLE test  AS ( SELECT * FROM TAB_ARA WHERE rownum<100); 
    CREATE TABLE test2  AS ( SELECT * FROM TAB_VIR WHERE rownum<100); 
    ALTER TABLE test ADD CONSTRAINT unicite FOREIGN KEY (ARA_NUM_COMPTE_CLI) REFERENCES test2(VIR_NUM_COMPTE_EMET);
    et il me renvoie "no matching unique or primary key for this column-list".
    ce qui me parait normal vu que je sais que les 2 colonnes ne sont pas identiques.

  4. #4
    Membre confirmé Avatar de NGasparotto
    Inscrit en
    Janvier 2007
    Messages
    421
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 421
    Points : 603
    Points
    603
    Par défaut
    Peitit exemple avec le DELETE CASCADE sur une FK, et ca marche très bien :
    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
    47
    48
    49
    50
    51
    52
    SQL> CREATE TABLE test_dup  AS ( SELECT object_name, object_id, 0 as oid FROM all_objects); 
     
    Table created.
     
    SQL> CREATE TABLE test2_dup  AS ( SELECT object_name, 0 as object_id, object_id as oid FROM test_dup); 
     
    Table created.
     
    SQL> ALTER TABLE test_dup ADD CONSTRAINT unicite_pk PRIMARY KEY (object_id);
     
    Table altered.
     
    SQL> ALTER TABLE test2_dup ADD CONSTRAINT unicite_fk FOREIGN KEY (oid) REFERENCES test_dup(object_id) on delete cascade;
     
    Table altered.
     
    SQL> 
    SQL> select object_id from test_dup where object_id <= 10;
     
     OBJECT_ID
    ----------
             3
             4
             5
             7
             9
     
    SQL> select oid from test2_dup where oid <= 10;
     
           OID
    ----------
             5
             9
             3
             7
             4
     
    SQL> 
    SQL> delete test_dup where object_id <= 10;
     
    5 rows deleted.
     
    SQL> 
    SQL> select object_id from test_dup where object_id <= 10;
     
    no rows selected
     
    SQL> select oid from test2_dup where oid <= 10;
     
    no rows selected
     
    SQL>
    Nicolas.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 22
    Points : 17
    Points
    17
    Par défaut quelques précisions :
    Je cherche un moyen de supprimer des éléments qui se trouvent dans les 2 tables et ne garder dans chaque table que les éléments qui ne se trouvent pas dans l'autre.

    exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    drop table test;
    drop table test2;
    create table test (a number);
    create table test2 (b number);
    insert into test values (1);
    insert into test values (2);
    insert into test2 values (2);
    insert into test2 values (3);
     
    ALTER TABLE test ADD CONSTRAINT unicite_pk PRIMARY KEY (a);
    ALTER TABLE test2 ADD CONSTRAINT unicite_fk FOREIGN KEY (b) REFERENCES test(a) ON DELETE cascade;
    ORA-02298: cannot validate (BO.UNICITE_FK) - parent keys not found

    si j'insère les mêmes valeurs dans les 2 tables, la contrainte se crée.

    je croit que je vais regarder du coté là : http://oracle.developpez.com/faq/?pa...#errconstraint

    mais ca me parait quand meme bien compliqué ...

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 22
    Points : 17
    Points
    17
    Par défaut I think I found it
    Merci pour votre aide.

    un moyen pour faire ça est d'ajouter une foreign key sur les 2 tables et de tester les rejets de contraintes:

    1 - création de la table des exceptions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    create table exceptions(row_id rowid, owner varchar2(30), table_name varchar2(30), constraint varchar2(30));
    2 - contraintes croisées :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    ALTER TABLE test ADD CONSTRAINT unicite_pk PRIMARY KEY (a);
    ALTER TABLE test2 ADD CONSTRAINT unicite2_pk PRIMARY KEY (b);
    ALTER TABLE test ADD CONSTRAINT unicite_fk FOREIGN KEY (a) REFERENCES test2(b) exceptions into exceptions;
    ALTER TABLE test2 ADD CONSTRAINT unicite2_fk FOREIGN KEY (b) REFERENCES test(a) exceptions into exceptions;
    3 - extraction depuis la table des exceptions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    select * from test where rowid in ( select row_id from exceptions where table_name='TEST');
    select * from test2 where rowid in ( select row_id from exceptions where table_name='TEST2');
    Je teste tout de suite sur la vraie base.

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 22
    Points : 17
    Points
    17
    Par défaut arg
    ORA-02437: cannot validate (BO.VIR_PK) - primary key violated

    les colonnes ARA_NUM_COMPTE_CLI et VIR_NUM_COMPTE_EMET ne peuvent pas être déclarées en tant que clés uniques.
    ca devient compliqué là.

  8. #8
    Membre confirmé Avatar de NGasparotto
    Inscrit en
    Janvier 2007
    Messages
    421
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 421
    Points : 603
    Points
    603
    Par défaut
    Citation Envoyé par Diwann
    supprimer des éléments qui se trouvent dans les 2 tables et ne garder dans chaque table que les éléments qui ne se trouvent pas dans l'autre.
    Je ne sais pas si tu pourras faire çà en une requête (est-ce vraiment nécessaire ?), mais avec un tout petit PL/SQL, çà peut être beaucoup plus simple (à voir tout de même pour les perf.) :
    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
    47
    48
    49
    SQL> CREATE TABLE test (a number);
     
    Table created.
     
    SQL> CREATE TABLE test2 (b number);
     
    Table created.
     
    SQL> INSERT INTO test VALUES (1);
     
    1 row created.
     
    SQL> INSERT INTO test VALUES (2);
     
    1 row created.
     
    SQL> INSERT INTO test2 VALUES (2);
     
    1 row created.
     
    SQL> INSERT INTO test2 VALUES (3);
     
    1 row created.
     
    SQL> 
    SQL> begin
      2  for x in (select a from test where exists (select 1 from test2 where a=b)) loop
      3      delete test where a = x.a;
      4      delete test2 where b = x.a;
      5  end loop;
      6  end;
      7  /
     
    PL/SQL procedure successfully completed.
     
    SQL> 
    SQL> select * from test;
     
             A
    ----------
             1
     
    SQL> select * from test2;
     
             B
    ----------
             3
     
    SQL>
    Nicolas.

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 22
    Points : 17
    Points
    17
    Par défaut
    a ouais !
    trop fort.
    Merci beaucoup, je teste ca demain.

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 22
    Points : 17
    Points
    17
    Par défaut
    Ca marche.
    Thanx a lot Nicolas.

    Je vais tester les perfs maintenant, mais ca devrait aller avec < 100 000 enregistrements.

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 22
    Points : 17
    Points
    17
    Par défaut précisions sur les perfs
    Je reviens sur ce sujet pour signaler qu'après des tests réels, les perfs se sont révélées déplorables (plusieurs heures parfois pour 150 000 lignes); et pour expliquer comment on a pu réduire ça à quelques secondes.

    L'idée étant qu'il y a très peu d'enregistrements différents d'une table à l'autre, et qu'il y a des optimisations possible en diminuant le nombre de requete DELETE effectuées.

    on a donc créé une colonne supplémentaire pour indiquer les enregistrements qu'il faudra garder.
    On utilise alors le script de NGasparotto pour chercher les enregistrements présents seulement dans l'une des 2 tables en faisant un NOT EXISTS à la place du EXISTS, et à la fin on supprime en une requete tous les éléments qui ont cette colonne vide.

    code :
    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
    drop table test3;
    drop table test4;
    CREATE TABLE test3  AS ( SELECT * FROM TAB_ARA);
    CREATE TABLE test4  AS ( SELECT * FROM TAB_VIR);
    ALTER TABLE test3 ADD keep INT;
    ALTER TABLE test4 ADD keep INT;
     
    begin
        FOR x IN   (SELECT * FROM test4 WHERE NOT EXISTS 
                    (SELECT 1 FROM test3 WHERE a=b) )loop                                
            UPDATE test4 SET keep = 1 WHERE a = x.a;
        end loop;
     
        FOR x IN   (SELECT * FROM test3 WHERE NOT EXISTS 
                    (SELECT 1 FROM test4 WHERE a=b) ) loop
            UPDATE test3 SET keep = 1 WHERE b = x.b;
        end loop;   
     
        DELETE FROM test3 where keep IS NULL;
        DELETE FROM test4 where keep IS NULL;
        commit;
    end;
    /
    ALTER TABLE test3 DROP column keep;
    ALTER TABLE test4 DROP column keep;
    ce qui nous a permis de passer de 4 heures à 40 sec.

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

Discussions similaires

  1. delete multi-tables en hql
    Par gregounet dans le forum Hibernate
    Réponses: 3
    Dernier message: 05/05/2008, 19h27
  2. DELETE multi-tables avec jointures
    Par Xunil dans le forum Requêtes
    Réponses: 13
    Dernier message: 23/10/2006, 16h44
  3. [MySQL 3.23.58] delete multi-tables
    Par GLDavid dans le forum Requêtes
    Réponses: 8
    Dernier message: 07/08/2006, 11h45
  4. Problème DELETE multi-tables
    Par Gwipi dans le forum Requêtes
    Réponses: 5
    Dernier message: 22/05/2006, 08h48
  5. erreur de syntaxe DELETE multi-tables
    Par yayacameleon dans le forum Requêtes
    Réponses: 7
    Dernier message: 12/04/2006, 11h34

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