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

Access Discussion :

Manipulation de l'objet recordset


Sujet :

Access

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2014
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2014
    Messages : 41
    Points : 39
    Points
    39
    Par défaut Manipulation de l'objet recordset
    Bonjour à tous,
    J'ai un petit problème à vous soumettre à propos des manipulations de l'objet recordset.
    Je replace d'abord le contexte.
    Je suis en train de basculer la gestion de portefeuilles boursiers d'Excel vers Access qui, compte tenu de la complexité accrue du sujet (plusieurs comptes titres dans plusieurs banques différentes, plusieurs porteurs et donc un historique de cours qui commence à devenir lourd).
    Ma base de données est organisée de la façon suivante pour l'historique des cours et le nombre de titres présent sur chaque compte. Chaque titre est détaillé dans une table dont le nom est le code ISIN (identifiant international unique pour toute valeur cotée en bourse).
    Chaque enregistrement de ces tables représente les données à une date :
    - champ "DateCours" (format date), unique et indexé en tant que clé primaire de nom "PK_DateCours" ;
    - champ "Cours" (format numérique double), non indexé, qui contient le cours de la valeur à la date donnée ;
    - autant de champs que nécessaire dont les noms sont "CPxxxx" (format numérique entier long) où les deux premiers "x" reprennent l'id du numéro du compte qui porte cette valeur et les deux derniers, l'id du porteur qui détient cette valeur. Pour info les id cités proviennent des tables "Comptes" et "Portefeuilles" qui décrivent leurs caractéristiques. Ces champs "CPxxxx" contiennent le nombre de titres détenus à la date donnée.
    Je mets donc à jour ces tables à partir des feuilles Excel qui contenaient les données.
    La première étape, qui s'est bien déroulée, a été la création de ces tables titres avec l'historique des cours (remplissage des champs "DateCours" et "Cours").
    J'ai donc environ 150 de ces tables dans la base.
    Lors de l'étape suivante, je crée dans ces tables le champ "CP0101" qui contiendra le nombre de titres détenus par le portefeuille 01 dans le compte 01.
    Pour ce faire, sous Excel, j'ai créé un fichier csv par table contenant deux champs par enregistrement reprenant chacun la date et le nombre de titres détenus à cette date et j'intègre ces données dans chaque table correspondante.
    La macro est la suivante :

    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    Sub ImportNbrCSV()
      ' Déclaration des variables
      Dim dtbBase As DAO.Database
      Dim tblTable As DAO.TableDef
      Dim fldChamp As DAO.Field
      Dim rstEnregO, rstEnregD As DAO.Recordset
      Dim strClasseurNom, strFicNom, strTableNom, strTableTmp, strChampNom, strRequete1, strRequete2 As String
      Dim sngChrono As Single
     
      ' Définition des variables
      Set dtbBase = CurrentDb
      strClasseurNom = "C:\Bourse\"
      strFicNom = Dir(strClasseurNom & "*.csv", vbDirectory)
      strTableTmp = "TableTmp"
      strChampNom = "CP0101"
     
      ' Boucle sur les fichiers CSV
      Do While (strFicNom <> "")
        ' Teste si c'est un fichier ou un répertoire
        If (GetAttr(strClasseurNom & strFicNom) And vbDirectory) <> vbDirectory Then
          ' C'est un fichier, on en déduit le nom de la table concernée à partir du nom du fichier
          strTableNom = Left(strFicNom, Len(strFicNom) - 4)
     
          ' Ajout d'un champ dans la table destination
          Set tblTable = dtbBase.TableDefs(strTableNom)
          Set fldChamp = tblTable.CreateField(strChampNom, dbLong)
          fldChamp.Required = True
          tblTable.Fields.Append fldChamp
          Set fldChamp = Nothing
          tblTable.Fields.Refresh
     
          ' Transfert du fichier trouvé dans une table temporaire avec le modèle d'import adéquat
          DoCmd.SetWarnings False
          DoCmd.TransferText acLinkDelim, "Import_CodeISIN", strTableTmp, strClasseurNom & strFicNom
     
          ' Ajout des données dans la table de destination
          Set rstEnregO = dtbBase.OpenRecordset(strTableTmp)
          Set rstEnregD = dtbBase.OpenRecordset(strTableNom)
          ' Boucle sur les enregistrements de la table temporaire
          sngChrono = Timer
          While Not rstEnregO.EOF
            ' Met la table destinataire à jour à partir de l'enregistrement de la table temporaire
     
            ' Solution 1 : RunSQL
            strRequete1 = "UPDATE " & strTableNom & _
                                " SET " & strTableNom & "." & strChampNom & " = " & CLng(rstEnregO.Fields("Cours").Value) & _
                                " WHERE " & strTableNom & ".DateCours = #" & Format(rstEnregO.Fields("DateCours").Value, "mm\/dd\/yyyy") & "#"
            DoCmd.RunSQL strRequete1
     
            ' Solution 2 : FindFirst
            'strRequete1 = "DateCours=#" & Format(rstEnregO.Fields("DateCours").Value, "mm\/dd\/yyyy") & "#"
            'rstEnregD.FindFirst strRequete1
            'rstEnregD.Edit
            'rstEnregD.Fields(strChampNom).Value = CLng(rstEnregO.Fields("Cours").Value)
            'rstEnregD.Update
     
            ' Solution 3 : Seek
            'strRequete1 = "#" & Format(rstEnregO.Fields("DateCours").Value, "mm\/dd\/yyyy") & "#"
            'strRequete2 = Format(rstEnregO.Fields("DateCours").Value, "mm\/dd\/yyyy")
            'rstEnregD.Index = "PK_DateCours"
            'rstEnregD.Seek "=", strRequete1
            'rstEnregD.Seek "=", strRequete2
            'rstEnregD.Edit
            'rstEnregD.Fields(strChampNom).Value = CLng(rstEnregO.Fields("Cours").Value)
            'rstEnregD.Update
     
            rstEnregO.MoveNext
            DoEvents
          Wend
     
          MsgBox "Durée du traitement : " & Timer - sngChrono & " secondes"
     
          ' Efface la table temporaire et le fichier csv
          Set rstEnregO = Nothing
          Set rstEnregD = Nothing
          Set tblTable = Nothing
          DoCmd.DeleteObject acTable, strTableTmp
          Kill strClasseurNom & strFicNom
          DoCmd.SetWarnings True
        End If
     
        ' Passe au fichier csv suivant
        strFicNom = Dir
        DoEvents
      Loop
     
      Set dtbBase = Nothing
    End Sub
    Première question : pourquoi est-on obligé de passer par une table temporaire pour récupérer les données du fichier csv ?
    J'ai bien sûr essayé d'enregistrer les données directement dans la table destinataire, mais ça ne marche pas...

    Ensuite, pour mettre à jour la table destinataire, je parcours la table temporaire enregistrement par enregistrement après avoir créé l'objet recordset "rstEnregO".
    Là, je recherche l'enregistrement de la table destinataire dont la date correspond à celle de l'enregistrement de la table temporaire pour mettre à jour le champ "CPxxxx" avec la donnée contenue dans le second champ de l'enregistrement de la table temporaire.
    J'ai d'abord exécuté cette opération par la méthode RunSQL (Solution 1) qui fonctionne parfaitement. Mais je me suis demandé si c'était la plus rapide.
    Donc j'ai tenté tour à tour les solutions 2 et 3 qui font appel à l'objet recordset "rstEnregD" créé sur la table destinataire.
    La solution 2 avec la méthode FindFirst génère l'erreur 3251 (Opération non autorisée pour ce type d'objet) sur la commande "rstEnregD.FindFirst strRequete1".
    La solution 3 avec la méthode Seek génère l'erreur 3421 (Erreur de conversion de typede données) pour le critère de recherche strRequete1 (avec dièses entourant la date) sur la commande "rstEnregD.Seek "=", strRequete1" et l'erreur 3021 (Aucun enregistrement en cours) avec le critère strRequete2 (sans les dièses) sur la commande "rstEnregD.Edit", ce qui veut dire qu'il n'a pas trouvé l'enregistrement cherché.
    Je ne comprends pas pourquoi ces erreurs sont générées. C'est donc l'objet de ma seconde question.
    Merci d'avance.

  2. #2
    Rédacteur/Modérateur
    Avatar de loufab
    Homme Profil pro
    Entrepreneur en solutions informatiques viables et fonctionnelles.
    Inscrit en
    Avril 2005
    Messages
    12 015
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Entrepreneur en solutions informatiques viables et fonctionnelles.
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2005
    Messages : 12 015
    Points : 24 550
    Points
    24 550
    Par défaut
    Bonjour,

    Je laisse le côté métier pour ne m'attacher qu'à la partie technique.

    runsql et autre db.execute sont généralement plus rapide puisque les requêtes font un traitement par lot d'enregistrement.

    L'approche dao/edit/addnew au moyen de findfirst traite les enregistrements par enregistrements c'est théoriquement plus long.

    A moins de faire du traitement par enregistrement au moyen de requêtes (runslq/execute). Suivant le traitement on peut avoir ou non le choix.

    Concernant tes messages d'erreurs :
    Findfirst : tu ouvres un recordset sur une table, utilise plutôt une requête du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
          Set rstEnregO = dtbBase.OpenRecordset("SELECT * FROM " & strTableTmp, dbopensnapshot)  'lecture seule
          Set rstEnregD = dtbBase.OpenRecordset("SELECT * FROM " & strTableNom; dbopendynaset)  'lecture/ecriture

    Seek :

    Essaye de passer ton paramètre date sans les # mais avec des ". Comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    strRequete1 = """" & Format(rstEnregO.Fields("DateCours").Value, "mm\/dd\/yyyy") & """"
    Je ne pense pas que le gain de temps soit significatif par rapport à la première instruction. Surtout si il y a des dates à Null.

    Cordialement,

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2014
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2014
    Messages : 41
    Points : 39
    Points
    39
    Par défaut
    Merci, je vais tester cela pour ne pas mourir idiot.
    Le traitement est terminé de façon très satisfaisante avec la méthode RunSQL.
    Encore merci du conseil.
    Bonnes fêtes

  4. #4
    Rédacteur/Modérateur
    Avatar de loufab
    Homme Profil pro
    Entrepreneur en solutions informatiques viables et fonctionnelles.
    Inscrit en
    Avril 2005
    Messages
    12 015
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Entrepreneur en solutions informatiques viables et fonctionnelles.
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2005
    Messages : 12 015
    Points : 24 550
    Points
    24 550
    Par défaut
    Merci et bonnes fêtes à toi aussi.

Discussions similaires

  1. ERREUR:la méthode open de l'objet recordset a échoué
    Par ashash dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 16/07/2007, 13h06
  2. Objet recordset de type table
    Par Kallamou dans le forum Access
    Réponses: 3
    Dernier message: 13/02/2007, 11h38
  3. Réponses: 12
    Dernier message: 14/06/2006, 09h50
  4. Problème de lock d'un objet recordset
    Par aircamus dans le forum IHM
    Réponses: 2
    Dernier message: 12/06/2006, 14h17
  5. Manipulation d'un Objet OLE Excel ?
    Par NiKro75 dans le forum VBA Access
    Réponses: 10
    Dernier message: 05/07/2004, 17h43

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