Check array for unique values and output csv - ms-access

I need to loop through an Access query, find all the unique values from a field (in this case called UtilityDunsNumber), put them into an array and then run another query for each DunsNumber in that array and output a CSV file with all the records from that new query, then loop back through to create a file for each DunsNumber.
Here's the code I have thus far:
Private Sub Command0_Click()
Dim db As DAO.Database
Dim records() As DAO.Recordset
Dim duns() As String
Dim i As Integer
Dim fs As String
fs = "C:\TestECI\IN_572_COMPANY_" & Format(Now(), "yyyymmdd") & "_814EN01_"
Set records = db.OpenRecordset("SELECT * FROM qry_RequestECI")
'loop through records, get list of unique DUNS numbers
'get unique duns
For Each Record In records
If IsInArray(Record.UtilityDunsNumber, duns) Then
continue
Else
ReDim Preserve duns(1 To UBound(duns) + 1) As String
' add value on the end of the array
arr(UBound(arr)) = Record.UtilityDunsNumber
End If
Next
For Each UtilityDunsNumber In duns
Set records = db.OpenRecordset("SELECT * FROM qry_RequestECI WHERE UtilityDunsNumber =" & dun)
i = 2000
fs = fs & i & ".csv"
DoCmd.TransferText acExportDelim, , records, fs, True
i = i + 1
Next
End Sub
It is failing here:
Set records = db.OpenRecordset("SELECT * FROM qry_RequestECI")
with the error
"Can't assign to array"

Dim records() As DAO.Recordset
Here you're declaring an array of recordsets...
Dim records As DAO.Recordset
Is probably what you want.

There's a simplification that may or may not help. To get the list of Duns numbers, you can use
set DunsRS=db.openrecordset "select UtilityDunsNumber from qry_RequestECI group by UtilityDunsNumber"
And then you can loop through the list with
DunsRS.movefirst
do while not DunsRS.eof
dun = DunsRS.fields("UtilityDunsNumber").value
...
...
DunsRS.movenext
Loop
This might be enough to fix the problem - not sure without trying it.

Related

VB6 Assigning data to variables from a database

I've been asked to make a change to a VB6 project. The issue I'm having is that I'm trying to get some data from an Access database and assign the data to some variables.
I've got the code:
Dta_Period.DatabaseName = DB_Accounts_Name$
Dta_Period.RecordSet = "SELECT * FROM [Period]"
Dta_Period.Refresh
The table Period contains 2 fields. sMonth and Period
The sMonth field contains the months January - December. The Period field stores a number 0 to 11, to represent what number has been assigned to which month in the customers financial year. January may be 0, or may be 11, essentially.
I need to know which month goes with which period, which is why I have selected this data from the database. However, I'm stuck with what to do next.
How can I loop over the RecordSet (If this is even possible?) and find out what number has been assigned to each month?
I don't think there is a way I can use a Do Until loop. Is it easier to just use 12 separate queries, and then create an array of strings and an array of integers and then loop over the array of strings until I find the correct month, the use the same index for the array on integers?
EDIT 1
To make things simpler to follow for both myself and anyone attempting to provide an answer, I have modified the code.
Dim rstPeriod As DAO.RecordSet
Dim accDB As DAO.Database
' DB_Session is a Workspace, whilst DB_Accounts_Name$ is the name of the DB I am using
Set accDB = DB_Session.OpenDatabase(DB_Accounts_Name$)
SQL = "SELECT * FROM [Period] ORDER BY [Period]"
Set rstPeriod = accDB.OpenRecordset(SQL, dbOpenDynaset)
If rstPeriod.BOF = False Then
rstPeriod.MoveFirst
End If
Dim strMonth(11) As String
Dim pNumber(11) As Integer
Pseudocode idea:
Do Until rstPeriod.EOF
Select Case currentRow.Field("Month")
Case "January"
strMonth(0) = "January"
pNumber(0) = currentRow.Field("Number")
Case "February"
strMonth(1) = "February"
pNumber(1) = currentRow.Field("Number")
End Select
Loop
Loop through recordset and fill the arrays with the month name and month number.
This assumes the recordset returns no more than 12 records.
Public Sub LoopThroughtRecordset()
On Error GoTo ErrorTrap
Dim rs As DAO.Recordset
Set rs = CurrentDb().OpenRecordset("SELECT * FROM [Period] ORDER BY [Period]", dbOpenSnapShot)
With rs
If .EOF Then GoTo Leave
.MoveLast
.MoveFirst
End With
Dim strMonth(11) As String
Dim pNumber(11) As Integer
Dim idx As Long
For idx = 0 To rs.RecordCount -1
strMonth(idx) = rs![Month]
pNumber(idx) = rs![Number]
rs.MoveNext
Next idx
Leave:
On Error Resume Next
rs.Close
Set rs = Nothing
On Error GoTo 0
Exit Sub
ErrorTrap:
MsgBox Err.Description, vbCritical, CurrentDb.Properties("AppTitle")
Resume Leave
End Sub
'strMonth(0) = January
'strMonth(1) = February
'...
'pNumber(0) = 1
'pNumber(1) = 2
'...

