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

Merise Discussion :

Supprimer un devis en totalité ou simplement une ligne


Sujet :

Merise

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    566
    Détails du profil
    Informations personnelles :
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2009
    Messages : 566
    Points : 1 045
    Points
    1 045
    Par défaut Supprimer un devis en totalité ou simplement une ligne
    Bonjour,

    J'ai quelques soucis pour traiter certaines opérations du MPD ci-dessous. Je travaille avec Firebird et Delphi 7 sous Windows



    Lorsque je veux supprimer une ligne du devis, il me faut d'abord supprimer la ligne présente dans la table de jointure "Lig_devis" puis dans la table "LIGNE", sauf si je mets mes clés étrangères de "Lig_devis" en cascade. Je gère cela correctement avec une procédure stockée ou pas.

    Par contre, les choses se compliquent dès que je veux supprimer le devis en totalité, car il faut supprimer les lignes présentes dans "Lig_devis", puis dans "LIGNE" et enfin la ligne du devis dans "DEVIS".

    Pour parvenir au résultat, si les clés étrangères de "Lig_devis" sont positionnées "NO ACTION", je dois créer une table temporaire, transférer les lignes de "Lig_devis" concernées, puis supprimer les éléments des tables "LIGNE" et "DEVIS". Ensuite, supprimer la table temporaire.

    Bonjour la manœuvre

    Je voudrais savoir s'il n'existe pas une méthode plus simple à l'aide d'un trigger ou d'une procédure stockée. Merci, de me donner votre avis.

    Le positionnement des clés étrangères dans "Lig_devis" en cascade ne supprime pas ma difficulté car les lignes de la table "LIGNE" ne sont supprimées. La table "Lig_devis" est l'enfant de "DEVIS" et "LIGNE" d'où impossibilité en supprimant la ligne dans "Lig_devis" d'enlever la ligne liée dans "LIGNE". Si trigger avant Delete dans "Lig_devis", je me heurte à la récursivité.

    Je tourne en rond et fais bouillir les quelques neurones qui me restent.

    Je ne suis peut être pas très explicite, ceci explique peut-être cela, mais vous pouvez me demander des renseignements complémentaires si nécessaire

    D'avance merci

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 793
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 793
    Points : 34 024
    Points
    34 024
    Billets dans le blog
    14
    Par défaut
    Envisageons plusieurs cas...

    1) Phase devis (pas encore de commande, encore moins de facture)
    a) Je veux modifier un devis en supprimant une de ses lignes.
    Avec ON DELETE CASCADE sur la FK2 de la table de jointure Lig_Devis, la ligne de devis sera automatiquement supprimée dans la table de jointure si je supprime la ligne de la table LIGNE.
    Le devis existe toujours, c'est normal !

    b) Je veux supprimer le devis.
    Avec ON DELETE CASCADE sur FK1 de la table de jointure Lig_Devis, toutes les lignes relatives au devis supprimé seront supprimées de la table de jointure si je supprime le devis dans la table DEVIS.
    Mais les lignes du devis existent toujours dan la table LIGNE, pas normal !

    Il faut donc en premier supprimer les lignes du devis dans la table LIGNE puis le devis dans la table DEVIS.

    *******************************
    Ton MLD laisse supposer qu'une ligne de commande ou de facture pourrait ne pas figurer dans le devis. Est-ce le cas ?
    *******************************

    2) Phase commande : Le devis a fait l'objet d'une commande, pas encore de facture.
    => Normalement, on ne touche plus au devis !
    a) Je veux supprimer une ligne de commande.
    i - La ligne est spécifique à la commande.
    On supprime la ligne dans la table LIGNE et avec ON DELETE CASCADE sur FK2 de la table de jointure Lig_cde, la ligne sera supprimée dans la table LIGNE.

    ii - La ligne figure dans le devis.
    On ne doit supprimer la ligne de la commande que dans la table de jointure Lig-cde. Si il y a ON DELETE CASCADE, elle serait aussi supprimée dans la table LIGNE.
    => Donc pas de ON DELETE CASCADE.

    b) On supprime la commande (bizarre mais bon... )
    Avec ON DELETE CASCADE sur FK1 de la table de jointure Lig_cde, les lignes de la commande seront supprimées de la table de jointure mais elles figureront toujours dans la table LIGNE. Normal si ce sont des lignes du devis, plus gênant si ce sont des lignes spécifiques à la commande car elles deviennent orphelines.

    Même problème pour la phase facturation. Il faudrait donc réserver le ON DELETE CASCADE à la phase Devis, et en interdisant les manipulations du devis une fois qu'il est passé en commande. Le schéma de données actuel ne l'interdit pas, il faut donc blinder le programme et protéger les accès à la BDD.

    ************************************************
    Peut-être que ton modèle de données, quoique joliment présenté, n'est pas idéal...

    Le fait d'avoir reporté l'identifiant du client sur toutes les tables fait qu'une ligne pourrait être liée à un client et à un devis d'un autre client !

    Je crois reconnaître ton schéma, lequel avait été abondamment discuté.

    La clé de sa pertinence repose sur la réponse à la question que j'ai posée plus haut :
    Une ligne de commande ou de facture peut-elle ne pas figurer dans un devis ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    566
    Détails du profil
    Informations personnelles :
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2009
    Messages : 566
    Points : 1 045
    Points
    1 045
    Par défaut
    Bonjour,

    merci @CinePhil pour ta réponse rapide.
    La clé de sa pertinence repose sur la réponse à la question que j'ai posée plus haut :
    Une ligne de commande ou de facture peut-elle ne pas figurer dans un devis ?
    Effectivement une ligne de commande ou de facture peut ne pas figurer dans un devis. Il est toujours possible que la commande ou/et la facture différent du devis.

    En principe, en dehors de la correction d'erreurs, la commande ou/et la facture non pas à être supprimés.

    La commande est enregistrée si elle est passé, elle peut être annulée mais, en principe pas supprimée.

    Pour la facture, les corrections se font par un avoir et une nouvelle facture.

    Ce qui m'intéresse c'est plus une approche générale lorsque je suis placé dans une telle situation et surtout comment supprimer un devis dans globalité (Devis + Lignes du devis).

    Effectivement, il est possible que mon MCD soit imparfait, s'il faut je le modifierai. En tout état de cause, je vais revoir le report de l'identifiant du client.

    Le fait d'avoir reporté l'identifiant du client sur toutes les tables fait qu'une ligne pourrait être liée à un client et à un devis d'un autre client !
    Après les tests, la réponse est qu'il n'est pas possible d'inclure la ligne d'un client au devis d'un autre client. Contrainte d'intégrité dans la table "Lig_devis" sur l'identifiant du client. Maintenant, il peut exister une situation à laquelle je n'ai pas pensé.

    Mon MCD puis MPD ont été validés avec @fsmrel.

    Merci pour ton éventuelle réponse.

  4. #4
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    7 966
    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 : 7 966
    Points : 30 778
    Points
    30 778
    Billets dans le blog
    16
    Par défaut Pas de panique !
    Pas de panique, je selle mon cheval et j'arrive au galop !
    (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.

  5. #5
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    7 966
    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 : 7 966
    Points : 30 778
    Points
    30 778
    Billets dans le blog
    16
    Par défaut Delete : trigger + variable de type Table
    Bonsoir seabs,


    Je ne connais ni Firebird ni Delphi 7, aussi je vous indique une solution avec SQL Server, en espérant qu’elle soit adaptable.

    Avec SQL Server donc, on peut utiliser un trigger dans lequel on déclare une variable de type table, qui servira à mémoriser les valeurs des clés des lignes à supprimer dans la table LIGNE.

    Pour me simplifier la vie à l’occasion des tests de ce trigger, j’ai remplacé systématiquement le type INT par le type CHAR(5).

    Supposons que l’on soumette l’instruction suivante, pour supprimer le devis dev02 du client cli01 :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    DELETE FROM  DEVIS 
           WHERE ClientId = 'cli01'
             AND DevisId = 'dev02' 
    ;
    Grâce au trigger, on intercepte les opérations de DELETE portant sur la table DEVIS. Avec l’option INSTEAD OF, on prend le contrôle avant que les suppressions ne soient effectuées.

    Description du trigger :

    Lignes 02 à 05 : déclaration de la variable @Temp, dont le contenu ne persistera que le temps de l’opération de Delete.

    Lignes 07 à 15 : on mémorise dans @Temp les valeurs des clés des lignes à supprimer dans la table LIGNE. A noter que le SGBD fournit dans une table particulière (qu’il nomme Deleted) les lignes à supprimer dans la table DEVIS.

    Lignes 17 à 23 : on supprime de qui doit l’être dans la table Lig_Devis.

    Lignes 25 à 31 : on supprime ce qui doit l’être dans la table LIGNE.

    Lignes 33 à 39 : on supprime ce qui doit l’être dans la table DEVIS.


    Code SQL : 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
    01  CREATE TRIGGER DEVIS_DELETE ON DEVIS INSTEAD OF DELETE AS
    02  DECLARE @Temp TABLE (
    03     ClientId CHAR(5)  NOT NULL,
    04     LigneId  CHAR(5)  NOT NULL,
    05     DevisId  CHAR(5)  NOT NULL)
    06  ;
    07  INSERT INTO @Temp
    08     SELECT x.ClientId, z.LigneId, x.DevisId 
    09     FROM        Deleted AS x
    10            JOIN Lig_Devis AS y
    11                   ON  x.ClientId = y.CLientId
    12                   AND x.DevisId = y.DevisId
    13            JOIN LIGNE AS z
    14                   ON  y.ClientId = z.CLientId
    15                   AND y.LigneId = z.LigneId
    16  ;
    17  DELETE FROM Lig_Devis 
    18         WHERE EXISTS 
    19              (SELECT ''
    20               FROM   @Temp AS y
    21               WHERE  Lig_Devis.ClientId = y.ClientId
    22                 AND  Lig_Devis.DevisId = y.DevisId 
    23              )
    24  ;
    25  DELETE FROM LIGNE
    26         WHERE EXISTS 
    27              (SELECT ''
    28               FROM   @Temp AS y
    29               WHERE  LIGNE.ClientId = y.ClientId
    30                 AND  LIGNE.LigneId = y.LigneId
    31              )
    32  ;
    33  DELETE FROM DEVIS
    34         WHERE EXISTS 
    35              (SELECT ''
    36               FROM   DELETED AS y 
    37               WHERE  DEVIS.clientid = y.clientid 
    38                 AND  DEVIS.devisId  = y.devisId
    39              )
    40  ;
    41  GO

    Maintenant, l’opération de suppression portant sur la table DEVIS réussira ou non selon le contenu de la table Commander et dépendra du choix NO ACTION ou CASCADE quant à contrainte référentielle liant ces deux tables.
    (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.

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    566
    Détails du profil
    Informations personnelles :
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2009
    Messages : 566
    Points : 1 045
    Points
    1 045
    Par défaut
    Bonjour,

    @fsmrel - Je vous remercie de votre réponse, laquelle confirme ma réflexion.

    Malheureusement, Firebird ne permet pas la création d'une table temporaire.Je pense que cela existera avec la version 2.5 qui doit sortir prochainement. En attendant, il faut faire avec la version 2.1.

    J'ai trouvé une solution avec une procédure stockée, elle est en cours de finalisation. Dès qu'elle sera définitive, je vous présenterai le code. Avant, je veux m'assurer qu'il n'existe pas un défaut caché.

    Sinon, je passerai par une table dédiée à cette opération avec une procédure stockée appelée depuis un trigger.

    Votre devise est au goût du jour
    Faire simple, mais pas plus simple
    Encore merci.

  7. #7
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    7 966
    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 : 7 966
    Points : 30 778
    Points
    30 778
    Billets dans le blog
    16
    Par défaut
    Bonjour seabs,


    Citation Envoyé par seabs
    Malheureusement, Firebird ne permet pas la création d'une table temporaire.
    On peut faire sans. L’idée est d’ajouter un attribut, appelons-le DrapeauDelete dans l’en-tête de la table LIGNE :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     Create Table LIGNE (
       ClientId             Char(5)              Not null,
       LigneId              Char(5)              Not null,
       LigneDesignation     Char(30)             Not null,
       LigneQuantite        Int                  Not null,
       LignePrix            Int                  Not null,
       DrapeauDelete        Char(1)              not null, 
       ...
      ) ;
    Et de le marquer comme « Ligne à supprimer » lors de la suppression d’un devis.

    Considérez le trigger suivant (toujours SQL Server) :

    Code SQL : 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
    01  CREATE TRIGGER DEVIS_DELETE ON DEVIS INSTEAD OF DELETE AS
    02  
    03  UPDATE LIGNE
    04         SET  DrapeauDelete = 'Y'
    05         WHERE ClientId IN 
    06              (SELECT  x.CLientId
    07               FROM        Deleted AS x
    08                      JOIN Lig_Devis AS y
    09                           ON  x.ClientId = y.CLientId   
    10                           AND x.DevisId = y.DevisId
    11                      JOIN LIGNE AS z
    12                           ON  y.ClientId = z.CLientId
    13                           AND y.LigneId = z.LigneId)
    14         AND LigneId IN 
    15              (SELECT  x.LigneId
    16               FROM        Lig_Devis AS x
    17                      JOIN Deleted AS y
    18                           ON  x.ClientId = y.CLientId   
    19                           AND x.DevisId = y.DevisId
    20                      JOIN LIGNE AS z
    21                           ON  x.ClientId = z.CLientId
    22                           AND x.LigneId = z.LigneId)
    23  ;
    24  DELETE FROM DEVIS
    25         WHERE EXISTS 
    26              (SELECT ''
    27                FROM   Deleted AS y 
    28                WHERE  DEVIS.clientid = y.clientid 
    29                AND    DEVIS.devisId  = y.devisId
    30               )
    31  ;
    32  DELETE FROM LIGNE
    33       WHERE DrapeauDelete = 'Y' 
    34 ;
    35  GO
    Lignes 03 à 23 : on marque les lignes à supprimer dans la table LIGNE.

    Lignes 24 à 31 : on supprime dans la table DEVIS et dans la table Lig_Devis (j’ai supposé ici que la contrainte référentielle entre les tables DEVIS et Lig_Devis était porteuse de la clause CASCADE).

    Lignes 32 à 34 : suppression effective dans la table LIGNE.

    On tend vers le bricolage, mais on fait en fonction des possibilités du SGBD...
    (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
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    566
    Détails du profil
    Informations personnelles :
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2009
    Messages : 566
    Points : 1 045
    Points
    1 045
    Par défaut
    Bonjour,

    @fsmrel - Avec vos différentes explications, j'ai une solution qui fonctionne.

    Je considère mon problème comme résolu dans l'immédiat. Je verrai bien si des nouvelles difficultés apparaissent lors de la mise en place du module "Commande" et module "Facture".

    Merci à tous pour vos réponses, lesquelles m'ont aidé à progresser et réliser une base de données plus solide que celle qui est actuellement exploitée.

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

Discussions similaires

  1. Figer simplement une ligne de tableau
    Par Biotik dans le forum Balisage (X)HTML et validation W3C
    Réponses: 1
    Dernier message: 02/07/2010, 09h34
  2. Supprimer plusieurs fichiers du même nom en une ligne de commande
    Par Orbiplanax dans le forum Administration système
    Réponses: 4
    Dernier message: 12/09/2007, 19h25
  3. incrementer simplement une valeur ?
    Par jerz dans le forum Requêtes
    Réponses: 2
    Dernier message: 08/03/2004, 15h28
  4. supprimer une ligne avec cle etrangere
    Par BaBas dans le forum Langage SQL
    Réponses: 4
    Dernier message: 15/07/2003, 12h24
  5. Supprimer une ligne dans un fichier
    Par sbeu dans le forum Langage
    Réponses: 3
    Dernier message: 13/05/2003, 11h30

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