Putting data from Access to Excel appears to become common task in VBA programming.
Trying to make this transfer fast, reliable and universal I've come across some
interesting methods and specifics, which I want to share in hope to receive
new ideas and to help others to not repeat my mistakes.
Methods being tested:
Below the list of methods with code and comments, advantages and disadvantages:
Notice first, that these are not all the possible methods, i would gladly accept
and test any method, not included here, second - not all the methods optimized
to their best performance (I will also gladly accept any modifications on that),
and, finally, there may be more possible methods and different performances
in later versions of MS Office - I was limited by Office 97 only.
The task was to test performance of various methods of putting result of given
sql string to excel worksheet. Let's notice, that from the beginning not all
procedures are equal in that kind of testing, since some of them (for example,
OutputTo), create an xls file on disk, while other (RunCommand for example)
need that file to be saved after creation. On the other hand, first kind of
methods can't produce workbook with multiple sheets or put data in specified
place of worksheet - you need to "collect" sheets in one workbook
after putting them to disk. Also different methods vary in their sensitivity
to mistakes, possible present in recordset.
So the task formulated as to put the result of sql string with errors into single
worksheet - as soon as data is on a worksheet, task is completed.
Microsoft Access/Excel 97 SR-2 Under WinNT 4.0 on Intel Pentium IV 2200, 256MB, 30GB machine was used to do the tests. Data transferred from local table, contained 13 fields and 10000 records to Excel worksheet just creatrd.
|
|
Later, the results were averaged.
General Description:
Very fast and powerful.
Features: you have to specify x and y - top left cell, and in n and m variables
you receive the height and width of range received. Set Headers variable to
true if you need column headers.
This method is error independent - error values just ignored.
The components of this solution are ADODB recordset - used to retrieve records
values from query and put them into array, and then array is being transposed
and put to MS Excel Range.
Requirements:
Requires references to MS Excel object library (optional indeed, - just to have
the correct syntax. You can get rid of it, receiving WS as Object) and ActiveX
Data Objects Library
Advantages:
Fast, adjustable, reliable.
Disadvantages:
This method is much slowed by the necessity to transpose matrix received by
getrows. Unfortunately, getrows puts values in transposed way. If it can be
avoided some way, speed will increase much.
Code:
|
|
General Description:
Actually this is a previous version of ADO+recordset method and as such have
some drawbacks.
Features: you have to specify x and y - top left cell, and in n and m variables
you receive the height and width of range received. Set Headers variable to
true if you need column headers.
This method is error independent - error values of cell just ignored.
The components of this solution are DAO recordset - used to retrieve records
values from query and put them into array, and then array is being transposed
and put to MS Excel Range.
Requirements:
Requires references to MS Excel object library (optional indeed - just to have
the correct syntax. You can get rid of it, sending WS as Object)
Advantages:
Doesn't need references to ADO library.
On low number rows (<50) shows best performance (see graph).
In this procedure some useful modifications are made. If you transfer large
amount of data (about 30000 rows in my machine) you can run out of memory, and
even if you don't it's slower, then do it 3 times by 10000. So this one function
is checking - is there more then 10000 rows and breaks them apart if necessary.
Disadvantages:
This method is dependent on number of errors. Unlike the ADO recordset, DAO
get rows method, when meets error in any field stops working and generates no
error - the data is lost, and you know nothing about this. So, instead of rs.getrows
in this procedure used stand alone procedure GetR, which uses getrows, and in
case of errors, read the record field by field and then continues.
Code:
|
|
General Description:
Pretty fast on its range of rows count - see graph and very simple method.
Errors are ignored.
Requirements: need to have dummy query "Bolvanka" (or any name).
Advantages:
Simple, fast, error-free method.
There may also considered as advantage, that you got file on disk already
Disadvantages:
You can output one sheet in time to one file.
You can put result of query only in top left cell of the sheet
You can't output without headers.
Code:
|
|
General Description:
That seems to be fastest way of all (see graph), but there are serious disadvantages.
Requirements: need to have dummy query "Bolvanka" (or any name).
Advantages:
Fastest, simple, you get file on disk.
Disadvantages:
You can put result of query only in top left cell of the sheet
If recordset contains an error, you have pop-up prompt, which I couldn't suppress
- so it's hardly can be automated. But I think, if something will be done to
prevent errors and to collect files after outputs to one worksheet, it still
will remain fastest way, at least at some range of rows number.
Code:
|
|
General Description:
This is built into excel method to get recordset values on worksheet
Requerements: MS Excel object library
Advantages:
Simple. Can put data anywhere on the page
Disadvantages:
In excel 97 you can use only DAO recordset in this method. As I mentioned, DAO
recordset has very unpleasant bug - if there's any error, it quits and shows
nothing. So, if you want to use this method, you must check recordset for errors
either before or after output. Excel of later versions support ADO recordsets,
which are free of this bug.
Code:
|
|
General Description:
QueryTables are simple way to get data from Access to excel using Excel UI.
However they can be created programmatically from Access.
Requirements: MS Excel object library
Advantages:
It's the best method, if you have, say, template, with lots formatting and few
data.
You refresh, kill QueryTables and save as different name. Very fast in that
case.
Disadvantages:
That's not a good practice to move files with query tables from machine to machine
or send thru e-mail - if someone accidentally refreshes query tables on machine
which hasn't DSN required, he'll get an error. So if you plan to move that file,
you have to do QueryTables("name").Delete - so that the data is only
thing left. Besides, this method is slow.
Code:
Function
QTXLOut(WS As Worksheet, sql As String) |
General Description:
When developing this method, I thought it's an artifact - curious, nothing more.
However, performance it showed appeared unexpected good on low (<500) rows.
Requirements: Requires references to MS Excel object library (optional
indeed - just to have the correct syntax. You can get rid of it, sending WS
as Object) , ActiveX Data Objects Library and MSForms Object library.
Method combines ADO recordset, and MSForms Data Object. DataObject used to interact
with clipboard. We fill the clipboard with string, where values divided by chr(9)
and rows by chr(10), then paste. There are ways to speed up this procedure,
for example not using DataObject, but API. Another possible way - using not
default text format in SetText, that may allow not compose string, but put the
array to the clipboard.
Advantages:
Fast.
Disadvantages:
Needs 3 libraries, dies if data size exceeds 2 kB (windows clipboard limitation).
Code:
|
|
General Description:
One of my first experiment in that area. Worst performance of all
Requirements: dummy query
Advantages: Microsoft excel object library (Optional)
Disadvantages:
Slow and you can't do anything while it works.
Code:
Function SKXLOut(WS As Worksheet,
sql As String) |


Present article contains testing results only in their dependence on number of rows returned. However some methods are data-type dependent, other may be sensitive to memory or disk speed e.t.c. I'm going to test them in that way. Also I stay open to any additions and modifications to my "collection" and bugs report. Email me on zmey2@1977.ru
Best regards,
Zmey2.
© Andrew Semenov 2003
All rights reserved