Access VBA: Scripting.Dictionary - Dump to Table?

Thanks to the helpful hand provided earlier, I have a functional approach to compute Word Frequency among strings in a recordset. The following code produces the desired result.
Last step will be to dump the dictionary structure into an Access table in the currentDB. I can step thru each key as commented out below and append to a table via SQL - but it is very slow w/24K terms.
UPDATED >> w/Solution <<
Private Sub Command0_Click()
Dim counts As New Scripting.Dictionary
Dim word As Variant
Dim desc As String
Dim rs1 As DAO.Recordset
Dim rs2 As DAO.Recordset '<< solution
Dim strSQL As String
Dim db As Database
Set db = CurrentDb
strSQL = "SELECT DISTINCT Items.Description FROM Items ;"
Set rs1 = db.OpenRecordset(strSQL, dbOpenDynaset)
Do While Not rs1.EOF
For Each word In Split(rs1!Description, " ")
If Not counts.Exists(word) Then
counts.Add word, 1
Else
counts.Item(word) = counts.Item(word) + 1
End If
Next
rs1.MoveNext
Loop
'>> .AddNew Solution inserted as suggested below <<
rs2 = db.OpenRecordset("Freq", dbOpenTable)
For Each word In counts.Keys
With rs2
.AddNew ' Add new record
.Fields!Term = word
.Fields!Freq = counts(word)
.Update
.Bookmark = .LastModified
End With
Next
rs2.Close
'>> End Solution <<
Set rs1 = Nothing
Set rs2 = Nothing
MsgBox "Done"
End Sub
Question:
Can I dump the Dictionary into a table in BULK, vs stepping thru the Keys one-by-one?
Rationale: Easier (for me) to perform downstream presentation & manipulation using a table structure.
Thanks!
Your code doesn't show how you tried to insert the rows - with separate INSERT INTO (...) VALUES (...) statements for each row, I assume?
For multiple inserts in a loop, don't use SQL INSERT statements. Instead use a DAO.Recordset with .AddNew, it will be much faster.
See this answer: https://stackoverflow.com/a/33025620/3820271
And here for an example: https://stackoverflow.com/a/36842264/3820271

Looping through an array and posting array to table

