What declarations I have to make in order to be able to use Excel objects and constants from my Access 2007 VBA script?
Dim wb As Workbook
or
Set objExcelApp = New Excel.Application
or
.Borders(xlEdgeBottom)
ms-access-2007vba
What declarations I have to make in order to be able to use Excel objects and constants from my Access 2007 VBA script?
Dim wb As Workbook
or
Set objExcelApp = New Excel.Application
or
.Borders(xlEdgeBottom)
[For the record, the official name for what once was 'Jet' is now the 'Access database engine'.]
For ACE (the Access2007 engine .accdb format) features it has to be ACEDAO.
For Jet 4.0 features it has to be ADO classic.
For Jet 3.51 features and earlier, pick either ADO or DAO. There are advantages and disadvantages to both. The vast majority of Access database engine functionality is common to both; the mutually exclusive functionality is arguable fringe. A lifestyle choice, perhaps, but no big deal. The smart coder uses the best of both :)
I've used both quite a bit and ADO is my personal preference. It is more modern than DAO, so architecturally it is an improvement: flatter object model, none of the tear down problems of DAO, etc. More properties and methods and introduces events (DAO has none) e.g. for asynchronous connection and fetching of records. ADO recordsets can be disconnected, hierarchical and fabricated, DAO recordsets cannot. Basically, they took the good things about DAO and made them better.
DAO is not without its strong points. For one, you will find more DAO code examples than ADO for Access/Jet.
P.S. for some reason, folk who like DAO really dislike ADO. Ignore the propaganda. ADO isn't deprecated. The ACE has an OLE DB provider and is currently the only way of using ACE in 64 bit. ADO.NET hasn't replaced ADO classic any more than VB.NET has replaced VBA6 in Access projects.
EDIT: just to clarify, "For Jet 4.0 features it has to be ADO classic," this is because DAO 3.6 only received a few enhancements for the features new to Jet 4.0. For example, for the DECIMAL
data type you cannot specify scale/precision. Other features are missing completely from DAO. For example, can you do the following in Jet 4.0 using DAO (or ACEDAO in ACE for that matter)?
CREATE TABLE Test (
col1 CHAR(4) WITH COMPRESSION DEFAULT '0000' NOT NULL,
CHECK (NOT EXISTS (
SELECT T1.col1
FROM Test AS T1
WHERE T1.col1 <> '0000'
GROUP
BY T1.col1
HAVING COUNT(*) > 1
))
);
(hint: compressible fixed-width text column with table-level data integrity constraint.) No, you cannot.
AFAIK the only enhancements to ACEDAO was for the new ACE functionality i.e. they didn't go back and fill in the Jet 4.0 gaps in DAO. And why should they? We still have ADO to plug the gaps. Better that the team spent their time more productively, like fixing that annoying DECIMAL
sort bug, for me the best thing about ACE ;-)
Use Dim
'd variables
Dim rng as Range
Set
the variable to the required range. There are many ways to refer to a single-cell range:
Set rng = Range("A1")
Set rng = Cells(1, 1)
Set rng = Range("NamedRange")
Or a multi-cell range:
Set rng = Range("A1:B10")
Set rng = Range("A1", "B10")
Set rng = Range(Cells(1, 1), Cells(10, 2))
Set rng = Range("AnotherNamedRange")
Set rng = Range("A1").Resize(10, 2)
You can use the shortcut to the Evaluate
method, but this is less efficient and should generally be avoided in production code.
Set rng = [A1]
Set rng = [A1:B10]
All the above examples refer to cells on the active sheet. Unless you specifically want to work only with the active sheet, it is better to Dim a Worksheet
variable too:
Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set rng = ws.Cells(1, 1)
With ws
Set rng = .Range(.Cells(1, 1), .Cells(2, 10))
End With
If you do want to work with the ActiveSheet
, for clarity it's best to be explicit. But take care, as some Worksheet
methods change the active sheet.
Set rng = ActiveSheet.Range("A1")
Again, this refers to the active workbook. Unless you specifically want to work only with the ActiveWorkbook
or ThisWorkbook
, it is better to Dim a Workbook
variable too.
Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")
If you do want to work with the ActiveWorkbook
, for clarity it's best to be explicit. But take care, as many WorkBook
methods change the active book.
Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")
You can also use the ThisWorkbook
object to refer to the book containing the running code.
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")
A common (bad) piece of code is to open a book, get some data then close again
This is bad:
Sub foo()
Dim v as Variant
Workbooks("Book1.xlsx").Sheets(1).Range("A1").Clear
Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
v = ActiveWorkbook.Sheets(1).Range("A1").Value
Workbooks("SomeAlreadyOpenBook.xlsx").Activate
ActiveWorkbook.Sheets("SomeSheet").Range("A1").Value = v
Workbooks(2).Activate
ActiveWorkbook.Close()
End Sub
And it would be better like:
Sub foo()
Dim v as Variant
Dim wb1 as Workbook
Dim wb2 as Workbook
Set wb1 = Workbooks("SomeAlreadyOpenBook.xlsx")
Set wb2 = Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
v = wb2.Sheets("SomeSheet").Range("A1").Value
wb1.Sheets("SomeOtherSheet").Range("A1").Value = v
wb2.Close()
End Sub
Pass ranges to your Sub
s and Function
s as Range variables:
Sub ClearRange(r as Range)
r.ClearContents
'....
End Sub
Sub MyMacro()
Dim rng as Range
Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:B10")
ClearRange rng
End Sub
You should also apply Methods (such as Find
and Copy
) to variables:
Dim rng1 As Range
Dim rng2 As Range
Set rng1 = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10")
Set rng2 = ThisWorkbook.Worksheets("SomeSheet").Range("B1:B10")
rng1.Copy rng2
If you are looping over a range of cells it is often better (faster) to copy the range values to a variant array first and loop over that:
Dim dat As Variant
Dim rng As Range
Dim i As Long
Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10000")
dat = rng.Value ' dat is now array (1 to 10000, 1 to 1)
for i = LBound(dat, 1) to UBound(dat, 1)
dat(i,1) = dat(i, 1) * 10 ' Or whatever operation you need to perform
next
rng.Value = dat ' put new values back on sheet
This is a small taster for what's possible.
Best Answer
I dissent from both the answers. Don't create a reference at all, but use late binding:
You will note that the only difference in the code above is that the variables are all declared as objects and you instantiate the Excel instance with CreateObject().
This code will run no matter what version of Excel is installed, while using a reference can easily cause your code to break if there's a different version of Excel installed, or if it's installed in a different location.
Also, the error handling could be added to the code above so that if the initial instantiation of the Excel instance fails (say, because Excel is not installed or not properly registered), your code can continue. With a reference set, your whole Access application will fail if Excel is not installed.