Microsoft Access is very capable of interfacing with data from other sources. It can use data from any OLEDB or ODBC data source, as well as data from FoxPro, dBASE, Paradox, Lotus, Excel, and many other sources. In this chapter, you will learn how to interface with external data sources, with the user interface, and by using code.
External data is data stored outside the current database. It can refer to data stored in another Microsoft Access database, as well as data stored in a multitude of other file formats—including ISAM, spreadsheet, ASCII, and more. This chapter focuses on accessing data sources other than ODBC and OLE DB data sources. ODBC and OLEDB data sources are discussed briefly in Chapter 20, “Developing Multiuser and Enterprise Applications.” They are covered in extensive detail in Alison Balter’s Mastering Access 2002 Enterprise Development.
Access is an excellent front-end product, which means that it provides a powerful and effective means of presenting data—even data from external sources. Data is stored in places other than Access for many reasons. Large databases, for example, can be managed more effectively on a back-end database server such as Microsoft SQL Server. Data often is stored in a FoxPro, dBASE, or Paradox file format because the data is being used by a legacy application written in one of those environments. Text data often has been downloaded from a mainframe. Regardless of the reason why data is stored in another format, it is necessary that you understand how to manipulate this external data in your VBA modules. With the capability to access data from other sources, you can create queries, forms, and reports.
When accessing external data, you have three choices. You can import the data into an Access database, access the data by linking to it from your Access database, or open a data source directly. Importing the data is the optimum route (except with ODBC data sources) but not always possible. If you can’t import external data, you should link to external files because Microsoft Access maintains a lot of information about these linked files. This optimizes performance when manipulating the external files. Sometimes a particular situation warrants accessing the data directly. You therefore should know how to work with linked files, as well as how to open and manipulate files directly.
When you import data into an Access table, a copy is made of the data and is placed in an Access table. After data is imported, it is treated like any other native Access table. In fact, neither you nor Access has any way of knowing from where the data came. As a result, imported data offers the same performance and flexibility as any other Access table.
Linking to external data is quite different from importing data. Linked data remains in its native format. By establishing a link to the external data, you can build queries, forms, and reports that present the data. After you create a link to external data, the link remains permanently established unless you explicitly remove it. The linked table appears in the database window just like any other Access table, except that its icon is different. In fact, if the data source permits multiuser access, the users of your application can modify the data as can the users of the applications written in the data source’s native database format (such as FoxPro, dBASE, or Paradox). The main difference between a linked and a native table is that you cannot modify the linked table’s structure from within Access.
Opening an external table is similar to linking to the table, except that a permanent relationship is not created. When you link to an external table, connection information is maintained from session to session. When you open a table, you create a recordset from the table, and no permanent link is established.
It is important that you understand when to import external data, when to link to external data, and when to open an external table directly. You should import external data in either of these circumstances:
You are migrating an existing system into Access.
You want to use external data to run a large volume of queries and reports, and you will not update the data. You want the added performance that native Access data provides.
When you are migrating an existing system to Access and you are ready to permanently migrate test or production data into your application, you import the tables into Access. You might also want to import external data if the data is downloaded from a mainframe into ASCII format on a regular basis, and you want to use the data for reports. Instead of attempting to link to the data and suffering the performance hits associated with such a link, you can import the data each time it is downloaded from the mainframe.
You should link to external data in any of the following circumstances:
The data is used by a legacy application requiring the native file format.
The data resides on an ODBC-compliant database server.
You will access the data on a regular basis (making it prohibitive to keep the data up-to-date if it is not linked).
Often, you won’t have the time or resources to rewrite an application written in FoxPro, Paradox, or some other language. You might be developing additional applications that will share data with the legacy application, or you might want to use the strong querying and reporting capabilities of Access instead of developing queries and reports in the native environment.
By linking to the external data, users of existing applications can continue to work with the applications and their data. Your Access applications can retrieve and modify data without concern for corrupting, or in any other way harming, the data.
If the data resides in an ODBC database such as Microsoft SQL Server, you want to reap the data-retrieval benefits provided by a database server. By linking to the ODBC data source, you can take advantage of Access’s ease of use as a front-end tool, while taking advantage of client/server technology.
Finally, if you intend to access data on a regular basis, linking to the external table instead of temporarily opening the table directly provides you with ease of use and performance benefits. After you create the link, in most cases, Access treats the table just like any other Access table.
You should open an external table directly in either of these circumstances:
You rarely need to establish a connection to the external data source.
You have determined that performance actually improves by opening the data source directly.
If you rarely need to access the external data, it might be appropriate to open it directly. Links increase the size of your MDB file. This size increase is not necessary if you rarely will access the data. Furthermore, in certain situations, when accessing ISAM (indexed sequential access method) data, you might find that opening the table directly provides better performance than linking to it.
Although this chapter covers the process of importing external data, this is essentially a one-time process and doesn’t require a lot of discussion. It is important to note, however, that after data is imported into an Access table, it no longer is accessed by the application in its native format. The majority of this chapter focuses on linking to or directly opening external data tables.
Microsoft Access enables you to import, link to, and open files in these formats:
Microsoft Jet databases (including previous versions of Jet)
Access projects (ADP and ADE files)
ODBC databases
HTML documents
XML documents (import and open only)
dBASE III, dBASE IV, and dBASE 5.0
Paradox 3.x, 4.x, and 5.x
Microsoft Excel spreadsheets, versions 3.0, 4.0, 5.0, and 8.0
Lotus WKS, WK1, WK3, and WK4 spreadsheets (import and open only)
ASCII text files stored in a tabular format
The process of importing external data is quite simple. You can import external data by using the user interface or by using VBA code. If you are planning to import the data only once or twice, you should use the user interface. If you are importing data on a regular basis (for example, from a downloaded mainframe file), you should write code that accomplishes the task transparently to the user.
To import an external data file using the user interface, follow these steps:
Right-click anywhere within the database window.
Choose Import (or choose File|Get External Data|Import). The Import dialog box appears, as shown in Figure 19.1.
From the Files of Type drop-down list, select the type of file you are importing.
Select the file you want to import and click Import.
Depending on the type of file you select, the import process finishes, or you see additional dialog boxes. If you select Excel Spreadsheet, for example, the Import Spreadsheet Wizard appears, as shown in Figure 19.2. This wizard walks you through the process of importing spreadsheet data.
The DoCmd
object has three methods that assist you with importing external data. They are TransferDatabase
, TransferText
, and TransferSpreadsheet
, each of which is covered in this section.
You use the TransferDatabase
method of the DoCmd
object to import data from a database such as FoxPro, dBASE, Paradox, or another Access database. Listing 19.1, included in basImport
, shows an example that uses the TransferDatabase
method.
This code and all the code in this chapter are located in the CHAP19EX.MDB file on the sample code CD-ROM.
Table 19.1 lists the arguments for the TransferDatabase
method.
Table 19.1. TransferDatabase
Arguments
Argument | Specifies |
---|---|
| Type of transfer being performed. |
| Type of database being imported. |
| Name of the database. If the table is a separate file (as is the case with dBASE, Paradox, and earlier versions of FoxPro), the database name is the name of the directory that contains the table file. Do not include a backslash after the name of the directory. |
| Type of object you want to import. This argument is ignored for all but Access objects. |
| Name of the object you are importing. Do not include the file extension. |
| Name of the imported object. |
| Whether you want the structure of the table only or the structure and data. |
| Whether you want to save the login ID and password for an ODBC database in the connection string for linked tables. |
You use the TransferText
method of the DoCmd
object to import text from a text file. Listing 19.2 shows an example of this method.
Table 19.2 lists the arguments for the TransferText
method.
Table 19.2. TransferText
Arguments
Argument | Specifies |
---|---|
| Type of transfer you want to make. |
| Name for the set of options that determines how the file is imported. |
| Name of the Access table that will receive the imported data. |
| Name of the text file to import from. |
| Name of the table or list in the HTML file that you want to import or link to |
| A long integer used to indicate the character set of the code page |
| Whether the first row of the text file contains field headings. |
You use the TransferSpreadsheet
method of the DoCmd
object to import data from a spreadsheet file. Listing 19.3 shows an example that uses the TransferSpreadsheet
method.
Table 19.3 lists the arguments for the TransferSpreadsheet
method.
Table 19.3. TransferSpreadsheet
Arguments
Argument | Specifies |
---|---|
| Type of transfer you want to make. |
| Type of spreadsheet to import from. The default is Excel 3.0. |
| Name of the Access table that will receive the imported data. |
| Name of the spreadsheet file to import from. |
| Whether the first row of the spreadsheet contains field headings. |
| Range of cells to import. |
If you need to keep the data in its original format but want to treat the data just like any other Access table, linking is the best solution. All the information required to establish and maintain the connection to the remote data source is stored within the linked table definition. You can create links through the user interface and by using code. This section covers both alternatives.
One of the most common types of links is a link to another Access table. This type of link is created so that the application objects (queries, forms, reports, macros, and modules) can be placed in a local database and the tables can be stored in another database on a file server. Numerous benefits are associated with such a configuration. Chapter 20 discusses these benefits in more detail.
It is very common to create a link using the user interface. If you know what links you want to establish at design time, this is probably the easiest way to establish links to external data. You can establish links using the Database Splitter or by establishing them manually.
The Database Splitter was designed to split databases that already have been built with the tables and other database objects all in one physical MDB database file. It automates the process of moving the data tables to another database. The Database Splitter is covered in detail in Chapter 20.
To create a link to an Access table, follow these steps:
Right-click anywhere within the Database window.
Choose Link Tables. The Link dialog box appears, as shown in Figure 19.3.
Select the name of the database containing the table to which you want to link.
Click the Link button. The Link Tables dialog box appears, as shown in Figure 19.4.
Click OK. The link process finishes. Notice the arrows in Figure 19.5, which indicate that the tblCustomer, tblOrders, and tblOrderDetails tables are linked tables instead of tables stored in the current database.
The process of creating links to other types of database files is a little different. It works like this:
Right-click anywhere within the Database window.
Choose Link Tables. The Link dialog box appears.
In the Files of Type drop-down list, select the type of table to which you are linking.
Select the external file containing the data to which you will be linking.
Click the Link button. The next dialog box varies, depending on the type of table to which you want to link. With a dBASE file, for example, the Select Index Files dialog box appears, as shown in Figure 19.6. It is important that you select any index files associated with the data file. These indexes are updated automatically by Access as you add, change, and delete table data from within Access.
You receive a message indicating that the index was added successfully and that you can add other indexes if you choose. Click OK.
Add any additional indexes and click Close.
The Select Unique Record Identifier dialog box appears, as shown in Figure 19.7 (see Note below if the dialog doesn’t appear). This dialog box enables you to select a unique identifier for each record in the table. Select a unique field and click OK.
You must install the Jet 4.0 Service Pack 5 or have the BDE (Borland Database Engine) for the Select Unique Record Identifier dialog box to appear. If you do not have one of these tools, the data in the database cannot be edited. For more information, see the Microsoft knowledge base article Q283294.
Notice the icon indicating the type of file you linked to, as shown in Figure 19.8.
Creating a link to an external table using code is a six-step process. Here are the steps involved in establishing the link:
Create a reference to the Microsoft ADO Extension 2.6 for DDL and Security (ADOX) library.
Create a Catalog
object.
Set the Connection property of the Catalog
object to the database that will contain the linked table.
Create a new Table
object.
Set properties of the Table
object.
Append the Table
object to the Catalog
.
Listing 19.4 shows the code for linking to an external table, which, in this case, exists in another Microsoft Access database.
Example 19.4. Linking to an External Table
Sub LinkToAccessTableProps() Dim cat As ADOX.Catalog Dim tbl As ADOX.Table 'Instantiate a Catalog Object Set cat = New ADOX.Catalog 'Set the connection of the Catalog object 'to the connection associated with the current 'project cat.ActiveConnection = CurrentProject.Connection 'Instantiate a table object Set tbl = New ADOX.Table 'Establish the name of the new table object tbl.Name = "tblLinkedTable" 'Point the catalog of the new table at the 'catalog object established above Set tbl.ParentCatalog = cat 'Set necessary properties of the new table object tbl.Properties("Jet OLEDB:Create Link") = True tbl.Properties("Jet OLEDB:Link Datasource") = _ CurrentProject.Path & "Chap19Data.mdb" tbl.Properties("Jet OLEDB:Link Provider String") = ";pwd=password" tbl.Properties("Jet OLEDB:Remote Table Name") = "tblClients" 'Append the new table object to the tables collection 'of the catalog object cat.Tables.Append tbl End Sub
In Listing 19.4, a Catalog
object is created. The ActiveConnection property of the Catalog
object is pointed at the connection associated with the current database. Next, a Table
object is created. The Name property of the Table
object is set equal to tblLinkedTable
. The ParentCatalog property of the Table
object is set to point at the Catalog
object. Four properties in the properties collection of the Table
object are set to the appropriate values, and the Table
object is appended to the Catalog
object. This process is discussed in further detail in the following sections.
When you link to an external table, you must provide information about the type, name, and location of the external database. This is accomplished by setting the following properties in the Properties collection of the Table object:
Jet OLEDB:Link Provider String
Jet OLEDB:Remote Table Name
Jet OLEDB:Link Datasource
The following three lines of code illustrate the process of setting the provider string, name, and location of the source table:
tbl.Properties("Jet OLEDB:Link Provider String") = ";pwd=password" tbl.Properties("Jet OLEDB:Remote Table Name") = "tblClients" tbl.Properties("Jet OLEDB:Link Datasource") = CurrentProject.Path & "Chap19Data.mdb"
The Jet OLEDB:Link Provider is the ISAM format that will be used for the link. Each source database type is a different folder in the Windows registry. The folders are located in the HKEY_LOCAL_MACHINESOFTWAREMicrosoftJet4.0ISAM Formats section of the registry. Valid source database types are as follows:
dBASE | dBASE III, dBASE IV, and dBASE 5.0 |
Excel | Excel 3.0, Excel 4.0, Excel 5.0, and Excel 8.0 |
HTML | HTML Export and HTML Import |
Jet | Jet 2.x, Jet 3.x |
Lotus | Lotus WK1, Lotus WK3, Lotus WK4, Lotus WJ2, and Lotus WJ3 |
Exchange | Exchange 4.0 |
Outlook | Outlook 9.0 |
Paradox | Paradox 3.x, Paradox 4.x, Paradox 5.x, and Paradox 7.x |
Text | N/A |
The Jet OLEDB:Link Datasource must include a fully qualified path to the file. You can specify the path with a drive letter and directory path or by using universal naming conventions (UNCs). For a local database, you must specify the path like this:
tbl.Properties("Jet OLEDB:Link Datasource") = "c:DatabasesChap19Data"
For a file server, you can specify the UNC path or the drive letter path. The UNC path looks like this:
tbl.Properties("Jet OLEDB:Link Datasource") = _ "\FILESERVERNAMEDatabasesChap19Data"
In this case, the database called Chap19Data is stored on the databases share of a particular file server.
Listing 19.5 shows how you put all the connection information together to establish a link to an external table.
Example 19.5. Establishing a Link to an External Table
Sub LinkToDBase(strDirName As String, strTableName As String, _ strAccessTable) Dim cat As ADOX.Catalog Dim tbl As ADOX.Table 'Instantiate a Catalog object Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection 'Instantiate a Table object Set tbl = New ADOX.Table tbl.Name = strAccessTable Set tbl.ParentCatalog = cat 'Set necessary properties of the new Table object tbl.Properties("Jet OLEDB:Create Link") = True tbl.Properties("Jet OLEDB:Link Datasource") = strDirName tbl.Properties("Jet OLEDB:Link Provider String") = & _ "dBASE III;HDR=NO;IMEX=2;" tbl.Properties("Jet OLEDB:Remote Table Name") = strTableName 'Append the new table object to the tables collection 'of the catalog object cat.Tables.Append tbl End Sub
Here is an example of how this subroutine is called:
Call LinkToDBase("c:customerdata","customer","tblCustomers")
The LinkToDBase
subroutine receives three parameters:
The name of the directory in which the dBASE file is stored.
The name of the file (the name of the table, without the DBF extension) to which you want to connect.
The name of the Access table that you are creating.
The subroutine creates two object variables: a Catalog
object variable and a Table
object variable. It points the ActiveConnection property of the Catalog
object variable at the connection associated with the current database. Next, it establishes properties of the Table
object. The Link Datasource is the name of the directory within which the dBASE file is stored. The Link Provider String specifies that the type of table you are linking to is a dBASE III file. The Remote Table Name is the name of the dBASE file that you are linking to. After setting these properties, you are ready to append the table definition to the database.
You have seen how you can link to a dBASE table. Listing 19.6 puts together everything you have learned thus far in this chapter by creating a link to an Access table stored in another database.
Example 19.6. Creating a Link to an Access Table Stored in Another Database
Sub LinkToAccess(strDBName As String, strTableName As String, _ strAccessTable) Dim cat As ADOX.Catalog Dim tbl As ADOX.Table 'Instantiate a Catalog object Set cat = New ADOX.Catalog 'Set the ActiveConnection property of the Catalog object 'to the connection associated with the current project cat.ActiveConnection = CurrentProject.Connection 'Instantiate a Table object Set tbl = New ADOX.Table 'Set the Name property of the Table object to the name 'you wish to give to the linked table tbl.Name = strAccessTable 'Set the ParentCatalog property of the Table object 'to the Catalog object Set tbl.ParentCatalog = cat 'Set all necessary properties of the Table object tbl.Properties("Jet OLEDB:Create Link") = True tbl.Properties("Jet OLEDB:Link Datasource") = strDBName tbl.Properties("Jet OLEDB:Link Provider String") = ";pwd=password" tbl.Properties("Jet OLEDB:Remote Table Name") = strTableName 'Append the Table object to the Tables collection 'associated with the CatalogObject cat.Tables.Append tbl End Sub
Notice that the Jet OLEDB Link Provider string no longer specifies the type of database to which you are connecting. Everything else in this routine is the same as the routine that connected to dBASE. Also, notice the parameters passed to this routine:
Call LinkToAccess("C:databases orthwind.mdb","Customers","tblCustomers")
The database passed to the routine is an actual Access database (as opposed to a directory), and the table name is the name of the Access table in the other database (instead of the DBF filename).
There are times when you will want to open—rather than link to—an external table. Linking provides ease of use when dealing with external tables. After you link to a table, it is treated just like any other Access table. The disadvantage of linking is that it uses ODBC. ODBC is not the most efficient means of interacting with a database for which you have a native OLEDB provider. Therefore, you might want to programmatically open an external table without creating a link to it. Opening an external table is a two-step process:
Establish a connection to the external data source.
Point a Recordset
object at the result of executing a SQL statement against the Connection
object.
The connection information you provide when you open an external table is similar to the information you provide when you link to the table. The connection information is provided as the ConnectionString
argument of the Open
method of the Connection
object. Here’s an example:
cnn.Open "Providersqlodedb;" & _ "Data Source=(local);" & _ _ "Initial Catalog=Pubs;" & _ "User ID=sa;Password=;"
Here, the connection string is to the SQL Server database called Pubs on the local machine.
The Recordset
object is pointed at the result of executing a Select
statement against the Connection
object:
Set rst = cnn.EXEcute("Select * from Authors")
Listing 19.7 shows what the entire process looks like in code.
Example 19.7. Using the OpenDatabase
Method
Sub OpenExternalSQL(strDBName As String, strTableName As String) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset 'Instantiate Connection and Recordset objects Set cnn = New ADODB.Connection Set rst = New ADODB.Recordset 'Use the Open method of the Connection object to establish 'a connection to the SQL Server database cnn.Open "Provider=sqloledb;" & _ "Data Source=(local);" & _ "Initial Catalog=" & strDBName & ";" & _ "User Id=sa;Password=; " 'Use the Execute method of the Connection object to execute 'a Select statement and return the result as a Recordset Set rst = cnn.Execute("Select * from " & strTableName) 'Loop through the resulting recordset, 'printing the value of the first field Do Until rst.EOF Debug.Print rst.Fields(0).Value rst.MoveNext Loop 'Close the Connection cnn.Close End Sub
Listing 19.7 is called with this code:
Call OpenExternalSQL("Pubs","authors")
Notice that you are not appending a table definition here. Instead, you are creating a temporary recordset that refers to the external data. After the external table is opened as a recordset, the code traverses through each record of the table, printing the value of the first field. Of course, after the recordset is opened, you can manipulate it in any way you want. The table does not show up as a linked table in the database window. In fact, when the routine completes and the local variable goes out of scope, the recordset no longer exists.
Now that you have seen how you can link to external tables as well as open them, you are ready to take a look at how you can refine both these processes. This involves learning the Windows registry settings that affect the linking process, learning more about the parameters that are available to you when specifying connection information, learning how to specify passwords, learning how to refresh and remove links, and learning how to create an external table using VBA code.
Each ISAM driver has a separate key in the Windows registry. These keys are located in the appropriate ISAM driver in the HKEY_LOCAL_MACHINESOFTWAREMicrosoftJet4.0ISAM Formats section of the registry. These keys are used to configure the driver after initialization. As you can see in Figure 19.9, the setup program has created keys for several data sources. If you look at a specific data source (in this case, dBASE III), you can see all the settings that exist for the dBASE driver. The IndexFilter
is set to dBASE Index(*.ndx)
, for example. At times, you will need to modify one of the registry settings to customize the behavior of the ISAM driver; this is covered later in this chapter in the section “Looking at Special Considerations.”
The Jet OLEDB:Link Provider String is used when linking to external tables. It includes the source database type, user ID, and password. A semicolon must be used to separate each part of the connection string.
Each source database type has a valid name. This is the name that must be used when accessing that type of data. These database types are found in the Windows registry under HKEY_LOCAL_MACHINESoftwareMicrosoftJet4.0ISAM Formats. You must accurately specify the source database type, or you will be unable to access the external data.
The user ID is used whenever a username must be specified in order to successfully log on to the data source. This is most common when dealing with back-end databases such as Oracle, Sybase, or Microsoft SQL Server. This part of the provider string can be required to log on the user to the system where the source data resides. The UID
keyword refers to the user ID.
As with the user ID, the password most often is included when dealing with back-end data. It also can be used on other database types that support passwords, such as Paradox, or when linking to an external Access table. The PWD
keyword is used when specifying the password.
Finally, the dataset name refers to a defined ODBC data source. The DSN
keyword refers to the dataset name in the connection string. The following is an example of a Jet OLEDB Link Provider String:
tbl.Properties("Jet OLEDB:Link Provider String") = "ODBC" & _ ";DATABASE=Pubs" & _ ";UID=Alison" & _ ";PWD=MyPass" & _ ";DSN=PublisherData"
In the example, the SQL Server database being accessed is Pubs
, the user ID is Alison
, the Password is MyPass
, and the data source name is PublisherData
.
In working with passwords, you probably won’t want to hard-code the password into your application because that defeats the purpose of placing a password on your database. In Listing 19.8, the database’s password is included in the code, allowing the link to be made to the secured table without any password validation.
Example 19.8. Embedding a Database Password in Code
Sub LinkToSecured() Dim cat As ADOX.Catalog Dim tbl As ADOX.Table 'Instantiate a Catalog object Set cat = New ADOX.Catalog 'Set the ActiveConnection property of the Catalog 'object to the connection associated with the 'current project cat.ActiveConnection = CurrentProject.Connection 'Instantiate a Table object Set tbl = New ADOX.Table 'Set the Name property of the Table object tbl.Name = "tblLinkedTable" 'Associate the ParentCatalog of the Table object 'with the Catalog object Set tbl.ParentCatalog = cat 'Set properties of the Table object tbl.Properties("Jet OLEDB:Create Link") = True tbl.Properties("Jet OLEDB:Link Provider String") = "ODBC" & _ ";DATABASE=Pubs" & _ ";UID=SA" & _ ";PWD=" & _ ";DSN=PublisherData" tbl.Properties("Jet OLEDB:Remote Table Name") = "Authors" 'Append the Table object to the Tables collection 'associated with the Catalog object cat.Tables.Append tbl End Sub
An invalid password results in a message appearing, requiring the user to log on. Unless you are using integrated Windows NT security to log on to your database server, it is best to require the user to supply the password at runtime. In Listing 19.9, the code prompts the user for a password. The password entered by the user is used as part of the connection string.
Example 19.9. Requiring Password Validation
Sub ReallySecure() Dim cat As ADOX.Catalog Dim tbl As ADOX.Table Dim strPassword As String 'Instantiate a Catalog object Set cat = New ADOX.Catalog 'Set the ActiveConnection property of the Catalog 'object to the connection associated with the 'current project cat.ActiveConnection = CurrentProject.Connection Set tbl = New ADOX.Table 'Set the Name property of the Table object tbl.Name = "tblLinkedTable" 'Associate the ParentCatalog of the Table object 'with the Catalog object Set tbl.ParentCatalog = cat 'Prompt the user for the password strPassword = InputBox("Please Enter Your Password", "Database" & _ "Security!!!") 'Set properties of the Table object tbl.Properties("Jet OLEDB:Create Link") = True tbl.Properties("Jet OLEDB:Link Provider String") = "ODBC" & _ ";DATABASE=Pubs" & _ ";UID=SA" & _ ";PWD=" & strPassword & _ ";DSN=PublisherData" tbl.Properties("Jet OLEDB:Remote Table Name") = "Authors" 'Append the Table object to the Tables collection 'associated with the Catalog object cat.Tables.Append tbl End Sub
Notice that the password is retrieved from the user and stored in a variable called strPassword
. This strPassword
variable is included in the connection string at runtime.
Refreshing links refers to updating the link to an external table. It is done when the location of an external table has changed. Removing links refers to permanently removing a link to an external table.
Access cannot find external tables if their locations have moved. You need to adjust for this in your VBA code. Furthermore, there might be times when you want to remove a link to external data—when it is no longer necessary to use the data, or when the data has been imported permanently into Access.
To refresh a link using VBA code, simply redefine the Jet OLEDB:Link Datasource. Listing 19.10 shows the code to refresh a link.
You can modify this routine to prompt the user for the directory containing the data tables, as Listing 19.11 shows.
Example 19.11. Prompting the User for the Database Path and Name
Sub RefreshLink() 'Initiate error handling On Error GoTo RefreshLink_Err Dim cat As ADOX.Catalog Dim tdf As ADOX.Table Dim strNewLocation As String Dim strTemp As String 'Instantiate a Catalog object Set cat = New ADOX.Catalog 'Set the ActiveConnection property of the Catalog 'object to the connection associated with the 'current project Set cat.ActiveConnection = CurrentProject.Connection 'Point the TableeDef object at the tblClients table Set tdf = cat.Tables("tblClients") 'Attempt to retrieve the Name property of the table strTemp = tdf.Columns(0).Name 'Exit the routine if all goes well Exit Sub RefreshLink_Err: 'If an error occurs, prompt the user for the new name 'and location strNewLocation = InputBox("Please Enter Database Path and Name") 'Set the properties of the TableDef object to the 'information provided by the user tdf.Properties("Jet OLEDB:Link Datasource") = _ strNewLocation Set cat.ActiveConnection = CurrentProject.Connection Set tdf = cat.Tables("tblClients") 'Try to grab the name property again Resume End Sub
This routine points a Table
object to the tblClients table. It then attempts to access the name of the first column in the table. If an error occurs, an input box prompts the user for the new location of the database. The Jet OLEDB:Link Datasource property for the database is modified to incorporate the new location. The code then resumes on the offending line of code. You should modify this routine to give the user a way out. Resume
throws the user into an endless loop if the database is not available. An enhanced routine (see Listing 19.13) is presented later in the “Practical Examples” section of this chapter.
To remove a link using VBA code, simply execute a Delete
method of the Tables collection of a Catalog
object connected to the database, as shown in Listing 19.12.
When dealing with different types of external files, various problems and issues arise. If you understand these stumbling blocks before they affect you, you will get a great head start in dealing with these potential obstacles.
The major concerns you will have when dealing with dBASE files surround deleted records, indexes, data types, and memo fields. When you delete a record from a dBASE table, it is not actually removed from the table. Instead, it is just marked for deletion. You must Pack the database (a process in a dBASE table that removes deleted rows) must be completed in order for the records to actually be removed from the table. If records are deleted from a dBASE table using an Access application, the records are not removed. Because you cannot pack a dBASE database from within an Access application, the records still remain in the table. In fact, they are not automatically filtered from the Access table. In order to filter deleted records so that they cannot be seen within the Access application, the Deleted
value in the HKEY_LOCAL_MACHINESOFTWAREMicrosoftJet4.0EnginesXbase section of the registry must be set to 01
(True).
Access can use the dBASE indexes to improve performance (Jet 4.0 Service Pack 5 the Borland Database Engine must be installed). After you link to a dBASE table and select an index, an INF file is created. This file has the same name as your dBASE database with an INF extension. It contains information about all the indexes being used. Here’s an example of an INF:
[dBASE III] NDX1=CUSTID.NDX UNDX1=CUSTID.NDX
dBASE III
is the database type identifier. NDX1
is an index number for the first index. The UNDX1
entry specifies a unique index.
The data types available in dBASE files are different from those available in Access files. It is important to understand how the field types are mapped. Table 19.4 shows how each dBASE data type is mapped to a Jet data type.
Finally, make sure that the dBASE memo files are stored in the same directory as the table. Otherwise, Access is unable to read the data in the memo file.
When linking to an ASCII text file, Jet can determine the format of the file directly, or it can use a schema information file, which resides in the same directory as the text file. It always is named SCHEMA.INI, and it contains information about the format of the file, the column names, and the data types. The schema information file is optional for delimited files, but it is required for fixed length files. It is important to understand that ASCII files can never be opened for shared use.
Unfortunately, working with external data is not always a smooth process. Many things can go wrong, including connection problems and a lack of temporary disk space.
Difficulties with accessing external data can be caused by any of the following circumstances:
The server on which the external data is stored is down.
The user does not have rights to the directory in which the external data is stored.
The user does not have rights to the external data source.
The external data source was moved.
The UNC path or network share name was modified.
The installable ISAM driver has not been installed.
Access requires a significant amount of disk space in order to run complex queries on large tables. This disk space is required whether the tables are linked tables stored remotely in another format, or they reside on the local machine. The application behaves unpredictably if not enough disk space is available to run the query. It therefore is necessary to make sure that all users have enough disk space to meet the requirements of the queries that are run.
Because your application has to go through an extra translation layer, the installable ISAM, performance is not nearly as good with ISAM files as it is with native Jet data. It always is best to import ISAM data whenever possible. If it is not possible to import the data, you need to accept the performance that linking offers or consider linking the best solution to an otherwise unsolvable problem.
Access 2002 enables you to import, export, and link to HTML documents. Although working with HTML documents is similar to working with other files types, HTML documents deserve special mention. To import an HTML document, follow these steps:
Right-click anywhere within the Database window and choose Import.
From the Files of Type drop-down list, select HTML Documents.
Select the document you want to import and click Import. The Import HTML Wizard appears, as shown in Figure 19.10.
The first step of the wizard attempts to parse the HTML document into fields. You can accept what the wizard has done or click Advanced. The Import Specification dialog box that appears enables you to designate field names, data types, and indexes for each field; and to select any fields you want to eliminate from the imported file. (See Figure 19.11.) This dialog box also enables you to modify the date order, date delimiter, and more.
After you make any required changes to the import specifications, click OK to return to the Import HTML Wizard. Click Next to advance to the next step of the wizard, which enables you to select whether the imported data is stored in a new table or in an existing table. Make your selection and then click Next.
Designate a field name, data type, and index for each field, as shown in Figure 19.12. Make any desired changes here and click Next.
The fourth step of the wizard enables you to indicate that you want Access to add a primary key to the table, that you want to select your own primary key, or that you don’t want the imported table to have a primary key. Make your selection and click Next.
The final step of the wizard enables you to assign a name to the table. You even can have the wizard analyze the table after importing it. Click Finish after you make your selection.
Not only can you import an HTML document, but you also can link to one. To link to an HTML document, follow these steps:
Right-click anywhere within the Database window and choose Link Tables.
From the Files of Type drop-down list, select HTML Documents.
Select the table you want to link to and click Link. The Link HTML Wizard appears.
Click the Advanced button to modify any link specifications and return to the first step of the wizard. Click Next to move to the second step of the wizard.
Specify information about each field you are linking to. Make any required changes and click Next.
Supply a name for the linked table and click Finish.
Whereas an imported HTML document acts like any other Access table, the data in a linked HTML document cannot be modified from within Access. You can use the linked document to create queries, reports, and forms.
Begin by using the Database Splitter (covered in Chapter 20, “Developing Multiuser and Enterprise Applications”) to separate the tables from the rest of the database objects. The CHAP19EX.MDB and CHAP19DATA.MDB files are included on the sample code CD-ROM. The CHAP19DATA.MDB file contains all the tables, and CHAP19EX.MDB contains the rest of the database objects.
If you distribute your application and all users did not have the same path to the CHAP19DATA.MDB file, the application would not load successfully. The LinkTables
routine, located in the Switchboard startup form, ensures that the tables are successfully linked, as Listing 19.13 shows.
Example 19.13. Loading the Application and Checking Table Attachments
Sub LinkTables() Dim objFileDialog As FileDialog On Error GoTo LinkTables_Err: DoCmd.Hourglass True 'Determine if links are ok If Not VerifyLink Then 'If not ok, attempt to relink with expected file name If Not ReLink(CurrentProject.FullName, True) Then 'If still not ok, ask user to locate file Set objFileDialog = FileDialog(msoFileDialogOpen) With objFileDialog .AllowMultiSelect = False .Show End With 'Attempt to link to file that user selected If Not ReLink(objFileDialog.SelectedItems(1), False) Then 'If not successful, display a message a quit app MsgBox "You Cannot Run This App Without " & _ "Locating Data Tables" DoCmd.Close acForm, "frmSplash" DoCmd.Quit End If End If End If DoCmd.Hourglass False Exit Sub LinkTables_Err: DoCmd.Hourglass False MsgBox "Error # " & Err.Number & ": " & Err.Description Exit Sub End Sub
Notice that the VerifyLink
routine is called from the LinkTables routine. The VerifyLink
routine appears in Listing 19.14.
Example 19.14. The VerifyLink
Routine Tests to See Whether Any Table Links Are Broken
Function VerifyLink() As Boolean 'Verify connection information in linked tables. 'Declare Required Variables Dim cat As ADOX.Catalog Dim tdf As ADOX.Table Dim strTemp As String 'Point Database object variable at the current database Set cat = New ADOX.Catalog With cat Set .ActiveConnection = CurrentProject.Connection 'Continue if links are broken. On Error Resume Next 'Open one linked table to see if connection 'information is correct. For Each tdf In .Tables If tdf.Type = "LINK" Then strTemp = tdf.Columns(0).Name If Err.Number Then Exit For End If End If Next tdf End With VerifyLink = (Err.Number = 0) End Function
The routine begins by pointing the ActiveConnection property of the Catalog
object to the connection associated with the current database. It then loops through each table in the Tables collection of the Catalog
object. If the table is a linked table, it attempts to access the name of the first column in the table. If any of the links are broken, an error occurs, and the For...Each
loop is exited. If no error occurs, the function returns True
; otherwise, the function returns False
.
If the VerifyLink
routine returns False
, the ReLink
routine is called. Listing 19.15 shows the ReLink
routine.
Example 19.15. The ReLink
Routine Attempts to Re-establish the Broken Links
Function ReLink(strDir As String, DefaultData As Boolean) _ As Boolean ' Relink a broken linked Access table. Dim cat As ADOX.Catalog Dim tdfRelink As ADOX.Table Dim oDBInfo As DBInfo Dim strPath As String Dim strName As String Dim intCounter As Integer Dim vntStatus As Variant 'Prepare status bar vntStatus = SysCmd(acSysCmdSetStatus, "Updating Links") Set cat = New ADOX.Catalog 'Instantiate database information class Set oDBInfo = New DBInfo With cat .ActiveConnection = CurrentProject.Connection 'Extract the name and path from the passed database oDBInfo.FullName = strDir strPath = oDBInfo.FilePathOnly strName = Left(oDBInfo.FileName, InStr(oDBInfo.FileName, ".") - 1) On Error Resume Next 'Update progress meter Call SysCmd(acSysCmdInitMeter, "Linking Data Tables", .Tables.Count) 'Loop through each table, attempting to update the link For Each tdfRelink In .Tables intCounter = intCounter + 1 Call SysCmd(acSysCmdUpdateMeter, intCounter) If .Tables(tdfRelink.Name).Type = "LINK" And _ Left(tdfRelink.Name, 3) = "tbl" Then tdfRelink.Properties("Jet OLEDB:Link Datasource") = _ strPath & strName & IIf(DefaultData, "Data.Mdb", ".mdb") End If If Err.Number Then Exit For End If Next tdfRelink End With 'Reset the progress meter Call SysCmd(acSysCmdRemoveMeter) vntStatus = SysCmd(acSysCmdClearStatus) ReLink = (Err = 0) End Function
The ReLink
function receives two parameters. The first parameter is the name of the database the function will attempt to link to. The second parameter is a Boolean variable that designates whether the database is considered the default database.
The function begins by modifying the status bar. It then creates a Catalog
object and an instance of a custom class called DBInfo
. This custom class is covered in further detail in Chapter 32, “Distributing Your Application.” Class modules are covered in Chapter 13, “Exploiting the Power of Class Modules.” The ActiveConnection property of the catalog object is set equal to the Connection property of the current project. Next, the FullName property of the DBInfo
class is set equal to the name of the file that is passed as a parameter to the function. The DBInfo
class extracts the path and the filename from the full filename. Just as with the VerifyLink
function, the ReLink
function uses a For...Next
loop to loop through all the tables in the database. As it loops through each table, it attempts to establish a link to a database with the name passed as parameter to the ReLink
function.
This ReLink
function is called twice from the LinkTables
routine, shown in Listing 19.13. The first time it is passed, the FullName property of the CurrentProject
object and the boolean is True
, indicating that it will try to locate the table in a database with the same location as the application database. If that attempt is not successful, the LinkTables
routine uses the FileDialog object to display the File Open dialog, allowing the user to attempt to locate the database. The ReLink
function is called again, searching for the table in the database selected by the user. If it is still unsuccessful, the routine quits the application.
The capability to link to external data is one of Access 2002’s strongest attributes. It is important that you understand how to link to external data via the user interface and by using VBA code. This chapter taught you how to link to external tables, open external data sources directly, refresh and remove links, and create external tables using VBA code. Many of the techniques covered in this chapter are covered extensively in Alison Balter’s Mastering Access 2002 Enterprise Development.
3.22.61.187