I am an old Foxpro programmer and I use to use arrays to post variable fields.
What I am trying to do is I have 15 date fields in the new table I designed.
In my query I have individual records with one date for activity.
I want to compile the 15 different dates for a each Client_id into one record with 15 dates but I can't seem to reference the table data as an array.
I have tried a couple different methods of defining the array but nothing seems to work.
Here is my code that I have. In my table I have 15 date fields named Mail_date1, Mail_date2, Mail_date3, etc.
I tried first defining it just as an array but did not like it; my code always fails when I try to reference the date field in the result table rs2!mdate2 = memdate(intcounter)
How can I reference my result table output fields as an array?
Do I have to put a whole bunch of if statements to load my results?
Seems like a waste.... should be able to load them as an array.
I am a new Access 2007 VBA programmer.
Dim db As DAO.Database
Set db = CurrentDb
Dim rs1 As DAO.Recordset
Dim rs2 As DAO.Recordset
Dim FinTotal, intcounter As Integer
Dim FinMPU, FinVersion As String
Dim mail_date(1 To 15) As Date
Dim memdate(1 To 15) As Date
Dim mdate2 As String
Set rs1 = db.OpenRecordset( _
"SELECT NewFile.MPU_ID, " & _
" NewFile.MAIL_DATE," & _
" NewFile.TOTAL, " & _
" Freight.Version " &_
"FROM Freight " & _
" LEFT JOIN NewFile ON Freight.[MPU ID] = NewFile.MPU_ID " & _
"ORDER BY NewFile.MPU_ID, NewFile.MAIL_DATE")
Set rs2 = db.OpenRecordset("Final")
DoCmd.RunSQL "DELETE Final.* FROM Final;"
intcounter = 1
memdate(intcounter) = rs1!mail_date
FinMPU = rs1!mpu_ID
FinTotal = rs1!total
FinVersion = rs1!Version
rs1.MoveNext
On Error GoTo Error_MayCauseAnError
Do While Not rs1.EOF
Do While Not rs1.EOF _
And memdate(intcounter) <> rs1!mail_date _
And FinMPU = rs1!mpu_ID
intcounter = intcounter + 1
memdate(intcounter) = rs1!mail_date
FinTotal = FinTotal + rs1!total
FinVersion = rs1!Version
FinMPU = rs1!mpu_ID
rs1.MoveNext
Loop
If FinMPU <> rs1!mpu_ID Then
rs2.AddNew
mdate2 = "mail_date" & CStr(intcounter)
rs2!mdate2 = memdate(intcounter)
rs2!total = FinTotal
rs2!mpu_ID = FinMPU
rs2!Version = FinVersion
rs2.Update
FinTotal = rs1!total
FinVersion = rs1!Version
FinMPU = rs1!mpu_ID
intcounter = 1
memdate(intcounter) = rs1!mail_date
End If
rs1.MoveNext
Loop
first, if you expect and answer, you should really spend more time on properly formatting your explanation and your code...
Now, for some remarks and possible answer to the question:
You should DELETE FROM Final before you open that table in a recordset.
You should be explicit about the type of recordset you are opening:
' Open as Read-only '
Set rs1 = db.OpenRecordSet("...", dbOpenSnapshot)
' Open as Read/Write '
Set rs1 = db.OpenRecordSet("...", dbOpenDynaset)
You should Dim memdate(1 To 15) As Variant instead of Date as the Date datatype cannot be Null, and since you are pulling data from a LEFT JOIN, it's possible that the returned values could be Null if there are no corresponding data to Freight in the table Newfile.
That On Error GoTo Error_MayCauseAnError should probably not be there.
Use On Error Goto only to catch errors you can't deal with at all.
Using that here will only hide errors in your code. With some proper checks statements you should not even need the On Error Goto...
It looks like your first internal loop is trying to skip some records.
However, when that loop breaks, it could be because it reached EOF, and you never test for that in the code that follows the loop.
You never test if your intcounter goes beyond the 15 allocated dates.
Are you absolutely sure that you can never have more than 15 records?
You do not say which error message you get exactly. That could be useful to help determine the kind of issue at hand.
Instead of
mdate2 = "mail_date" & CStr(intcounter)
rs2!mdate2 = memdate(intcounter)
Use
rs2.Fields("mail_date" & intcounter).Value = memdate(intcounter)
the ! syntax of DAO really only is a shorthand for the longer rs.Fields("name") form.

How to search a field in a table in Access

Using VBA, how can I search for a text string, for example "CHIR", in a table called "ServiceYES", in the field "Service".
After that, I would like to save the neighboring field for all the rows that "CHIR" exists in the table "ServicesYES". The "ServiceYES" table is below:
I basically, want to find all the "CHIR" in "Service" column and then save the names which are on the left of the CHIR, eg "FRANKL_L", "SANTIA_D" as an array.
Thanks for all your help in advance.
Start by creating a SELECT query.
SELECT Code_Perso
FROM ServicesYES
WHERE Service = 'CHIR';
Use SELECT DISTINCT Code_Perso if you want only the unique values.
Add ORDER BY Code_Perso if you care to have them sorted alphabetically.
Once you have a satisfactory query, open a DAO recordset based on that query, and loop through the Code_Perso values it returns.
You don't need to load them directly into your final array. It might be easier to add them to a comma-separated string. Afterward you can use the Split() function (assuming you have Access version >= 2000) to create your array.
Here's sample code to get you started. It's mostly standard boiler-plate, but it might actually work ... once you give it "yourquery".
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strItems As String
Dim varItems As Variant
Set db = CurrentDb
Set rs = db.OpenRecordset("yourquery", dbOpenSnapshot)
With rs
Do While Not .EOF
strItems = strItems & "," & !Code_Perso
.MoveNext
Loop
.Close
End With
If Len(strItems) > 0 Then
' discard leading comma '
strItems = Mid(strItems, 2)
varItems = Split(strItems, ",")
Else
MsgBox "Oops. No matching rows found."
End If
Set rs = Nothing
Set db = Nothing
I tested this and it seems to work. This function will pull all records where ServiceYes='CHIR' and dump the Code_Person value into an array which it will return:
Function x() As String()
Dim rst As Recordset
Set rst = CurrentDb.OpenRecordset( _
"Select * from ServiceYES where Service='CHIR'")
Dim Arr() As String
Dim i As Integer
While rst.EOF = False
ReDim Preserve Arr(i)
Arr(i) = rst.Fields("Code_Person")
i = i + 1
rst.MoveNext
Wend
x = Arr
End Function
Sample Usage:
Debug.Print x()(0)
Paolo,
Here is something I threw together in a few minutes. You can add it to the VBA editor in a module. It uses a trick to get the RecordCount property to behave properly. As for returing the array, you can update the function and create a calling routine. If you need that bit of code, just post a comment.
Thanks!
Option Compare Database
Function QueryServiceYES()
Dim db As Database
Dim saveItems() As String
Set db = CurrentDb
Dim rs As DAO.Recordset
Set rs = db.OpenRecordset("SELECT Code_Perso, Service, Favorites " & _
"FROM ServiceYES " & _
"WHERE Service = 'CHIR'")
'bug in recordset, MoveFirst, then MoveLast forces correct invalid "RecordCount"
rs.MoveLast
rs.MoveFirst
ReDim Preserve saveItems(rs.RecordCount) As String
For i = 0 To rs.RecordCount - 1
saveItems(i) = rs.Fields("Code_Perso")
rs.MoveNext
Next i
'print them out
For i = 0 To UBound(saveItems) - 1
Debug.Print saveItems(i)
Next i
rs.Close
Set rs = Nothing
db.Close
Set db = Nothing
End Function

