vba code to set values in different variables in Loop

aman

Registered User.
Local time
Today, 14:52
Joined
Oct 16, 2008
Messages
1,251
Hi All

I have variables as below:

sScore1
sScore2
sScore3
.
.
.
.
sScore20

Now I want to write a loop that will store data in each variable. SO basically a quick way for the loop:
So I am using "i" variable that will increment each time so initially it will be sScore1 and then next time it will be sScore2 but it doesn't work.

Code:
 dim i as integer
 i=1
 Set rs = CurrentDb.OpenRecordset("SELECT * FROM qryABC WHERE ID=" & Me.txtID)
    Do Until rs.EOF
        sScore & i = rs!Score
        rs.MoveNext
         i=i+1
    Loop

Any help will be much appreciated.

Thanks
 
There is no way to address named variables in a loop like that. What you might want to do is use an array or a collection; some structure in which you can address members using a numeric index.

But maybe you can say more about your overall purpose, because you seem to have this data in the recordset already, which is itself a very useful structure. Why do you need to put this data into some other sequential or indexed structure when it already exists in the recordset?
 
As I want to display the score for each record in word document. Please see attached.

Code:
         Set rs = CurrentDb.OpenRecordset("SELECT * FROM qryQAMatrix WHERE QAID=" & Me.txtQAID)
        
       Do Until rs.EOF
        Controls ("sScore") & i = rs!Score
        rs.MoveNext
    Loop
         headers = headers & """" & "Score1" & """" & vbTab
        record = record & """" & RemoveTrailingvalue(sScore1) & """" & vbTab
        headers = headers & """" & "Score2" & """" & vbTab
        record = record & """" & RemoveTrailingvalue(sScore2) & """" & vbTab
        headers = headers & """" & "Score3" & """" & vbTab
        record = record & """" & RemoveTrailingvalue(sScore3) & """" & vbTab
        headers = headers & """" & "Score4" & """" & vbTab
        record = record & """" & RemoveTrailingvalue(sScore4) & """" & vbTab
        headers = headers & """" & "Score5" & """" & vbTab
        record = record & """" & RemoveTrailingvalue(sScore5) & """" & vbTab
        headers = headers & """" & "Score6" & """" & vbTab
        record = record & """" & RemoveTrailingvalue(sScore6) & """" & vbTab
        headers = headers & """" & "Score7" & """" & vbTab
        record = record & """" & RemoveTrailingvalue(sScore7) & """" & vbTab
 

Attachments

Yeah, so just use the recordset as the loop control structure, like....
Code:
    With CurrentDb.OpenRecordset("SELECT * FROM qryQAMatrix WHERE QAID=" & Me.txtQAID)
        Do While Not .EOF
            headers = headers & "Score" & i & vbTab
            record = record & DoSomeFormatting(!Score) & vbTab
            i = i + 1
            .MoveNext
        Loop
        .close
    end with
You don't need to transfer the data out of the recordset, then use that transfered data. See how this way saves a step and takes the data directly from the recordset and into your concatenated strings?
Hope this helps,
 
Mark, I am getting runtime error 91 "Object variable or with block variable not set" at the following line of code:
Code:
  Do While Not .EOF
             headers = headers & """" & "Score" & i & """" & vbTab
             [COLOR=red]record = record & """" & RemoveTrailingvalue(rs!Score) & """" & vbTab
[/COLOR]            
            i = i + 1
            .MoveNext
        Loop
 
PMFJI,

Code:
record = record & """" & RemoveTrailingvalue(.Score) & """" & vbTab
or
Code:
record = record & """" & RemoveTrailingvalue(!Score) & """" & vbTab
as Mark had indicated?

I'm never sure whether to use the ! or the . TBH and prefer the .
 
In VBA the ! (bang) can only be used to reference a named member of a collection. It can become confusing in some cases why it works, because we commonly use it with objects that expose that collection as their default property, like Form.Controls, and Recordset.Fields.
Code:
[COLOR="Green"]' so if we do this...[/COLOR]
debug.print Me!tbTesting
[COLOR="Green"]' we are actually doing this...[/COLOR]
debug.print Me.Controls("tbTesting")[COLOR="Green"] ' but 'Controls' is the default property[/COLOR]

