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

DB2 Discussion :

DELETE lignes dont la clé est dans une table et absente d'une autre


Sujet :

DB2

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur COBOL
    Inscrit en
    Juin 2014
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur COBOL
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2014
    Messages : 1
    Points : 1
    Points
    1
    Par défaut DELETE lignes dont la clé est dans une table et absente d'une autre
    Bonjour,

    Je travaille actuellement sur 2 tables dans la configuration suivante

    TABLE1
    CODE1 PIC 9(005) (clé primaire)
    TS1 PIC X(026) (clé primaire)
    Données ...

    TABLE2
    CODE1 PIC 9(005) (clé primaire)
    TS1 PIC X(026) (clé primaire)
    CPT1 PIC 9(003) (clé primaire)
    Données ...

    Normalement, les lignes dans TABLE2 doivent avoir leur équivalent dans TABLE1 avec le même CODE1 et le même TS1. Mais, chez mon client, il n'y a pas de contrainte d'intégrité référentielle. Du coup on trouve des lignes présentes dans TABLE2 et pas dans TABLE1 ce qui fait planter des programmes.

    Je dois donc développer un programme qui supprime les lignes présentes dans TABLE2 sans équivalent dans TABLE1 mais j'ai des contraintes à respecter au niveau des requêtes DB2 :
    - Pas de requête imbriquée ou sous-requête
    - Pas de FETCH pour modification

    J'ai donc essayé ça :
    DELETE
    FROM TEST.TABLE2 B
    LEFT OUTER JOIN TEST.TABLE1 A
    ON (A.CODE1 = B.CODE1
    AND A.TS1 = B.TS1)
    WHERE A.CODE1 IS NULL
    ;

    Mais SPUFI n'a pas aimé :
    SQLCODE = -199, ERROR: ILLEGAL USE OF KEYWORD LEFT. TOKEN INCLUDE
    <END-OF-STATEMENT> QUERYNO WHERE SKIP WITH SET WAS EXPECTED
    SQLSTATE = 42601 SQLSTATE RETURN CODE
    SQLERRP = DSNHPARS SQL PROCEDURE DETECTING ERROR
    SQLERRD = 2 0 0 -1 151 506 SQL DIAGNOSTIC INFORMATION
    SQLERRD = X'00000002' X'00000000' X'00000000' X'FFFFFFFF'
    X'00000097' X'000001FA' SQL DIAGNOSTIC INFORMATION

    Alors qu'il accepte très bien :
    SELECT *
    FROM TEST.TABLE2 B
    LEFT OUTER JOIN TEST.TABLE1 A
    ON (A.CODE1 = B.CODE1
    AND A.TS1 = B.TS1)
    WHERE A.CODE1 IS NULL
    ;

    Cela me retourne très bien les lignes incriminées.
    Si j'avais la possibilité de faire du DELETE sur des lignes fetchées, j'aurais déjà la solution, mais c'est interdit.

    Quelqu'un aurait-il une solution pour réaliser cela sans requête imbriquée et sans DELETE sur un FETCH ?

    Merci d'avance !

  2. #2
    Membre expert
    Homme Profil pro
    Retraité
    Inscrit en
    Octobre 2005
    Messages
    1 473
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Finance

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 473
    Points : 3 283
    Points
    3 283
    Par défaut
    Citation Envoyé par Samuel_Vimaire Voir le message
    ...
    Je dois donc développer un programme qui supprime les lignes présentes dans TABLE2 sans équivalent dans TABLE1 mais j'ai des contraintes à respecter au niveau des requêtes DB2 :
    - Pas de requête imbriquée ou sous-requête
    - Pas de FETCH pour modification
    Mon dieu ... encore un exemple de règles débiles ...


    Mais SPUFI n'a pas aimé
    Normal ... la notion de jointure ne s'applique qu'au SELECT ...


    Quelqu'un aurait-il une solution pour réaliser cela sans requête imbriquée et sans DELETE sur un FETCH ?
    Est ce que la récupération de la clé primaire sur un curseur puis un DELETE direct sur la clé ainsi récupérée est permis ?

  3. #3
    Membre actif
    Homme Profil pro
    Architecte technique & logiciel IBM i
    Inscrit en
    Septembre 2010
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte technique & logiciel IBM i
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2010
    Messages : 179
    Points : 275
    Points
    275
    Par défaut
    Bonjour

    Cette instruction devrait faire ce que tu veux :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    delete
    from test.table2 a
    where not exists (select '*' from test.table1 b where b.code1=a.code1 and b.ts1=a.ts1) ;

  4. #4
    Membre chevronné Avatar de bernard59139
    Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2006
    Messages
    950
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Octobre 2006
    Messages : 950
    Points : 2 064
    Points
    2 064
    Par défaut
    Citation Envoyé par pwrdwnsys Voir le message
    Bonjour

    Cette instruction devrait faire ce que tu veux :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    delete
    from test.table2 a
    where not exists (select '*' from test.table1 b where b.code1=a.code1 and b.ts1=a.ts1) ;
    Il y a une sous-requete, donc pas adapté à la demande. J'aurais bien aussi proposé........

  5. #5
    Membre actif
    Homme Profil pro
    Architecte technique & logiciel IBM i
    Inscrit en
    Septembre 2010
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte technique & logiciel IBM i
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2010
    Messages : 179
    Points : 275
    Points
    275
    Par défaut
    Citation Envoyé par bernard59139 Voir le message
    Il y a une sous-requete, donc pas adapté à la demande. J'aurais bien aussi proposé........
    Effectivement (j'avais zappé ce postulat ridicule), mais du coup, s'il faut vraiment se plier à des règles totalement dépassées, il ne faut plus faire de SQL et il faut développer des programmes de quelques dizaines de lignes pour faire la même chose de manière moins lisible et avec probablement plus de risque de bogue...
    Et du coup, en SQL, je ne vois aucune solution autre qu'une sous-requête, puisque la valeur de la clé est externe...

  6. #6
    Membre chevronné Avatar de bernard59139
    Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2006
    Messages
    950
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Octobre 2006
    Messages : 950
    Points : 2 064
    Points
    2 064
    Par défaut
    Je connais ce genre de règles "ridicules", souvent faites pour éviter que des personnes mettent à jour des tables avec des LOCK qui durent, qui durent.................
    @ +

  7. #7
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 002
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Spécialiste en bases de données
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2006
    Messages : 8 002
    Points : 30 905
    Points
    30 905
    Billets dans le blog
    16
    Par défaut
    Bonsoir,


    Je n’ai pas fait de DB2 depuis plus de 10 ans, je peux donc dire des bêtises, mais pourquoi ne pas utiliser une méthode bourrin ?


    1) CREATE TABLE T3 LIKE T2 ;

    2) INSERT dans T3 des lignes de T2 qui ne sont pas orphelines ;

    3) DROP des index de T2 ;

    4) DELETE FROM T2 ;

    5) INSERT de T3 dans T2 ;

    6) Création des index de T2 et Reorg de T2 ;

    7) DROP TABLE T3.


    Maintenant, vous direz à celui qui vous impose des contraintes stupides, que ne pas mettre en œuvre l’intégrité référentielle, c’est passible des tribunaux relationnels.
    (a) Faites simple, mais pas plus simple ! (A. Einstein)
    (b) Certes, E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
    => La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

    __________________________________
    Bases de données relationnelles et normalisation : de la première à la sixième forme normale
    Modéliser les données avec MySQL Workbench
    Je ne réponds pas aux questions techniques par MP. Les forums sont là pour ça.

  8. #8
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 561
    Points
    38 561
    Billets dans le blog
    9
    Par défaut
    Bonjour,

    L'une des premières questions à se poser pour ce genre de problème est : "quel volume dois-je traiter"
    En effet la réponse sera totalement différente selon qu'il s'agit de quelques lignes ou de millions ou milliards de lignes
    Bien sur il faut penser à l'évolution de ce volume, si la base est nouvelle il faut tenir compte de son taux de croissance

    Dans le cas de volumes faibles (quelques lignes à quelques dizaines de lignes), le where exists évoqué plus haut est une solution simple, la restriction normative que tu évoques est curieuse, et peut peut être faire l'objet d'une dérogation.
    Par contre faire un where exists avec un select * est aberrant, pour un test d'existence, il est bien préférable de faire un select constante ou select d'une colonne de petite taille, inutile de transporter toute la table :
    DELETE from MATABLE
    WHERE NOT EXISTS
    (SELECT 1 FROM SUBQ
    WHERE...)

    Dans le cas de très fortes volumétries (genre épuration annuelle d'une base archive, traitement de convergence, de migration...) il est préférable de
    - décharger par unload les 2 tables
    - appareiller les fichiers pour éliminer les orphelins
    - trier les fichiers résultants sur la clef cluster
    - recharger en load replace avec les options "log no" et "statistics table all index all keycard" de facon à réorganiser la table, produire les stats et ne pas charger la log DB2 (contrairement au delete en masse)
    Le temps de traitement par rapport a du delete sera divisé de façon exponentielle

  9. #9
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 002
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Spécialiste en bases de données
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2006
    Messages : 8 002
    Points : 30 905
    Points
    30 905
    Billets dans le blog
    16
    Par défaut D'amour mourir me font, belle Marquise, vos beaux yeux
    Bonjour,



    J’espère que, depuis le temps, Samuel a réglé son problème...



    Citation Envoyé par escartefigue
    faire un where exists avec un select * est aberrant
    Ça peut paraître aberrant, mais ça n’a aucune incidence. En effet qu’on code :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    WHERE NOT EXISTS
        (SELECT 1 FROM SUBQ WHERE...) ;
    Ou bien :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    WHERE NOT EXISTS
        (SELECT * FROM SUBQ WHERE...) ;

    Depuis sa naissance, DB2 considère comme équivalents * ou 1 ou 2 ou ' D'amour mourir me font, belle Marquise, vos beaux yeux', dans le cas du prédicat EXISTS.

    Je vous renvoie à ce qu'a écrit C. J. Date dans A Guide to DB2 en 1984 :

    « Incidentally, the parenthesized subquery in an EXISTS expression does not necessarily have to involve the “SELECT *” form of SELECT; it may for example, be of the form “SELECT field-name FROM ...”. »


    La doc officielle de DB2 confirme. Extrait de DB2 10 for z/OS, SQL Reference, SC19-2983 :

    (a) Faites simple, mais pas plus simple ! (A. Einstein)
    (b) Certes, E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
    => La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

    __________________________________
    Bases de données relationnelles et normalisation : de la première à la sixième forme normale
    Modéliser les données avec MySQL Workbench
    Je ne réponds pas aux questions techniques par MP. Les forums sont là pour ça.

Discussions similaires

  1. Réponses: 6
    Dernier message: 15/06/2010, 03h18
  2. Réponses: 4
    Dernier message: 01/04/2010, 12h06
  3. [Modèle Relationnel] Faire une table par type ou une table des types ?
    Par jax54000 dans le forum Schéma
    Réponses: 12
    Dernier message: 18/11/2009, 11h43
  4. [MySQL] Créer une table actuelle à partir d'une table historique
    Par cleminute dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 20/10/2009, 14h35
  5. recupérer les info d'une table X pour alimenter une table Y
    Par lemerite dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 09/09/2008, 11h31

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