how to reference array variable in vba access to another variable

hi guys im trying to take the value of data(0)
and put it into say variable InvoiceNumber. I tried putting an image of my watch screen but i ended up not being allow. but here is what my watch screen would look like.
data
data(0)
data(0,1) 1
data(0,2) 2
data(0,3) 3
I have tried
dim InvoiceNumber as variant <br/>
invoiceNumber = data(0)
but i keep getting error. I dont know how to reference just the part of that array. any help would be greatly appreciated.
here is the full code for anyone that would like to see a little more.
Dim db As Database
Dim rs As Recordset
Dim data As Variant
Dim colummn1 As Variant
Dim obj As Object
Set db = CurrentDb
Set rs = db.OpenRecordset("select * from Table1")
'set obj = new object
While Not rs.EOF
'MsgBox (rs.RecordCount)
'MsgBox (rs.Fields.Count)
data = rs.GetRows(rs.Fields.Count)
Column1 = data.data(0)
Wend
rs.Close
db.Close
End Sub
Try
Column1 = data(0,0)
instead of
Column1 = data.data(0)
data contains a two-dimensional array. The fist index is the field number, the second index is the row number. Both start at zero. So data(0,0) is the first field of the first row. data(1,0) is the second field of the first row.
I would try to make an array of invoices by using a user defined type
Public Type Invoice
Nr As Variant
IssueDate As Variant
Total As Variant
'Or whatever your invoice contains
End Type
Public Sub TestGetRecords()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim data As Variant
Dim numRecords As Long, i As Long
Dim Invoices() As Invoice
Set db = CurrentDb
Set rs = db.OpenRecordset("select * from Table1")
data = rs.GetRows()
rs.Close
db.Close
numRecords = UBound(data, 2) + 1
ReDim Invoices(0 To numRecords - 1) As Invoice
For i = 0 To numRecords - 1
Invoices(i).Nr = data(0, i)
Invoices(i).IssueDate = data(1, i)
Invoices(i).Total = data(2, i)
Next i
Debug.Print Invoices(0).Total
End Sub
An error in you solution is, that you placed GetRows in a loop. However, GetRows returns all the rows at once!
I am finding it a little hard to understand what you are trying to achieve.
You are reading an entire table of data into a recordset object, loading the fields of the recordset object into a two dimensional array and then trying to iterate through the array to output the results to a single variable (or a sum of array values).
Why don't you just use an SQL expression to extract the data directly from your table?
If we can assume you have a table of invoices (say ... "myInvoiceTable") with at least the following fields ...
invoiceID
invoiceValue
(and probably many others, eg. invoiceDate, clientID, etc.)
you can write an expression something like this
"SELECT SUM(invoiceValue) AS MyTotal FROM myInvoiceTable WHERE invoiceID > xxxx"
This might go into your VBA code like this.
Dim rst as Recordset
Dim strSQL as string
strSQL = "SELECT SUM(invoiceValue) AS MyTotal FROM myInvoiceTable WHERE invoiceID > 400" '-- use an appropriate WHERE clause if needed
Set rst = CurrentDb.Openrecordset(strSQL) '-- the rst object should contain a single value "MyTotal" which is the sum of the fields you are trying to access
MsgBox rst!MyTotal '-- use this value wherever you need to use it