Get the Nth index of an array in VBA - excel

I am a noob in VBA and can't find a way to get the element of an array at a given index... It might be easy for you, though.
I have an excel file with 2 columns, "Emails" and "Categories", and I want to filter out all emails for a given category.
I ended up so far with the following code:
Sub filterEmails()
Dim tbl As ListObject
Dim emails As Variant
Dim email As String
Dim categories As Variant
Dim category As String
Dim i As Integer
Set tbl = ActiveWorkbook.Worksheets("Feuil1").ListObjects("Tableau1")
emails = tbl.ListColumns("EMAILS").DataBodyRange.Value
categories = tbl.ListColumns("SERVICES").DataBodyRange.Value
i = 1
For Each email In emails
category = ???
If category = "some service" Then
MsgBox email
End If
i = i + 1
Next email
End Sub
I tried many ways to get the ith item from the categories array, like categories(i) but didn't succeed. It might be because I wasn't able to initialize variables with the right type.

I would do it this way:
Sub filterEmails()
Dim tbl As ListObject
Dim emails As Variant
Dim email As String
Dim categories As Variant
Dim category As String
Dim i As Long '<< always best to prefer Long over Integer
Set tbl = ActiveWorkbook.Worksheets("Feuil1").ListObjects("Tableau1")
'Both "emails" and "categories" will be 2-D arrays
emails = tbl.ListColumns("EMAILS").DataBodyRange.Value
categories = tbl.ListColumns("SERVICES").DataBodyRange.Value
For i = lbound(emails,1) to ubound(emails, 1)
category = categories(i, 1)
If category = "some service" Then
MsgBox email
End If
Next i
End Sub

Here's your code, changed it a little, It should work now:
Option Explicit
Sub filterEmails()
Dim tbl As ListObject
Dim emails As Variant
Dim email As Variant
Dim categories As Variant
Dim category As String
Dim i As Integer
Set tbl = ActiveWorkbook.Worksheets("Feuil1").ListObjects("Tableau1")
emails = tbl.ListColumns("EMAILS").DataBodyRange.Value
categories = Application.Transpose(tbl.ListColumns("SERVICES").DataBodyRange.Value)
i = 1
For Each email In emails
category = categories(i)
If category = "some service" Then
MsgBox email
End If
i = i + 1
Next email
End Sub
Comments:
categories(i)
That command wont work because categories is a 2 dimension array, I store it as 1 dimensional array using Application.transpose command.

Related

How to extract the members' info of a distribution list, and save in Outlook contacts folder?

I have an Excel VBA macro (Macro A) to export the members' information (Name and Address) from Outlook contacts folder to Excel.
I am trying to retrieve the members of a distribution list, and push them into my Outlook contacts folder on a daily basis. In that case, I can use macro A to export the latest DL members found in my contacts folder.
My ultimate objective is to get the latest name and email address of the members found in a distribution list in Excel format.
I searched online for solutions that can directly export the members of Outlook distribution list to Excel, but didn't achieve my intended effect.
Sub PrintDistListDetails()
Dim olApplication As Object
Dim olNamespace As Object
Dim olContactFolder As Object
Dim olDistListItem As Object
Dim destWorksheet As Worksheet
Dim distListName As String
Dim memberCount As Long
Dim memberIndex As Long
Dim rowIndex As Long
Const olFolderContacts As Long = 10
distListName = "dl.xxxxxx" 'change the name accordingly
Set olApplication = CreateObject("Outlook.Application")
Set olNamespace = olApplication.GetNamespace("MAPI")
Set olContactFolder = olNamespace.GetDefaultFolder(olFolderContacts)
Set olDistListItem = olContactFolder.Items(distListName)
Set destWorksheet = Worksheets.Add
destWorksheet.Range("A1:B1").Value = Array("Name", "Address") 'column headers
memberCount = olDistListItem.memberCount
rowIndex = 2 'start the list at Row 2
'For memberIndex = 1 To memberCount
For memberIndex = 1 To 1
With olDistListItem.GetMember(memberIndex)
destWorksheet.Cells(rowIndex, "a").Value = .Name
destWorksheet.Cells(rowIndex, "b").Value = .Address
End With
rowIndex = rowIndex + 1
Next memberIndex
destWorksheet.Columns.AutoFit
Set olApplication = Nothing
Set olNamespace = Nothing
Set olContactFolder = Nothing
Set olDistListItem = Nothing
Set destWorksheet = Nothing
End Sub
It is only printing out the name of a distribution list, and its "parent email". For example, the output will be "dl.xxxxxx" in A2 cell, and "dl.xxxxxx#outlook.com" in B2 cell, instead of retrieving all the members in the distribution list.
How do I get the latest name and address of the members in a distribution list, and print in Excel using any of the two methods described above?
Your loop only runs once:
For memberIndex = 1 To 1
change it back to
For memberIndex = 1 To memberCount