[COLOR="Green"]' in this thread we have an active With block exposing the recordset, 
' and we reference a member of the (default) Fields collection...[/COLOR]
With CurrentDb.OpenRecordset("SELECT * FROM SomeTable")
   debug.print .Fields("Field1")
[COLOR="Green"]   ' or in this case referencing a named member of the default (Fields) collection...[/COLOR]
   debug.print !Field1
End With
This is also why the bang does not provide intellisense at design time, because it doesn't--like the '.' (dot)--provide access to members of the object. It's just a shorthand way to exposes a named member of the collection, like...
Code:
debug.print Forms!Form1.Caption
[COLOR="Green"]' which is the same as...[/COLOR]
debug.print Forms("Form1").Caption
 
I like to first check on that EOF or BOF before starting the loop :

Code:
With CurrentDb.OpenRecordset("SELECT * FROM qryQAMatrix WHERE QAID=" & Me.txtQAID)
	If Not .BOF And Not .EOF Then
		.MoveFirst
		Do While Not .EOF
			headers = headers & "Score" & i & vbTab
			record = record & DoSomeFormatting(!Score) & vbTab
			i = i + 1
			.MoveNext
		Loop
	End If
	.close
End with

But again that are some best practices that not everybody uses.
 
Thanks guys, Please see my complete code but it doesn't merge up the scoring for each record in word document. Please see attached the word document. In the attached word document I am manually typing in <<Score1>>,<<Score2>> etc.

Code:
 Private Sub cmdSummit_Click()
Dim db As DAO.Database
'define query object perameter
Dim qry As DAO.QueryDef
Dim i As Integer
Dim rsMailmerge As Recordset
Dim strTextFile As String
Dim strTemplatePath As String
Dim strSavePath As String
Dim strSaveName As String
 Me.txtHidden.SetFocus
 strTemplatePath = "L:\Access Databases\Group Manufacturing\Mortgages Direct\Academy\ADFE\Files\T&C Templates\QA Forms\"
strSavePath = DLookup("Variable", "tblVariable", "VariableID=16")
strSaveName = "Health Check Form " & Format(Now(), "yyyymmmdd_hhmmss") & " " & Me.cboAgent.Column(1) & ".doc"
 'set current datedate as database objects
Set db = CurrentDb
'set your record set using reference from the form
Set rsMailmerge = db.OpenRecordset("SELECT * FROM tblQA WHERE [QAID] =" & Me.QAID)
 'Call GetWordHandle
'function that opens word to run in the background, function can be placed in a global module
   
    If WordApp Is Nothing Then ' if word not called before
        Err.clear   ' Clear Err object in case error occurred.
        Set WordApp = CreateObject("Word.Application")   'Start a new word application
    Else
        ' an instance of word has been created before
        On Error Resume Next 'Turn off error handling
        Err.clear   ' Clear Err object in case error occurred.
        WordApp.Visible = False 'attempt to access previous instance of word
        If Err.Number <> 0 Then ' if instance of word no longer exists then create a new one
            Err.clear   ' Clear Err object
            Set WordApp = CreateObject("Word.Application")   'Start a new word application
            On Error GoTo 0 'Revert to normal error  handling
        End If
    End If
    'Hide word (it will be made visible again CloseOrEditDocument or if an error occurs)
   
    WordApp.Visible = False
    WordApp.WindowState = 2
    WordApp.Visible = False
 'next we are going to create a text file that that the word template will merge with
'_________________________________________________________________________________________
 'text file file name
strTextFile = "HealthCheck_" & Format(Now(), "yyyymmdd_hhnnss")
 'function that creates and saves the text file
createKFIMailMergefile strPath, strTextFile & ".txt"
 'open template
Set WordDoc = WordApp.Documents.Open(strTemplatePath & "Health Check Form.dot")
'merge template with txt file
WordDoc.MailMerge.MainDocumentType = 0
WordDoc.MailMerge.Destination = wdSendToNewDocument
WordDoc.MailMerge.OpenDataSource (strPath & strTextFile & ".txt")
WordDoc.MailMerge.Execute
 'Go through all created doc and remove all mail merge errors
For i = 1 To WordApp.Application.Documents.Count
    If InStr(1, WordApp.Application.Documents(i).Name, "Error") <> 0 Then
        WordApp.Application.Documents.Item(i).Close False
        i = i - 1
    End If
    If i = WordApp.Application.Documents.Count Then Exit For
