The following methods provide you with three different ways of reading a range into a collection in VBA.
Source 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
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
PublicFunctionreadRangeIntoTableCollection(ByRefrngAsRange,ByValkeyColAsInteger)AsScripting.DictionaryDimiAsLongDimjAsIntegerDimrecAsScripting.DictionaryDimdictAsNewScripting.DictionaryIfNot(rngIsNothing)ThenIfkeyCol<>0Then' Loop through all rows in a given range object.Fori=2Torng.Rows.CountSetrec=NewScripting.Dictionary' Loop through all columns in a given range object.Forj=1Torng.Columns.Count' Read one record.rec.Addrng.Cells(1,j).value,rng.Cells(i,j).valueNextj' Add one record to returned collection.dict.Addrng.Cells(i,keyCol).value,recNextiEndIfEndIfSetreadRangeIntoTableCollection=dictEndFunction' @Author - Alexander Bolte' @ChangeDate - 2014-10-09' @Description - Reading a provided Range objects values into a collection holding key value pairs.' @Param rng - a Range object holding one or more columns.' @Param keyCol - a column within provided Range holding keys.' @Param valCol - a column within provided Range holding values.' @Remarks - The index for columns starts in a provided Range, not in the worksheet.' If for example the handed Range starts in column C of a worksheet' and you need the first column of handed Range as keys, you would provide 1 and not 3 as keyCol.PublicFunctionreadRangeIntoCollection(ByRefrngAsRange,ByValkeyColAsInteger,ByValvalColAsInteger)AsScripting.DictionaryDimiAsLongDimdictAsNewScripting.DictionaryIfNot(rngIsNothing)ThenIfkeyCol<>0AndvalCol<>0ThenFori=1Torng.Rows.Countdict.Addrng.Cells(i,keyCol).value,rng.Cells(i,valCol).valueNextiEndIfEndIfSetreadRangeIntoCollection=dictEndFunction' @Author - Alexander Bolte' @ChangeDate - 2014-10-09' @Description - Reading a provided Range objects values into a collection.' @Param rng - a Range object holding one column.' @Returns a collection of type VBA.Collection holding all values' from the first column in provided Range object.PublicFunctionreadRangeIntoVbaCollection(ByRefrngAsRange)AsVBA.CollectionDimiAsLongDimdictAsNewVBA.CollectionIfNot(rngIsNothing)ThenFori=1Torng.Rows.CountIfrng.Rows(i).Hidden=FalseThendict.AddTrim(rng.Cells(i,1).value)EndIfNextiEndIfSetreadRangeIntoVbaCollection=dictEndFunction
If you have to write an ado db recordset into an Excel worksheet, you have two basic options.
Either you write a recordset object using Excel API function copyFromRecordset or you write the data implementing an own method looping through all records.
However calling the function copyFromRecordset is pretty fast compared to looping through all records, it opposes the risk of incorrectly formatted data in a target worksheet. Root cause for this is the often failing attempt of ADO to guess a data type of a column in a source worksheet based on the first few records.
You can switch some optional parameter in a connection string called IMAX in order to have ADO take all records of a field in a recordset into account before guessing a field type, but this will lead only to incredible bad performance.
On top of that ADO is still likely to fail in guessing a field type of an Excel column even, if you use IMAX.
Handling of Date values can become very annoying. Especially, if Excel always thinks it knows better than the programmer or user *sigh*! Automation is meant to help people, not mess up their work.
In order to help me at least displaying date values in the correct format I implemented a little function to get a pattern string based on a users system locale settings.
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
' @Author - Alexander Bolte' @Change Date - 2013-12-14' @Description - Determines the date format of the system the application is running on.' The Excel application is getting the date seperator and the format of date values' from the systems locale settings.' @Returns - A String holding literals for Day (dd), Month (mm) and Year (yyyy)' in the order corresponding the systems locale setting separated using the locales date separator.FunctiongetDateFormat()AsStringDimdateFormatAsStringDimdatOrderAsIntegerDimdatSeparatorAsStringOnErrorGoToerr_handler:datOrder=Application.International(xlDateOrder)datSeparator=Application.International(xlDateSeparator)IfdatOrder=0ThendateFormat="mm"&datSeparator&"dd"&datSeparator&"yyyy"ElseIfdatOrder=1ThendateFormat="dd"&datSeparator&"mm"&datSeparator&"yyyy"ElseIfdatOrder=2ThendateFormat="yyyy"&datSeparator&"mm"&datSeparator&"dd"EndIferr_handler:IfErr.Number<>0ThenErr.ClearEndIfgetDateFormat=dateFormatEndFunction