Code VBA pour report de données d'une année vers une autre

Résolu
@tech -  
tech40 Messages postés 1 Statut Membre -
Bonjour à tous,

J'ai un petit soucis avec ma base de donnée Access (Access 2003), et je vais avoir besoin d'aide...

Tous les ans je dois reporter des interventions préventive d'une année sur une autre, selon la périodicité.

J'ai une table qui s'appelle "planning préventif" avec les champs suivants

N° BTP
Semaine interv (avec cadencement de plusieurs semaine pour certains BTP)
Année interv
soldé interv
date de fin du BTP

J'ai une requête "Report preventif" (avec les mêmes champs que la table "planning préventif") afin de pouvoir reporter tous les BTP sur les années suivantes selon leurs périodicités.

Le code VBA ci-dessous ne fonctionne pas très bien, car il ne reporte pas tous cadencements... certains passe dans les mailles du filet et je ne sais pas pourquoi !

Au lieu de reporter 2314 cadencement au total, il n'en reporte que 1706, ce qui fait une différence de 608.

Option Compare Database
Option Explicit

Private Sub CmdReportBTP_Click()
Dim db As Database
Dim rsScan As DAO.Recordset
Dim rsPlan As DAO.Recordset
Dim machine As String
Dim annee As Integer
Dim semaines() As Integer
Dim numeros() As Integer
Dim i As Integer
Dim anneeReport As Integer

anneeReport = InputBox("Saisir l'année de report :")

Set db = CurrentDb
Set rsScan = db.OpenRecordset("report_preventif", dbOpenSnapshot)
Set rsPlan = db.OpenRecordset("Planning preventif", dbOpenDynaset)
i = 1
If rsScan.BOF = True And rsScan.EOF = True Then
MsgBox "Aucun enregistrement", vbCritical
Exit Sub
End If

machine = rsScan.Fields("code machine").Value
annee = rsScan.Fields("année interv").Value

Do While rsScan.EOF = False

If rsScan.Fields("code machine").Value = machine And rsScan.Fields("année interv").Value = annee Then
If annee <= anneeReport Then
rsPlan.AddNew
rsPlan.Fields("N° BTP").Value = rsScan.Fields("N° BTP").Value
rsPlan.Fields("Semaine interv").Value = rsScan.Fields("Semaine interv").Value
rsPlan.Fields("année interv").Value = annee + rsScan.Fields("périodicité").Value
rsPlan.Fields("soldée interv").Value = False
rsPlan.Update
End If
annee = rsScan.Fields("année interv").Value
End If

rsScan.MoveNext
'Ajouter le test si on est pas en EOF
If Not rsScan.EOF Then
If rsScan.Fields("code machine").Value <> machine Then annee = rsScan.Fields("année interv").Value
machine = rsScan.Fields("code machine").Value

End If
Loop
rsScan.Close
rsPlan.Close
Set rsScan = Nothing
Set rsPlan = Nothing

MsgBox "Report des BTP effectué avec succès"

End Sub

Voila! Est-ce que quelqu'un pourrais éventuellement m'aider à résoudre ce petit problème, car moi avec mon petit niveaux je n'y arriverai pas...

Merci d'avance à tous et bonne année !

11 réponses

Résumé de la discussion

Le problème porte sur le report annuel des interventions préventives dans une base Access 2003 selon une périodicité; le code VBA ne couvre pas tous les cadencements. Des suggestions initiales recommandent de déboguer pas à pas et de vérifier les valeurs des variables pour comprendre pourquoi certaines lignes échouent dans la boucle. La discussion propose ensuite une solution plus simple et fiable: une requête d’insertion qui duplique les enregistrements pour l’année suivante, tout en évitant les doublons. Cependant, l’emploi d’un index unique multi-champs peut bloquer les cadences multiples et nécessite une gestion des insertions via vérifications préalables ou contraintes adaptées pour éviter les enregistrements répétés.