Next i
 'Save merged document as new file
WordApp.ActiveDocument.AttachedTemplate.Saved = True
WordDoc.Application.Documents.Item(1).SaveAs strSavePath & strSaveName, , , , False, , True
 'Go through all created doc and close them
    For i = 1 To WordApp.Application.Documents.Count
        WordApp.Application.Documents.Item(WordApp.Application.Documents.Count).Close False
    Next i
 'WordDoc.Close
'WordApp.Quit
 'delete the text file
Kill strPath & strTextFile & ".txt"
 'delete the subs
exithere:
WordApp.Quit
Set WordDoc = Nothing
Set WordApp = Nothing
Set qry = Nothing
Set db = Nothing
MsgBox ("Export Completed")
'MergePCACallData
Application.FollowHyperlink strSavePath & strSaveName
Exit Sub
 exporterror:
Resume exithere
End Sub

Code:
Function createKFIMailMergefile(sFileDIR As String, sFileName As String)
'static constants that make the fumction work
Dim FileNumber
Dim rs As Recordset
Dim headers As String
Dim record As String
Dim i As Integer
 'variable function that change depending on the data that is being added to the text file
Dim sScore1 As String
Dim sScore2 As String
Dim sScore3 As String
Dim sScore4 As String
Dim sScore5 As String
Dim sScore6 As String
Dim sScore7 As String
Dim sScore8 As String
Dim sScore9 As String
Dim sScore10 As String
Dim sScore11 As String
Dim sScore12 As String
Dim sScore13 As String
Dim sScore14 As String
Dim sScore15 As String
Dim sScore16 As String
Dim sScore17 As String
Dim sScore18 As String
Dim sScore19 As String
Dim sScore20 As String
Dim sScore21 As String
Dim sScore22 As String
Dim sScore23 As String
'set the variables that will be used for this recordset as null
 sScore1 = ""
sScore2 = ""
sScore3 = ""
sScore4 = ""
sScore5 = ""
sScore6 = ""
sScore7 = ""
sScore8 = ""
sScore9 = ""
sScore10 = ""
sScore11 = ""
sScore12 = ""
sScore13 = ""
sScore14 = ""
sScore15 = ""
sScore16 = ""
sScore17 = ""
sScore18 = ""
sScore19 = ""
sScore20 = ""
sScore21 = ""
sScore22 = ""
sScore23 = ""
 
'Get unused file (note by SW - unsure what this does)
FileNumber = FreeFile
        
    i = 1
    'First we open a need to create the headings. (opens the file and sets the output for the data to be transfered into it)
    Open sFileDIR & sFileName For Output As #FileNumber ' Create filename.
    
    'Get all QA Data
    'Open the recordset for where this particular data will be sourced from (can be table or a query)
    'Set rs = CurrentDb.OpenRecordset("SELECT * FROM tblQAStandard WHERE QAID=" & Me.txtQAID)
        
    'loop through all the records, setting format where necessary and dealing with null values
    With CurrentDb.OpenRecordset("SELECT * FROM tblQAStandard WHERE QAID=" & Me.txtQAID)
    If Not .BOF And Not .EOF Then
        .MoveFirst
        Do While Not .EOF
             headers = headers & """" & "Score" & i & """" & vbTab
             record = record & """" & RemoveTrailingvalue(!Score) & """" & vbTab
             i = i + 1
            .MoveNext
        Loop
    End If
        .Close
    End With
      
    Print #FileNumber, headers ' Output text.
    Print #FileNumber, record ' Output text.
        
    Close #FileNumber   ' Close file.
End Function

Many Thanks
 

Attachments

ANy help on this anyone? There is a score field in the table and for each criteria about 20 records so I need to display the scoring for each record in word document . The code in previous post doesn't merge up the scoring..
Thanks
 
My understanding was if no records exist then both .BOF and .BOF would be true on the select code?
If that is not the case then at least one record exists?

I've just created the code below to satisfy myself and the messages are displayed as coded and expected.

Tested SQL output on both .BOF and .EOF with same results, so I see little point on testing for both. My typing is not that good, so any shortcuts I can use the better.:D

Code:
Sub TestEOF()