How to create a document and then replace the values of the fields in the specific document

I have an agent which imports records from Excel to Notes. At the moment each time, it runs it creates a new document. I would like it:
The first time it runs to create the document.
The next time it will run, to replace the field values of the specific document NOT to create a new one.
How can I fix my agent which is:
Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim xlApp As Variant, xlsheet As Variant, xlwb As Variant, xlrange As Variant
Dim filename As String, currentvalue As String
Dim batchRows As Integer, batchColumns As Integer, totalColumns As Integer
Dim x As Integer, y As Integer, startrow As Integer
Dim curRow As Long, timer1 As Long, timer2 As Long
Dim DataArray, fieldNames, hasData
Dim view As NotesView
Set db = session.CurrentDatabase
Set view = db.GetView("test-forecast")
Set doc = view.GetFirstDocument
timer1=Timer
filename="C:\DM\Forecast\forecast-a.xlsx"
batchRows=2 'process 2 rows at a time
Set db=session.CurrentDatabase
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True 'set Excel program to run in foreground to see what is happening
Set xlwb=xlApp.Workbooks.Open(filename)
Set xlsheet =xlwb.Worksheets(1)
Redim fieldNames(1 To 5) As String
DataArray=xlsheet.Range("A1").Resize(batchRows, 5).Value 'get worksheet area of specified size
For y=1 To 5 'we assume max 5 columns in the sheet
currentvalue=Cstr(DataArray(1,y))
If currentvalue<>"" Then 'abort counting on empty column
fieldNames(y)=currentvalue 'collect field names from the first row
totalColumns=y
Else
y=2
End If
Next
Redim Preserve fieldNames(1 To totalColumns) As String
curRow=2
hasData=True
While hasData=True 'loop until we get to the end of Excel rows
If curRow=2 Then startrow=2 Else startrow=1
For x=startrow To batchRows
curRow=curRow+1
If Cstr(DataArray(x,1))+Cstr(DataArray(x,2))<>"" Then 'when 2 first columns are empty, we assume that it's the end of data
Print Cstr(curRow-2)
Set doc=New NotesDocument(db)
doc.Form="test-forecast"
doc.Type="test-forecast"
For y=1 To totalColumns
currentvalue=Cstr(DataArray(x,y))
Call doc.ReplaceItemValue(fieldNames(y), currentvalue)
Next
Call doc.save(True, False)
Else
hasData=False
x=batchRows
End If
Next
If hasData=True Then DataArray=xlsheet.Range("A"+Cstr(curRow)).Resize(batchRows, totalColumns).Value 'get worksheet area
Wend
timer2=Timer
Call xlApp.Quit() 'close Excel program
End Sub
Thank you in advance.
As of your comment you only have 2 rows in your excel- file: The first row contains the fieldnames, the second row contains the values.
Every import only contains one document. And you want to update this single document on every run.
There are multiple ways to get that document, the fastest is by using a view containing that document. Create a view with Selection formula: SELECT Form = "test-forecast". Give it a speaking name like (ViwLkpDocument). If you really have only one import with one document, then you can keep the default column, otherwise you might sort the first column by some sort of key to identify the matching document.
I would add a function for that so that you can change the method later if your requirments change:
Function GetDocument(db as NotesDatabase) As NotesDocument
Dim viwLkp as NotesView
Dim docTmp as NotesDocument
Set viwLkp = db.GetView( "(ViwLkpDocument)" )
Set docTmp = viwLkp.GetFirstDocument
If docTmp is Nothing then
Set docTmp = New NotesDocument( db )
docTmp.Form="test-forecast"
docTmp.Type="test-forecast"
End If
Set GetDocument = docTmp
End Function
Then change your code like that:
...
Print Cstr(curRow-2)
Set doc=GetDocument(db)
For y=1 To totalColumns
...

Trying to count the number of matching items in a table column

I am trying to determine the number of items in a column that match a specific string. I want to be able to use this number to size an array later.
I have been trying various ways to use the countif function.
Sub testMatrix()
Dim nm1 As String
Dim nm2 As String
Dim tbl As ListObject
Dim nm1Count As Double
Dim nm2Count As Integer
nm1 = "teleport 1"
nm2 = "user2"
Set tbl = ActiveSheet.ListObject("Table1")
nm1Count = Application.WorksheetFunction.CountIf(Range("Table1[username]"), nm1)
End Sub
I would like to end up with the variable nm1Count being equal to the number of times string "teleport 1" occurs in the username column of my table. So for my specific sheet it should say 4.
Currently, when it gets to the nm1Count = line it errors out and says
Object doesn't support this property or method
I dumbly forgot the s at the end of ListObjects. Here is the corrected code.
Sub testMatrix()
Dim nm1 As String
Dim nm2 As String
Dim tbl As ListObject
Dim nm1Count As Long
Dim nm2Count As Long
nm1 = "teleport 1"
nm2 = "user2"
ActiveSheet.Activate
Set tbl = ActiveSheet.ListObjects("Table1")
nm1Count = Application.WorksheetFunction.CountIf(tbl.DataBodyRange.Columns(1), nm1)
nm2Count = Application.WorksheetFunction.CountIf(tbl.DataBodyRange.Columns(1), nm2)
End Sub