Généré automatiquement par IA
sur la base des meilleures réponses
  1. f894009 Messages postés 17417 Date d'inscription   Statut Membre Dernière intervention   1 717
     
    Bonjour,

    Mettre un point d'arret sue cette ligne:

    If rsScan.Fields("code machine").Value = machine And rsScan.Fields("année interv").Value = annee Then

    Verifiez le contenu des variables precedent cette ligne.
    Pour verifier, passez le curseur souris sur les variables
    Si ok, appuyez sur la touche F8 pour faire derouler le code ligne par ligne en verifiant a chaque fois le contenu de vos variables
    1
  2. @tech
     
    Bonjour f894009,

    Merci pour ton commentaire et désolé, pour ma réponse tardive... autres soucis à régler...

    Aussi, j'ai oublié de préciser que j'ai une table "preventif" avec les champs suivants :

    Code machine
    Année interv
    Semaine interv
    N° BTP
    périodicité

    J'ai déjà réalisé plusieurs fois des arrêts sur cette lignes, et les variables "machine" et "annee" recopie bien les bonnes valeurs.

    Mais certaines lignes sont ignorées ! et je n'arrive pas à trouver la cause !

    Est-ce un couac dans le code ou est-ce la requête "Report preventif" ?

    Merci pour ton aide :)
    0
  3. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   Ambassadeur 1 588
     
    bonjour, nous as-tu dit combien de lignes étaient affichées quand tu ouvrais la requête "Report preventif" ?
    0
    1. @tech
       
      Bonjour yg_be,

      12627 lignes
      0
    2. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       
      voilà ce que je retiens de ton code:
      anneeReport = InputBox("Saisir l'année de report :")
      Set rsScan = db.OpenRecordset("report_preventif", dbOpenSnapshot)
      Set rsPlan = db.OpenRecordset("Planning preventif", dbOpenDynaset)
      machine = rsScan.Fields("code machine").Value
      annee = rsScan.Fields("année interv").Value
      Do While rsScan.EOF = False
      	If rsScan.Fields("code machine").Value = machine And rsScan.Fields("année interv").Value = annee Then
      		If annee <= anneeReport Then
      			rsPlan.AddNew
      		End If
      		annee = rsScan.Fields("année interv").Value
      	End If
      	rsScan.MoveNext
      	If Not rsScan.EOF Then
      		If rsScan.Fields("code machine").Value <> machine Then annee = rsScan.Fields("année interv").Value
      		machine = rsScan.Fields("code machine").Value
      	End If
      Loop


      je crois deviner que la requete report_preventif classe les données par machine puis par année.
      si je comprends ton code, il ne traite pas, pour chaque machine, le premier enregistrement de chaque année, sauf pour la première année.
      ton code me semble particulièrement maladroit.
      entr'autres, pourquoi tester "rsScan.Fields("code machine").Value = machine", je pense qu'il est toujours vrai.
      0
  4. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   Ambassadeur 1 588
     
    peux-tu utiliser les balises de code quand tu partages to code:https://codes-sources.commentcamarche.net/faq/11288-les-balises-de-code
    0
    1. @tech
       
      Option Compare Database
      Option Explicit
      
      Private Sub CmdReportBTP_Click()
      Dim db As Database
      Dim rsScan As DAO.Recordset
      Dim rsPlan As DAO.Recordset
      Dim machine As String
      Dim annee As Integer
      Dim semaines() As Integer
      Dim numeros() As Integer
      Dim i As Integer
      Dim anneeReport As Integer
      
      anneeReport = InputBox("Saisir l'année de report :")
      
      Set db = CurrentDb
      Set rsScan = db.OpenRecordset("report_preventif", dbOpenSnapshot)
      Set rsPlan = db.OpenRecordset("Planning preventif", dbOpenDynaset)
      i = 1
      If rsScan.BOF = True And rsScan.EOF = True Then
          MsgBox "Aucun enregistrement", vbCritical
          Exit Sub
      End If
      
      machine = rsScan.Fields("code machine").Value
      annee = rsScan.Fields("année interv").Value
      
      Do While rsScan.EOF = False
          
          If rsScan.Fields("code machine").Value = machine And rsScan.Fields("année interv").Value = annee Then
              If annee <= anneeReport Then
                  rsPlan.AddNew
                  rsPlan.Fields("N° BTP").Value = rsScan.Fields("N° BTP").Value
                  rsPlan.Fields("Semaine interv").Value = rsScan.Fields("Semaine interv").Value
                  rsPlan.Fields("année interv").Value = annee + rsScan.Fields("périodicité").Value
                  rsPlan.Fields("soldée interv").Value = False
                  rsPlan.Update
              End If
              annee = rsScan.Fields("année interv").Value
          End If
          
          rsScan.MoveNext
          'Ajouter le test si on est pas en EOF
          If Not rsScan.EOF Then
              If rsScan.Fields("code machine").Value <> machine Then annee = rsScan.Fields("année interv").Value
              machine = rsScan.Fields("code machine").Value
              
          End If
      Loop
      rsScan.Close
      rsPlan.Close
      Set rsScan = Nothing
      Set rsPlan = Nothing
      
      MsgBox "Report des BTP effectué avec succès"
      
      End Sub
      0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. @tech
     
    Bonjour à tous,

    yg_be à raison, le code se perd...

    J'aimerais mieux expliquer mon besoin...

    Ci-dessous le contenu de chaque table et de la requête report_preventif :

    Champs de la table "préventif"
    Date Création, Date en cours, Semaine Calculée, Travaux à effectuer, Code machine, Temps théorique, Activé, unitée, Sous organe, Libellé, N° BTP, périodicité, Type d'intervention, Organisation

    Champs de la table "Planning preventif"
    N° BTP, Semaine interv, Année interv, soldée interv, date de fin du BTP

    Champs de la requête "report_preventif"
    N° BTP, Semaine interv, Année interv (table planning preventif)
    Code machine, périodicité, Activé (table préventif)

    Requête "report_preventif"
    SELECT [Planning preventif].[N° BTP], préventif.[Code machine], [Planning preventif].[Semaine interv], [Planning preventif].[Année interv], préventif.périodicité
    FROM préventif INNER JOIN [Planning preventif] ON préventif.[N° BTP] = [Planning preventif].[N° BTP]
    WHERE (((préventif.Activé)=Yes))
    ORDER BY [Planning preventif].[N° BTP], [Planning preventif].[Semaine interv] DESC , [Planning preventif].[Année interv] DESC;

    Je besoin d'aller chercher les infos de la table "Planning preventif" et "préventif" pour la périodicité (1, 2, 3, 4, 5 ans, ...)
    et lors de l'insertion dans la table "Planning preventif" prendre en compte la périodicité et l'additionner à l'année 2020.

    Ex:

    Planning Preventif initiale

    N° BTP, Semaine interv, Année interv, soldée interv, date de fin du BTP
    7, 31, 2020, -1, 28/07/2020 (périodicité 1ans)
    8, 31, 2020, -1, 29/07/2020 (périodicité 2ans)

    Planning Preventif après report

    N° BTP, Semaine interv, Année interv, soldée interv, date de fin du BTP
    7, 31, 2020, -1, 28/07/2020 (périodicité 1ans)
    7, 31, 2020, -1, 28/07/2021
    8, 31, 2020, -1, 29/07/2020 (périodicité 2ans)
    8, 31, 2020, -1, 29/07/2022

    Voila! j'espère m'être fait comprendre, ce n'est pas évident à expliquer... en théorie c'est simple! mais pas à mettre en oeuvre...

    Merci pour votre aide :)
    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       
      ton exemple est incomplet: tu ne nous montres pas les données issues de la requête "report_preventif"
      0
    2. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       
      N° BTP est-il la clé primaire dans la table "préventif"?
      0
  7. @tech
     
    Ops !

    Exemple de résultat de la requête "report_preventif"
    Code machine, Année interv, Semaine interv, N° BTP, périodicité
    ACCOMP07, 2020, 4, 798, 1
    ACCOMP07, 2020, 15, 1242, 1

    Merci :)
    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       
      dans ton exemple "Planning Preventif après report", je suis étonné que le champ "Année interv" soit partout 2020.
      le champ "date de fin du BTP" est-il un champ calculé?

      il ne peux jamais y avoir deux codes machine pour un n°BTP?

      si je vois bien, ton exemple est incomplet, ce ne sont pas partout les mêmes n°BTP.
      un exemple, cela ne se fait pas en sortant quelques lignes au hasard dans chaque table.

      si tu ne peux ni expliquer la théorie, ni montrer des exemples utiles, je ne vois pas trop comment t'aider.
      0
  8. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   Ambassadeur 1 588
     
    essayons autrement.
    la requête suivante te donne-t'elle exactement tous les enregistrements à ajouter dans la table "planning préventif": le bon nombre d'enregistrements avec les bonnes informations?

    SELECT [Planning preventif].[N° BTP], [Planning preventif].[Semaine interv], 
    [Planning preventif].[Année interv] + préventif.périodicité
    FROM préventif INNER JOIN [Planning preventif] 
    ON préventif.[N° BTP] = [Planning preventif].[N° BTP]
    WHERE (((préventif.Activé)=Yes)) and [Planning preventif].[Année interv] = 2020
    ORDER BY [Planning preventif].[N° BTP], [Planning preventif].[Semaine interv] ;
    0
    1. tech40
       
      Concernant les année 2020... La plupart des BTP sont remporté tous les ans, en 2021 j'en aurais au tant quand 2020. Après selon la périodicité certaines interventions sont reporté sur d'autres années (ex: si le champ "périodicité" est égal à 2.. Le résultat sera 2022 et non 2020).

      Le champ date de fin du BTP est renseigné le jour de l'intervention par le tech en validant la case à cocher correspondant au champ soldée interv de la table "planning preventif."

      Concernant le fonctionnement...
      Une machine peut avoir plusieurs n° de BTP du à des travaux différents.
      Un n° de BTP peut avoir plusieurs "semaine interv" du au cadencement (ex: tous les 6 mois)

      Concernant la requête "report_preventif" elle foncionne très bien, elle renvoie bien toutes les bonnes informations.

      La difficulté se trouve ensuite, car il faut prendre toutes les lignes, additionné les périodicités aux années et les reporter sur la table "planning preventif"

      Voilà je pense t'avoir tous dis :)
      0
      1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588 > tech40
         
        regarde l'exemple que tu as donné pour "Planning Preventif après report", et explique pourquoi il y a 2020 pour les quatre enregistrements.
        explique aussi comment tu détermines les valeurs de "date de fin du BTP" pour les enregistrements ajoutés.

        N° BTP est-il la clé primaire dans la table "préventif"?
        0
  9. @tech
     
    Ops ! Désolé !

    J'ai mal informé le résultat attendu (le fameux copier-coller) :)

    N° BTP, Semaine interv, Année interv, soldée interv, date de fin du BTP
    7, 31, 2020, -1, 28/07/2020 (périodicité 1ans)
    7, 31, 2021, 0
    8, 31, 2020, -1, 29/07/2020 (périodicité 2ans)
    8, 31, 2022, 0

    pour les les valeurs de "date de fin du BTP" pour les enregistrements ajoutés doivent être à zéro, car on ne c'est pas encore la date de la future intervention.

    Oui, n° BTP est bien la clé primaire dans la table "préventif" (avec NuméroAuto).
    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       
      peux-tu répondre à la question en #12?
      0
    2. @tech > yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention  
       
      Question en #12?

      Est-ce para rapport au code que j'ai posté ?
      Dim i As Integer

      Ce n'est pas moi qui est codé cette application, j'essaye de corriger quelques anomalies...

      Pour moi cette ligne ne sert à rien, je pense que la personne qui l'as codé a du vouloir l'utiliser et à oublier de l'effacer !

      comme pour la ligne 20
      i = 1
      0
    3. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588 > @tech
       
      peux-tu répondre à la question que j'ai posée dans mon message #12?
      0
    4. @tech > yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention  
       
      Oui, la requête fonctionne très bien !
      Ce sont bien tous les enregistrements à ajouter dans la table "planning préventif".
      0
    5. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588 > @tech
       
      alors tu peux utiliser ceci, je pense, pour faire le report:
      INSERT INTO [Planning preventif] 
              ([N° BTP], [Semaine interv], [Année interv], [soldée interv] )
      SELECT [Planning preventif].[N° BTP], [Planning preventif].[Semaine interv], 
      [Planning preventif].[Année interv] + préventif.périodicité, False
      FROM préventif INNER JOIN [Planning preventif] 
      ON préventif.[N° BTP] = [Planning preventif].[N° BTP]
      WHERE (((préventif.Activé)=Yes)) and [Planning preventif].[Année interv] = 2020
      ORDER BY [Planning preventif].[N° BTP], [Planning preventif].[Semaine interv] ; 
      0
  10. @tech
     
    Ouuuuao! Tu es trop fort !

    Mois j'ai exporté sur Excel, et appliqué 2 formules...

    Toi une petite requête et le tour est joué !

    Je m'incline... ;)

    Avec les 2 méthodes, je trouve le même résultat.

    J'ai éliminer les doublons, et réussi enfin mettre l'index unique sur la table.

    Par contre, maintenant j'ai l'erreur 3022 (risque de doublons) lorsque je lance le code.
    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       
      si tu relances le code une deuxième fois pour la même année, c'est normal, non, que cela soit refusé avec "risque de doublons", non?
      0
      1. @tech > yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention  
         
        J'ai bien vérifier les données, je reprend toujours une sauvegarde pour refaire les test.
        La sauvegarde na plus de doublons dans la table et à le code qui fonctionne bien.
        Dès que je met la table avec l'option unique , là ça ne marche plus

        Mais pour info!
        j'ai déjà certaines ligne pour 2021, 2022, 2023, suite au périodicité des années antérieures.
        ex: 2019 avec une périodicité de 2 ans = 2021
        Je pense que il doit y avoir des doublons dans les années futures...
        0
  11. @tech
     
    Du coup j'ai bien trouvé plusieurs doublons sue les années à venir.

    Le code marche super bien ! tu es trop fort !

    Si on compare le code précédent avec le tiens y a pas photo ! (pourquoi faire simple... si on peut faire compliqué)

    Je ne ç'est pas comment te remercier !

    Merci beaucoup pour ton aide yg_be :)
    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       
      avec plaisir!

      pourras-tu marquer la discussion comme résolue?
      0
  12. tech40 Messages postés 1 Statut Membre
     
    Oui bien sûr !

    Mais je n'ai pas l'option "marquer comme résolu" sur le site, j'ai essayé via mon email, mais ça ne fonctionne pas non plus.

    Au moins j'aurais essayé.

    Merci encore pour ton aide
    0