With CurrentDb.OpenRecordset("Select * from tblEmployee")
    If .BOF Then
        MsgBox "Empty File"
    Else
        .MoveFirst 'Not really needed?
        MsgBox "Records exist"
        Do Until .EOF
            MsgBox !EmployeeName
            .MoveNext
        Loop
    End If
End With
End Sub



I like to first check on that EOF or BOF before starting the loop :

Code:
With CurrentDb.OpenRecordset("SELECT * FROM qryQAMatrix WHERE QAID=" & Me.txtQAID)
	If Not .BOF And Not .EOF Then
		.MoveFirst
		Do While Not .EOF
			headers = headers & "Score" & i & vbTab
			record = record & DoSomeFormatting(!Score) & vbTab
			i = i + 1
			.MoveNext
		Loop
	End If
	.close
End with

But again that are some best practices that not everybody uses.
 
Last edited:
Agreed. This is sufficient for looping thru rows in a newly opened recordset...
Code:
with currentdb.openrecordset("SomeTable")
   do while not .eof
[COLOR="Green"]      'do something with each row[/COLOR]
      .movenext
   loop
   .close
end with
In a newly opened recordset both .bof and .eof have the same value, and if there is at least one record, the first record is current. So no need to check both .bof and .eof, and no need to .MoveFirst.
 
I see. The templates I uses are made so i can display at the bottom of access a counter. Like "processing file x of y" If you want that, you must first move to the last record to get the correct value in "RecordCount".

But again, it is a matter of preferences i guess. You can also just test if RecordCount <> 0.
 
Hello, The record count is not null but the Scoring doesn't get copied across the word document. Is it because I have typed manually in word document <<Score1>>
<<Score2>>,<<Score3>> etc...
 
Yes you will have to create a word document and use the mail merge thing :
mail_merge2.jpg


Just start the wizard and when you need to select a file, select the access database. There you will be able to select your data and use the fields to create the table.

(If you have trouble just create a A4 label.)
 
Grumm , I know how to create mail merge but if you see my complete code , I have to use Headers in the mail merge. In the table there is only one field "Score" but I am using different Headers like SCore1,SCore2,Score3 ...etc. to store scoring for each record and now I want to use those headers in the word document. ANy help on this?
 
But your complete code is not correct... you cannot get variables by using "score" & i.
Have you tried to fix that already ?
 
Grumm, so is this not the correct way to define headers as below:
Code:
 If Not .BOF And Not .EOF Then
        .MoveFirst
        Do While Not .EOF
             headers = headers & """" & "Score" & i & """" & vbTab
             record = record & """" & RemoveTrailingvalue(!Score) & """" & vbTab
             i = i + 1
            .MoveNext
        Loop
    End If

I believe , it should create headers SCore1,Score2,SCore3.... etc..

Thanks
 
Yes sorry. That is correct. So for each score you have a header and a record.
But I don't see why you need headers since you want to display the score in one table.

Why not just use the query as datasource ?

Example :
Code:
Set WordDoc = WordApp.Documents.Open(strTemplatePath & "Health Check Form.dot")
strConnection = "DSN=MS Access Databases;DBQ=Path to your accdb or mdb;FIL=RedISAM;"
'merge template with txt file
WordDoc.MailMerge.MainDocumentType = wdFormLetters
WordDoc.MailMerge.Destination = wdSendToNewDocument
WordDoc.MailMerge.OpenDataSource Name:="Path to your accdb or mdb", Connection:=strConnection, SQLStatement:="SELECT * FROM tblQA WHERE [QAID] =" & Me.QAID
WordDoc.MailMerge.Execute
 'Go through all created doc and remove all mail merge errors
For i = 1 To WordApp.Application.Documents.Count
    If InStr(1, WordApp.Application.Documents(i).Name, "Error") <> 0 Then
        WordApp.Application.Documents.Item(i).Close False
        i = i - 1
    End If
    If i = WordApp.Application.Documents.Count Then Exit For
Next i
 'Save merged document as new file
WordApp.ActiveDocument.AttachedTemplate.Saved = True

Not sure if it will work after the first try. But here is some extra information :
https://msdn.microsoft.com/en-us/library/office/ff841005.aspx
 

Users who are viewing this thread

Back
Top Bottom