How to write to excel from vba

I am trying to create a button on my Access form that takes the current entry and writes the information to an Excel doc
Public Sub ExportExcel()
Dim ObjEx As Object
Dim WhatIsThisVariableFor As Object
Dim Selec As Object
Dim Column As Integer
Dim Row As Integer
Dim CustName As String
Dim Org As String
Dim Contact As String
Dim Product As String
Dim Quantity As Integer
Dim rst As DAO.Recordset
Set ObjEx = CreateObject("EXCEL.APPLICATION")
Set WhatIsThisVariableFor = ObjEx.Workbooks.Add
'Set rst = CurrentDb.OpenRecordset("Select") <---- This will be used when I get the code working
Column = 1
Row = 1
CustName = "Test" '<---- This is only used for the test
Cells(Row, Column) = CustName
ObjEx.Visible = True
Set Selec = ObjEx.Selection
End Sub
This code creates the Excel doc, but leaves it blank. I think that the Cells(Row, Column) command isn't working because it would have to be called from within excel? I'm not sure (I am very new to VBA)
How can I write to the spreadsheet cells from within Access?
You need to qualify your Cells() function to Excel's application object.
ObjEx.ActiveSheet.Cells(Row, Column).Value = CustName
I would recommend that you also choose the worksheet object explicitly:
Dim ws As object
Set ws = ObjEx.Worksheets("Sheet1")
ws.Cells(row, column).value = CustName

Accessing Lotus Notes database from Excel VBA - how do I pick up COLUMNVALUES?

I am investigating pulling data from a Notes database directly into Excel as our Finance guy is manually re-typing figures a.t.m.
This is my code so far:
Sub notesBB()
Const DATABASE = 1247
Dim r As Integer
Dim i As Integer
Dim c As Integer
Dim db As Object
Dim view As Object
Dim Entry As Object
Dim nav As Object
Dim Session As Object 'The notes session
Dim nam As Object
Dim val As Variant
Dim v As Double
Dim items As Object
Set Session = CreateObject("Lotus.NotesSession")
Call Session.Initialize
Set nam = Session.CreateName(Session.UserName)
user = nam.Common
Set db = Session.getdatabase("MSPreston", "Billbook1415.nsf")
Set view = db.GetView("By Month\By Dept")
view.AutoUpdate = False
Set nav = view.CreateViewNav
Set Entry = nav.GetFirst
val = Entry.childcount
val = Entry.ColumnValues(6) ' this doesn't work
Set items = Entry.ColumnValues 'from a suggestion on the net
val = items(6) 'this doesn't work either
MsgBox (val)
End Sub
error is "object variable or With Block variable not set"
The annoying thing is that I can see the values I want in the ExcelVBA debug window... so I can't be far off. I guess its how to access an array of items properly
The answer is to declare a variant array and assign it directly...
Sub notesBB()
Const DATABASE = 1247
Dim r As Integer
Dim i As Integer
Dim db As Object
Dim view As Object
Dim Entry As Object
Dim nav As Object
Dim Session As Object 'The notes session
Dim nam As Object ' notes username
Dim v() As Variant ' to hold the subtotal values
Dim bills(12, 16) ' 12 months, 16 departments
r = 1
Worksheets(1).Range("A1:z99").Clear
Set Session = CreateObject("Lotus.NotesSession") 'Start a session to notes
Call Session.Initialize
Set nam = Session.CreateName(Session.UserName)
user = nam.Common
Set db = Session.getdatabase("MSPreston", "Billbook1415.nsf")
Set view = db.GetView("By Month\By Dept")
view.AutoUpdate = False
Set nav = view.CreateViewNav
Set Entry = nav.GetFirst
Do Until Entry Is Nothing
If Entry.isCategory Then
r = r + 1
v = Entry.ColumnValues
For i = 1 To 16
bills(v(0), i) = v(4 + i)
Cells(4 + r, 2 + i) = bills(v(0), i)
Next
End If
Set Entry = nav.getNextCategory(Entry)
DoEvents
Loop
End Sub
This code just extracts the 12 months (rows) by 16 departments (cols) bills values from the Notes view and populates an Excel range with them. Easy when you know (find out) how !

Resources