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

Requêtes et SQL. Discussion :

Regrouper deux lignes de sous formulaire en une seule [AC-2003]


Sujet :

Requêtes et SQL.

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut Regrouper deux lignes de sous formulaire en une seule
    Bonjour à tous,

    Je possède un sous-formulaire (basé sur la table "T_Commande") comprenant entre autre les champs "NoFacture", "NoArticle", et "Quantité". Je souhaiterai faire en sorte que si l'utilisateur choisit un NoArticle déjà existant pour ce NoFacture, la Quantité se cumule automatiquement, et qu'aucune nouvelle ligne ne soit créée.

    Pour cela j'ai tenté le code suivant dans Quantité_AfterUpdate :

    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
    Dim db As DAO.Database
    Dim rst As DAO.RecordSet
     
     
     
    Set db = CurrentDb()
    Set rst = db.OpenRecordSet("SELECT * FROM [T_Commande] WHERE [NoFacture] = ' " & Me.NoFacture & " ' AND NoArticle = ' " Me.LstArticles.Column(0) & " ' ")     '(le numéro d'article étant contenu dans une Combobox)
     
     
    'cumule les quantités s'il existe un premier enregistrement, ne change rien sinon
    rst.MoveFirst
    If Not rst.NoMatch Then
         rst.Edit
              rst ("Quantité") = rst ("Quantité") + Me.Quantité.Value
         rst.Update
    End If
     
     
    'efface le deuxième enregistrement s'il existe (c'est-à-dire s'il y en avait déjà un premier pour ce NoArticle et NoFacture)
    If Not rst.EOF Then
         rst.MoveNext
         rst.Delete
    End If
     
     
     
    rst.Close
    Set rst = Nothing
    Set db = Nothing

    Il cumule bien les quantités, mais rencontre un problème sur le delete : "aucun enregistrement en cours". Je pensais que le test sur EOF suffirait, mais visiblement non.

    J'ai essayé différentes petites choses, comme de placer le MoveNext avant le test, ou alors les FindFirst, NoMatch, et autres joyeux "Not IsNull (rst)", mais rien à faire je suis bloquée...


    Une petite aide, siouplait ?

  2. #2
    Rédacteur/Modérateur

    Avatar de Jean-Philippe André
    Homme Profil pro
    Architecte Power Platform, ex-Développeur VBA/C#/VB.Net
    Inscrit en
    Juillet 2007
    Messages
    14 642
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Canada

    Informations professionnelles :
    Activité : Architecte Power Platform, ex-Développeur VBA/C#/VB.Net
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2007
    Messages : 14 642
    Points : 34 354
    Points
    34 354
    Par défaut
    Bonjour,
    attention aux espaces en trop dans la requête SQL :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Set rst = db.OpenRecordSet("SELECT * FROM [T_Commande] WHERE [NoFacture] = '" & Me.NoFacture & "' AND NoArticle = '" Me.LstArticles.Column(0) & "' ")     '(le numéro d'article étant contenu dans une Combobox)

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    Oh, je ne savais pas que ça avait une importance
    Mais je les avais ajoutés pour être lisible sur le forum, ils n'y sont pas dans mon code (d'ailleurs j'ai aussi oublié un "&", dans mon exemple.. )

  4. #4
    Rédacteur/Modérateur

    Avatar de Jean-Philippe André
    Homme Profil pro
    Architecte Power Platform, ex-Développeur VBA/C#/VB.Net
    Inscrit en
    Juillet 2007
    Messages
    14 642
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Canada

    Informations professionnelles :
    Activité : Architecte Power Platform, ex-Développeur VBA/C#/VB.Net
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2007
    Messages : 14 642
    Points : 34 354
    Points
    34 354
    Par défaut
    OK,
    le plus judicieux serait de faire une requête SUM, et de mettre le résultat dans une nouvelle table, quitte à renommer celle-ci dans la foulée.

    Qu'en dis-tu ?

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    Que je ne sais pas bien comment faire ça ?

    Une requête avec un RunSQL ? (je connais surtout les requêtes SELECT, en fait...). Pourquoi une autre table ? Et comment faire, du coup, pour qu'elle remplace l'ancienne ? Et que vont devenir les autres enregistrements ? ...

  6. #6
    Rédacteur/Modérateur

    Avatar de Jean-Philippe André
    Homme Profil pro
    Architecte Power Platform, ex-Développeur VBA/C#/VB.Net
    Inscrit en
    Juillet 2007
    Messages
    14 642
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Canada

    Informations professionnelles :
    Activité : Architecte Power Platform, ex-Développeur VBA/C#/VB.Net
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2007
    Messages : 14 642
    Points : 34 354
    Points
    34 354
    Par défaut
    Oui
    ou bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CurrenDb.Execute strSQL
    Avec un enchaînement du type :
    - requête SELECT * INTO NouvelleTable FROM AncienneTable
    - requete DROP AncienneTable
    - code VBA REnameTable


    pistes issues de la
    http://access.developpez.com/faq/?page=SQL#qryActions

    sinon le cours très complet sur DAO :
    http://warin.developpez.com/access/dao/

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    Merci beaucoup

    Je regarde ça ce soir et demain matin, et je te tiens au courant si j'ai des difficultés

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    Bon. J'ai un petit peu décortiqué tout ça, et j'ai réussi la première étape : créer une copie de ma table T_Commande, l'enregistrer dans une nouvelle table T_Temporaire, puis supprimer T_Commande et renommer T_Temporaire en T_Commande. Jusqu'ici, ça marche. (du moins je l'ai fait sur un test, je n'ai pas réellement supprimé ma table T_Commande)

    Mais j'ai encore quelques soucis. Le plus difficile à résoudre (je pense) est que mes tables sont attachées, et j'aimerai qu'elles le restent =/ . C'est à dire que mon application est dans un certain fichier, et que mes tables (Appli_pincip.mdb) sont dans un autre. Or avec cette méthode, je crée une table dans le même fichier que l'appli.

    Bien plus embêtant, la nouvelle table créée n'a surtout aucune relation avec les autres. Si je supprime mon ancienne table T_Commande, je fiche donc en l'air toute mon application =/

    Enfin, j'ai bien réussi à faire une copie exacte, mais je ne comprends pas bien comment utiliser la requête SUM pour faire ce que je voulais au départ, à savoir cumuler les quantités. Je pourrai, je crois, copier la table champ par champ, et ainsi faire la somme pour le champ Quantité, mais dans ce cas il me marquerait tout de même deux lignes (les deux qui ont le même NoArticle et NoFacture)..


    Bref je suis un peu perdue



    Edit :

    Après quelques recherches je me suis aperçue qu'il existait des fonctions pour créer les relations à l'aide du VBA. Je regarde ça.

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    Bon, alors j'ai pas mal avancé, j'ai trouvé comment créer une relation (enfin en théorie, même si avec mes bugs je n'ai pas encore pu vérifier que ça fonctionnait), et ce, même si les tables sont attachées.

    Le problème, c'est qu'Access refuse de me l'ajouter, cette relation, puisque "Le moteur de base de données n'a pas pu vérouiller la table T_Facture car elle est déjà utilisée par une autre personne ou un autre processus.". Ce qui est vrai, puisque ce code se trouve, je le rappelle, dans Quantité_AfterUpdate, Quantité étant un champ du sous formulaire SF_Commande, fils du formulaire F_Facture, basé sur la table T_Facture (compliqué à expliquer, tout ça... ). Mais comment faire, alors ? Je suis bien obligée d'ouvrir la table T_Facture, pour modifier mon sous-formulaire...


    Si ça peut aider, voici mon 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
       Dim db As DAO.Database
       Dim relCF As DAO.Relation
       Dim fldCF As DAO.Field
     
     
     
       Set db = OpenDatabase("chemin de mon fichier mdb contenant mes tables attachées")
       Set relCF = db.CreateRelation("CF", "T_Facture", "T_Commande2", dbRelationUpdateCascade)   'Je ne sais pas ce que représente mon attribut "CF", le 'name' apparemment, mais sans ça ne marchait pas, alors j'ai mis cette désignation au hasard  :]
       Set fldCF = relCF.CreateField("NoFac")   'NoFac étant l'ID de ma table T_Facture
       fldCF.ForeignName = "NoFacture"   'NoFacture étant un champ de la table T_Commande
       relCF.Fields.Append fldCF
       db.Relations.Append relCF
       db.Relations.Refresh
     
     
       (...)

    Il m'indique l'erreur à la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    db.Relations.Append relCF


    précision : j'ai essayé d'intégrer à mon code la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.Close acTable, "T_Facture"
    , ou encore
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Dim tbl As DAO.RecordSet
    Set tbl = db.OpenRecordSet("T_Facture", dbOpenTable)
    tbl.Close
    , mais rien n'y fait.



    (Sinon, je n'ai toujours pas résolu non plus mon problème de somme...)




    (Autrement, si quelqu'un a une solution plus simple à mon problème initial, je suis toujours preneuse, hein...)


    .

  10. #10
    Expert éminent
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Points : 7 759
    Points
    7 759
    Par défaut Une aure piste
    Bonsoir,

    Moi, j'essaierai d'agir dans l'événement "Avant MAJ" du sous-formulaire.
    C'est à dire, avant que le nouvel enregistrement en cours de saisie, ne soit enregistré dans la table.

    J'ai essayé d'intégrer tes noms de champs et contrôles, dans mon code.
    Code de l'événement "Avant MAJ" du formulaire utilisé en sous-formulaire :
    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
    Private Sub Form_BeforeUpdate(Cancel As Integer)
    Dim rs As DAO.Recordset
    Dim strRefproduit As String, lgQte As Long
     
    ' Ne rien faire si l'enregistrement n'est pas
    ' un nouvel enregistrement
    If Not Me.NewRecord Then Exit Sub
     
    ' référence le clone du recordset du formulaire
    Set rs = Me.RecordsetClone
    If Not (rs.BOF And rs.EOF) Then
       ' récupérer référence produit
       strRefproduit = Me.LstArticles.Column(0)
       ' récupérer Qté
       lgQte = Me.Quantité
     
       ' Est-ce que la référence produit existe déjà
       ' dans le jeu de données du formulaire
       rs.FindFirst "[NoArticle] = '" & strRefproduit & "'"
       If Not rs.NoMatch Then
          ' Si oui, annuler la saisie
          Cancel = True
          Me.Undo
     
          ' FindFirst a positionné l'enregistrement actif
          ' sur référence produit
          ' On augmente la quantité
          rs.Edit
          rs("Quantité") = rs("Quantité") + lgQte
          rs.Update
       End If
    End If
    End Sub
    RecordsetClone est un duplicata du jeu de données du formulaire.
    Dans le cadre d'un sous-formulaire, ce jeu de données est restreint par la relation parent/enfant qui existe entre le formulaire et le sous-formulaire.
    Donc pas besoin de limiter à NoFacture dans ce contexte. C'est forcement le cas.

    L'avantage de cette méthode (j'espère ne pas dire de bêtise), c'est qu'en passant par RecordsetClone,
    le Formulaire "voit" plus rapidement que des données on été modifiées.
    Ce n'est pas le cas si on modifie des données, par une requête ou un recordset créé avec OpenRecordset.
    Il peut y avoir un temps de latence, surtout si les données sont dans une dorsale sur un serveur.

    Juste au cas où :
    Si le champ NoArticle est numérique, remplacer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
       rs.FindFirst "[NoArticle] = '" & strRefproduit & "'"
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
       rs.FindFirst "[NoArticle] = " & strRefproduit
    A+

  11. #11
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 84
    Points : 35
    Points
    35
    Par défaut
    Merci beaucoup pour cette nouvelle réponse
    Ca fonctionne presque \o/


    En fait, ça fonctionne même totalement sans le test sur EOF et BOF
    Pourquoi l'avoir fait, je ne comprends pas ?

  12. #12
    Expert éminent
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Points : 7 759
    Points
    7 759
    Par défaut
    Bonjour,

    Je teste BOF et EOF pour savoir si le recordset est vide (lorsqu'on saisie la toute première ligne).
    Dans ce cas, inutile de chercher si NoArticle a déjà été saisi.
    Malheureusement, je me rend compte que ça ne fonctionne pas avec Me.RecordsetClone.

    Tu peux remplacer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    If Not (rs.BOF And rs.EOF) Then
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    If rs.RecordCount > 0 Then
    ou bien carrément enlever le test.

    A+

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

Discussions similaires

  1. [AC-2010] Griser une ligne de sous formulaire.
    Par fab.85 dans le forum IHM
    Réponses: 11
    Dernier message: 13/08/2013, 20h58
  2. Requête regroupant deux lignes sur une colonne
    Par majo59 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 02/08/2012, 10h05
  3. [AC-2003] Export d'un sous-formulaire qu'une seule fois
    Par valy_442 dans le forum IHM
    Réponses: 5
    Dernier message: 08/12/2010, 12h35
  4. Comment ajouter une ligne à un sous-formulaire?
    Par Leila59 dans le forum IHM
    Réponses: 14
    Dernier message: 17/05/2008, 14h08
  5. [sous formulaire] acceder à une valeur
    Par debdev dans le forum Access
    Réponses: 2
    Dernier message: 28/10/2005, 09h59

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