Où oDb est t'il instancié ?
Version imprimable
Où oDb est t'il instancié ?
Le Delete sert à supprimer le contenu de la table mais pas la table (en tant qu'objet).
Pour supprimer physiquement une table (objet) ou un lien il faut utiliser la commande :
Je suis peut-être à coté de la plaque ?!Code:
1
2 docmd.DeleteObject acTable...
Loufab
Ok, je comprends mieux...
Donc oDb.Execute pour travailler avec le contenu de la table.
et docmd.DeleteObject acTable... pour travailler avec la table dans son entier.
(si j'ai pas trop mal compris)
Tofalu
oDb est intancié au début de chaque procédure qui l'utilisent, (sauf erreur).
Et à ce propos j'ai un nouveau problème :
(Le code qui suit est partiellement extrait de ton cours DAO.)
Le but étant la création d'une table "Table1" et d'un champ, dont le nom est contenu dans la variable "GlobNumChp".Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 Private Sub CreerTable1() Dim oDb As DAO.Database Dim oNouvelleTable As DAO.TableDef 'Instancie la base de données Set oDb = CurrentDb 'Crée la nouvelle table Set oNouvelleTable = oDb.CreateTableDef("Table1") 'Crée le champ contenu dans la variable "GlobNumChp" et l'ajoute oNouvelleTable.Fields.Append oNouvelleTable.CreateField(GlobNumChp, _ dbText, 100) 'Ajoute la table à la base de données oDb.TableDefs.Append oNouvelleTable 'Libère les variables oDb.Close Set oNouvelleTable = Nothing Set oDb = Nothing End Sub
La ligne "oDb.TableDefs.Append oNouvelleTable" semble causer une erreur :
"Le moteur de base de données ne peut trouver ". Assurez-vous que le nom de paramètre ou d'alias est valide, qu'il ne comprend pas de caractère ou de ponctuation incorrect et qu'il n'est pas trop long."
Concernant ton problème chez moi ça fonctionne, à part la variable Globnum... correspondant au nom que j'ai remplacé par "TOTO" (un nom qui en vaut un autre).
Pour créer une table tu peux également utiliser une requete de creation de table.
Voir CREATE en langage SQL. Dans mon tuto sur la recherche il y a 3 liens -vers le milieu du tuto- qui donne l'ensemble des syntaxes SQL.
Cordialement,
Tu a visé juste ! C'était bien la variable "GlobNumChp" qui causait l'erreur !
Merci pour l'info de création via SQL c'est bon à savoir !
Modif message
J'utilise actuellement ce type de code pour effectuer des enregistrement dans une table :
Mais je souhaiterai pouvoir effectuer des enregistrements sur une même ligne, de colonne en colonne dans une table.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 Private Sub SauvTab() Dim oDb As DAO.Database Dim oRsTab As DAO.Recordset Set oDb = CurrentDb Set oRsTab = oDb.OpenRecordset("Table1", dbOpenTable) If (oRsTab.RecordCount <> 0) Then oRsTab.MoveLast End If oRsTab.AddNew oRsTab.Fields(GlobNumChp).Value = GlobSauvTab1 oRsTab.Update Set oRsTab = Nothing Set oDb = Nothing End Sub
J'ai déjà pensé à créer une fonction qui ajoute des champs selon un test :
Mais je ne sais pas comment écrire en VBA : enregistre "ceci" "là", en ayant le choix ET de la ligne ET de la colonne.Code:
1
2
3 If GlobNumChp > 1 Then Call AjtChpTable1 'appel de la fonction d'ajout de champ End If
J'espère ne pas passer pour un boulet qui n'a pas cherché avant de poster parce que c'est un problème que je traine depuis longtemps !
Modif
(P.S: Je précise au passage que mon but est de trier des données, donc si quelqu'un a une suggestion à me faire concernant la manière habituelle de traiter ce genre de problème ça m'intéresse !)
Voilà un extrait de la procédure mère de mon formulaire.Code:
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 Private Sub AutoCall(oDb As DAO.Database, sRef As String, iNiveau As Integer) ... ... 'requête SQL de sélection des sous références qui sont elles mêmes mères sSql = "SELECT REF_2 FROM T1 WHERE (((REF_1)=""" & sRef & """) " & _ "AND ((REF_1)<>(REF_2)) AND ((TYPE_REF_2)=1))" 'attribution des résultats de la requête ci-dessus à l'objet recordset oRs Set oRs = oDb.OpenRecordset(sSql, dbOpenSnapshot) 'dbOpenSnapshot 'boucle d'enregistrement des références trouvées dans la zone de liste ... ... ' Boucle sur les enregistrements jusqu'au dernier Do Until oRs.EOF = True 'La source des lignes de la listbox (séparées par ;) est 'complétée au fur et à mesure 'par le champ de l'enregistrement courant Me.Liste2.RowSource = Me.Liste2.RowSource & oRs.Fields(0) & ";" 'Appel récursif de la fonction 'paramètres : la base contenant la table, le champ de 'l'enregistrement courant, la profondeur de recherche suivante AutoCall oDb, oRs.Fields(0), iNiveau + 1 'on passe à l'enregsitrement suivant oRs.MoveNext Loop 'fin de la boucle ... ... End Sub
Elle effectue une recherche récursive dans une table contenant plus de 100 000 enregistrements en exécutant autant de fois que nécessaire la requête SQL.
Cette "double boucle" fonctionne très bien (merci encore à Philben), mais selon la variable de recherche "sRef" le temps d'exécution peut atteindre 15 ou 20 secondes.
Je sais que ce n'est pas facile à partir d'un morceau de programme, mais si quelqu'un a un conseil à me donner pour accélérer la vitesse de recherche ça m'intéresse beaucoup.
Bonjour,
je regarde si on peut optimiser la vitesse, en attendant peux-tu vérifier 2 choses :
A) que le champ REF_1 soit bien indexé avec doublons (l'indexation des autres champs n'est pas nécessaire pour améliorer la vitesse)
B) que ton ordinateur ne soit pas un 8086 !:lol:
@+
Philippe
Une fois encore tu satisfait on ne peut mieux mes objectifs.
En indexant REF_1 (le premier champ) la recherche sur la plus grosse arborescence (059-063) a pris une petite seconde contre une 20taine avant !
Que du bonheur !
Modif
En fichier joint un aperçu de la version actuelle de la fenêtre du formulaire.
Ce formulaire contient une zone de liste (le grand tableau à fond blanc), celle ci ayant pour "contenu" la table "TabArbo" créée par le formulaire. Mon problème est que je ne sais pas comment "vider" cette zone de liste à chaque exécution de la recherche, ni comment la mettre à jour à la fin de la recherche. J'ai essayé mais les résultats des recherches successives s'affichent à la suite les uns des autres, donc problème...
Pour info la zone de liste est nommée Liste_TabArbo, et la table du contenu "TabArbo".
Merci pour toute suggestion !
Pour l'instant j'ai laissé de côté le problème d'actualisation et d'initialisation de la liste...
En attendant je me retrouve face à mon dernier objectif ! A près mon programme sera fini !
En fichier joint figure un aperçu de la table que me créé mon formulaire.
Les enregistrements font apparaître l'arborescence appartenant à une référence mère.
Sachant que chaque référence est associée à une quantité et à un prix je souhaiterai en calculé le total automatiquement.
L'idée est donc de calculer successivement les prix des références de plus bas niveau (le plus à droite dans la table) et de remonter chaque branche pour sommer les prix en tenant compte des quantités.
Mon explication est un peu confuse, mais si quelqu'un a une suggestion d'un point de vue "logique" sur la démarche à privilégier ça m'intéresse beaucoup !
Oubliez le message précédent j'ai changé d'optique !
Par contre j'aimerai bien savoir comment mettre un enregistrement spécifique d'une table en enregistrement "courant" !
Merci pour toute aide !
Modif
Je ne comprends pas, à chaque fois que je lance mon formulaire j'ai un bug qui me dit que je n'ai pas d'enregistrement courant et qui me renvoi à la ligne oRstt.edit.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 'AJOUTER (pas remplacer) la somme calculée au prix de la table PRIX Private Sub Ajout_Prix() Dim oDbtt As DAO.Database Dim oRstt As Recordset Dim sSql As String Set oDbtt = CurrentDb sSql = "SELECT * FROM PRIX WHERE (PRIX.Reference_Article)="" & GlobREF & """ MsgBox GlobREF Set oRstt = oDbtt.OpenRecordset(sSql, dbOpenDynaset) 'stocker l'enregistrement courant de la table PRIX If (oRstt.RecordCount = 0) Then MsgBox "Recordset vide" End If oRstt.Edit oRstt("Prix_U") = oRstt("Prix_U") + PRIX_TOTAL oRstt.Update oRstt.Close Set oRstt = Nothing Set oDbtt = Nothing End Sub
[/QUOTE]Code:
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 'AJOUTER (pas remplacer) la somme calculée au prix de la table PRIX Private Sub Ajout_Prix() Dim oDbtt As DAO.Database Dim oRstt As Recordset Dim sSql As String Set oDbtt = CurrentDb sSql = "SELECT * FROM PRIX WHERE (PRIX.Reference_Article)=""" & GlobREF & """;" ' verifie également cette chaine SQL les double cote et la virgule MsgBox GlobREF Set oRstt = oDbtt.OpenRecordset(sSql, dbOpenDynaset) 'stocker l'enregistrement courant de la table PRIX If (oRstt.RecordCount = 0) Then MsgBox "Recordset vide" exit sub 'normal si il est vide on sort End If oRstt.Edit oRstt("Prix_U") = oRstt("Prix_U") + PRIX_TOTAL oRstt.Update oRstt.Close Set oRstt = Nothing Set oDbtt = Nothing End Sub
merci pour le code mais je ne comprend pas comment oRstt puisse être vide...puisque lorsque je créé manuellement une requête en utilisant à la lettre la chaîne SQL utilisé dans cette procédure, j'obtiens un résultat !...Bizarre.
Modif
Sans trop comprendre pourquoi depuis que j'ai modifié le code précédent par celui-ci je n'ai plus eu de bug avec la ligne oRstt.edit
Mais quand un bug est résolu, un nouveau prend la relève...Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 Private Sub Ajout_Prix() Dim oDbtt As DAO.Database Dim oRstt As Recordset Set oDbtt = CurrentDb Set oRstt = oDbtt.OpenRecordset("PRIX", dbOpenDynaset) If oRstt.Fields(0).Value = GlobREF Then oRstt.Edit oRstt(1) = oRstt(1) + PRIX_TOTAL oRstt.Update Else oRstt.MoveNext End If oRstt.Close Set oRstt = Nothing Set oDbtt = Nothing End Sub
Avant de ré appeller au secours j'aimerai savoir si il est possible d'exécuter un code en mode normal (pas en pas à pas) mais en forçant le surlignage de chaque ligne du code au fur et à mesure de leur lecture ?
Bonjour,
Une requête utilisée par mon formulaire "FormRechSousNom" est nommée "Req_TabArbo2".
Je n'arrive pas à l'actualiser quand je le souhaite via du code VBA.
J'ai déjà essayé :
mais un message d'erreur me retourne "Req_TabArbo2" comme variable indéfinie... Merci d'avance.Code:Req_TabArbo2.requery
Bonjour Julien,
c'est sur ton sous-formulaire qu'il faut faire requery et non directement sur ta requete.
@+
Philippe
Merci ça à l'air de fonctionner ! (Toujours un bug mais venant d'ailleurs je pense).
J'ai 2 petites questions :
Est ce correct d'écrire ceci si je veux augmenter la valeur d'une cellule (2ième colonne d'une table Access), d'une certaine valeur contenue dans une variable (Cout) :
Dim cout as integer
...
oRs.Fields(1) = oRs.Fields(1) + Cout
...
Question 2 :
Comment écrire en code VBA : Si le contenu du recordset "oRs" est vide alors faire CA, sinon faire CECI.
Merci d'avance !
C'est Ok, pour plus de lisibilité tu peux écrire :Citation:
Dim cout as integer
...
oRs.Fields(1) = oRs.Fields(1) + Cout
...
Code:
1
2
3
4
5
6
7
8
9
10 ' Style littéraire ! oRs.fields("NomduChamp").Value = oRs.fields("NomduChamp").Value + Cout ou oRs.fields("NomduChamp") = oRs.fields("NomduChamp") + Cout ou oRs.fields![NomduChamp] = oRs.fields![NomduChamp] + Cout ou ...
pour vérifier si oRs n'est pas vide, on test le flag EOF (ou BOF ?) qui est vrai si l'on a dépassé la fin du jeu d'enregistements.
Si on dépasse la fin du jeu d'enregistrement avant d'avoir déplacé le curseur (oRs.movenext,etc...) c'est qu'il n'y a pas d'enregistrement...
@+Code:
1
2
3
4
5
6
7 if not oRs.EOF then 'si le jeu d'enr. n'est pas vide ... else 'pas d'enregistrement ... endif
Philippe
Merci Philippe !
Pour ce qui est de la syntaxe d'ajout d'une valeur à un objet Recordset je pense être bien calé maintenant !
Par contre, mon problème du à un enregistrement "vide" persiste.
J'ai essayé ceci :
Explication du fonctionnement théorique du code ci-dessus :Code:
1
2
3
4
5
6
7
8 top: If oRs.EOF = False Then oRs.MoveNext If oRs.Fields("REF") = REF Then GoTo top End If End If
Le recordset contient le résultat d'une requête triée par le champ REF.
Je veux écrire : Si on est pas arrivé à la fin du Recordset, ALORS aller à l'enregistrement suivant (oRs.MoveNext).
Puis effectuer le test suivant :
Si le contenu du champ REF (format "texte") de l'enregistrement suivant est identique au précédent, ALORS aller à "Top" et recommencer le premier test.
Pour une raison que je ne comprends pas encore, à chaque exécution de mon formulaire, j'ai systématiquement le message d'erreur suivant :
Erreur d'exécution '3021'.
Aucun enregistrement en cours.
Je procède donc au débogage et lorsque je glisse ma souris sur REF (juste avant le then), l'info bulle du contenu de la variable REF m'affiche toujours le dernier enregistrement de la requête !
Si ce n'est pas clair, questionnez moi et merci d'avance pour tout type d'aide !
Bonjour Julien,
je pense que le problème vient du fait que tu bouges le curseur trop tôt et ton flag eof peut être à vrai avant d'accéder au contenu du champ, écrire un truc comme ça :
Conventionnellement, on n'utilise pas une étiquette pour faire une boucle, utiliser plutôt les boucles while/wend ou do/loop.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 If oRs.EOF = False Then REF = ors.fields("REF") 'récupère le contenu du 1er enr. du recordset oRs.MoveNext do until ors.eof = true 'boucle jusqu'à la fin du jeu d'enr. If oRs.Fields("REF") = REF Then 'si ref identiques REF = ors.fields("REF") 'sauve alors la ref en cours oRs.MoveNext 'passe à l'enr suivant else exit do ' on sort si la ref de l'enr. précédent est différente de la ref en cours endif loop End If
@+
Philippe
Merci pour le code !
En effet j'avais un problème d'ordonnancement dans mon premier code.
Celui-ci est maintenant adapté à mon objectif :
Il fallait que je fasse le test oRs.EOF = False APRES le passage au recordset suivant et non AVANT !Code:
1
2
3
4
5
6
7 top: oRs.MoveNext If oRs.EOF = False Then If oRs.Fields("REF") = REF Then GoTo top End If End If
Merci !
Je vais régler le problème de la boucle par étiquette et ça devrait être bon !
Modif
Ca m'a enfin l'air correct ainsi :
(J'espère que l'utilisation de l'étiquette "fin:" n'est pas abusive.
Code:
1
2
3
4
5
6
7 Do Until oRs.EOF = True If oRs.Fields("REF") = REF Then oRs.MoveNext Else: GoTo fin End If Loop fin:
Re Bonjour,
Pour effacer des tables j'utilise l'agorythme suivant :
Mais je suppose qu'on peut éviter d'écrire une procédure à chaque nouvelle table à effacer (?) N'est-il pas possible de gérer ça par le biais d'argument (dont je ne connais pas la syntaxe).Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 Private Sub SupprTabArbo() On Error GoTo err Dim oDb As DAO.Database Dim NomTable As String NomTable = "TabArbo" DoCmd.DeleteObject acTable, NomTable Set oDb = Nothing err: End Sub Private Sub SupprTabArbo2() On Error GoTo err Dim oDb As DAO.Database Dim NomTable As String NomTable = "TabArbo2" DoCmd.DeleteObject acTable, NomTable Set oDb = Nothing err: End Sub
Pour info, l'appel des 2 procédures ci-dessus est effectué par la fonction "Call" située dans une autre procédure principale.
Si il y a une solution permettant de centraliser l'effacement de tables plutôt que d'écrire une procédure dédiée à chacune d'elles je suis donc très intéressé !
Merci d'avance pour tout commentaires.