Connecting to a Server

To access data on a remote server, your application must establish a connection. This connection creates a communication link to the server across the network. You can use any of the following methods to connect to a server:

This section describes each of these methods, as well as their respective time and memory requirements on both the client and the server.

Linking Tables and SQL Views from a Server

The easiest and most common way to access data on a server is to link tables from the server. With few exceptions, you can use linked tables in your application just as you would Microsoft Access tables. Microsoft Access automatically connects to the server when you open a linked table.

If your server supports SQL views, you can link them to your local database. An SQL view is a virtual table that is derived from other tables or previously defined views. It has a name, a list of attributes, and a query which define the contents of the view. Microsoft Access treats a linked view exactly like a linked table without indexes. The processing defined in a view is always performed by the server.

Û To link a table or an SQL view from a server

In your Visual Basic code, create an ODBC connection string that references the data source you set up with the ODBC Data Source Administrator. Assign the connection string to a variable.

  1. Create a new TableDef object and set its Connect property to the variable you created in step 1.
  2. Append the TableDef object to the TableDefs collection to link the table or SQL view to your Microsoft Access database.
  3. Open a Recordset object on the linked table or SQL view. You can use the properties and methods of the Recordset object to manipulate the data in the ODBC data source.

The following example uses the Pubs sample database included with Microsoft SQL Server to link the Authors table, and counts the number of authors whose phone number begins with the area code that is passed as an argument to the function.

Function CountByAreaCode(strAreaCode As String) As Long
	Dim dbs As Database, rst As Recordset
	Dim strConnect As String, tdf As TableDef
	Dim lngCount As Long

	strConnect = "ODBC;DSN=Pubs;UID=SA;PWD=;DATABASE=Pubs"

	Set dbs = OpenDatabase("C:\data\cs.mdb")

	' Delete any existing links named LinkedAuthors.
	On Error Resume Next
	dbs.TableDefs.Delete "LinkedAuthors"
	dbs.TableDefs.Refresh

	On Error GoTo ErrorHandler

	' Create a TableDef and set its Connect property.
	Set tdf = dbs.CreateTableDef("LinkedAuthors")
	tdf.Connect = strConnect
	' Specify the table to access within the Pubs database.
	tdf.SourceTableName = "Authors"
	dbs.TableDefs.Append tdf
	dbs.TableDefs.Refresh

	' Open a recordset on the linked table.
	Set rst = dbs.OpenRecordset("LinkedAuthors", dbOpenForwardOnly)

	' Count number of authors whose phone number begins with specified area code.
	Do Until rst.EOF
		If Left$(rst!phone, 3) = strAreaCode Then
			lngCount = lngCount + 1
		End If
		rst.MoveNext
	Loop
	rst.Close
	dbs.Close
	CountByAreaCode = lngCount
	Exit Function

ErrorHandler:
	MsgBox "Error " & Err & ": " & Err.Description
	Exit Function
End Function

In this example, the Authors Recordset object is opened as a forward-only-type Recordset object to optimize performance. Because forward-only-type Recordset objects are snapshots, you cannot update data in them. If you want to be able to update data in the recordset, open it as a dynaset-type Recordset object by using the dbOpenDynaset constant with the OpenRecordset method.

Note   Although you can update information in ODBC databases by using update queries or dynaset-type Recordset objects, you should consider using a pass-through query, which is usually much more efficient. For more information on pass-through queries, see the next section “Using Pass-Through Queries.”

Microsoft Access stores field and index information for the tables you link, which improves performance when you open the tables. Relink remote tables if you change their structure or the structure of their indexes on the server.

See Also   For information on relinking tables, search the Help index for “RefreshLink method.”

Tip   When you link a table from a server, you usually have the option of storing your server password in the local database so that you don’t have to type it each time you start the application. However, if you don’t want users to have this option when they link tables, you can disable the feature. For more information, search the Help index for “MSysConf table.”

See Also   For information on linking remote tables and creating connection strings, see Chapter 18, “Accessing External Data.” For general information on linking, search the Help index for “tables, linking.”

Creating Indexes on Linked SQL Views

If your server allows you to update data by using SQL views and you want to take advantage of this updatability in Microsoft Access, you need to create a pseudo index on the linked view. This index tells Microsoft Access the field or fields that make up the primary key for a record returned by the view—the field or fields that uniquely identify the record. Microsoft Access can then create an updatable dynaset on the view, which forms and queries can use to view and update data.

For example, suppose you link an SQL view named SeptOrdersView that returns a subset of records in the remote Orders table, and you name the linked view SeptemberOrders. Because the OrderID field is still unique within the view, you would use a data-definition query to create the index by running the following SQL statement:

CREATE UNIQUE INDEX index1 ON SeptemberOrders (OrderID)

This doesn’t create a real index on the server or in your local database, nor does it take up much space locally. It simply tells Microsoft Access that the OrderID field is the primary key for the linked view.

See Also   For more information on data-definition queries, search the Help index for “data-definition queries.”

Using Pass-Through Queries

The second way to access data on a server is to use pass-through queries. Pass-through queries are SQL statements that are sent directly to a database server without interpretation by Microsoft Access. You can use pass-through queries in your application to directly manipulate the features of a database server that may or may not be supported by Microsoft Access.

In many applications, you’ll use both ordinary Microsoft Access queries based on remote tables and pass-through queries. When you use an ordinary query to retrieve information from the tables on your database server, Microsoft Access compiles and runs the query, combining the power of the server with the capabilities of the Microsoft Jet database engine. With a pass-through query, you create an SQL statement that Microsoft Access sends directly to the server without stopping to compile the query.

Pass-through queries offer the following advantages over ordinary Microsoft Access queries:

On the other hand, pass-through queries do have several disadvantages:

Creating Pass-Through Queries

Pass-through queries consist of an SQL statement and an ODBC connection string. The SQL statement is interpreted only by the database server and must follow the server’s SQL language specification. The SQL statement cannot contain any Microsoft Access–specific elements or any Visual Basic functions or commands.

See Also   For information on connection strings, see Chapter 18, “Accessing External Data.”

Û To create a pass-through query

  1. Create a QueryDef object by using the CreateQueryDef method. Specify only the name argument for the query. If you want to create a temporary QueryDef object, specify a zero-length string ("") for the name argument.
  2. Set the Connect property of the QueryDef object to a valid connection string.

    Important Always set the Connect property before you set the SQL property so that Microsoft Jet passes the query directly to the ODBC data source without processing it.

  3. Set the SQL property of the QueryDef object to an SQL statement that is compatible with the ODBC data source you are querying.
  4. If your query is an action query that does not return a recordset, set the ReturnsRecords property of the QueryDef object to False and use the Execute method to run the query. Otherwise, set the ReturnsRecords property to True and run the query by opening a recordset on the stored query definition.

The following example sends three pass-though action queries to the Pubs sample database included with Microsoft SQL Server. The first query creates a new table called sales_archive with the same structure as the Sales table in the Pubs database. The second query appends all of the sales records that were created before 1993 from the Sales table to the sales_archive table. The third query deletes all of the sales records created before 1993 from the Sales table.

Sub ArchiveSales()
	Dim dbs As Database, qdf As QueryDef
	Dim strConnect As String
	Dim strSQL As String

	On Error GoTo ErrorHandler

	Set dbs = CurrentDb
	strConnect = "ODBC;DSN=Pubs;UID=sa;PWD=;DATABASE=Pubs"
	Set qdf = dbs.CreateQueryDef("")
	qdf.Connect = strConnect

	strSQL = "CREATE TABLE sales_archive (stor_id char (4) "
	strSQL = strSQL & "NOT NULL, ord_num varchar (20) NOT NULL, "
	strSQL = strSQL & "ord_date datetime NOT NULL, "
	strSQL = strSQL & "qty smallint NOT NULL, "
	strSQL = strSQL & "payterms varchar (12) NOT NULL, "
	strSQL = strSQL & "title_id tid NOT NULL)"

	qdf.ReturnsRecords = False

	qdf.SQL = strSQL
	qdf.Execute

	qdf.SQL = "INSERT INTO sales_archive SELECT * FROM sales WHERE ord_date < '1/1/93'"
	qdf.Execute

	qdf.SQL = "DELETE FROM sales WHERE ord_date < '1/1/93'"
	qdf.Execute

	Exit Sub

ErrorHandler:
	MsgBox "Error " & Err & ": " & Err.Description
	Exit Sub
End Sub

In the previous example, the ReturnsRecords property is set to False because all three queries are action queries. The following example uses a pass-through query to return records. It returns all sales records in the Pubs sample database for the year 1994.

Dim dbs As Database, qdf As QueryDef
Dim strConnect As String, rst As Recordset
Dim strSQL As String

Set dbs = CurrentDb
strConnect = "ODBC;DSN=Pubs;UID=SA;PWD=;DATABASE=Pubs"
Set qdf = dbs.CreateQueryDef("94Sales")
qdf.Connect = strConnect
strSQL = "SELECT * FROM sales WHERE ord_date BETWEEN "
strSQL = strSQL & "'1/1/1994' AND '12/31/1994'"
qdf.SQL = strSQL
qdf.ReturnsRecords = True

Set rst = dbs.OpenRecordset("94Sales", dbOpenSnapshot)

Do Until rst.EOF
	Debug.Print rst!ord_date
	rst.MoveNext
Loop

Note Recordset objects opened on a pass-through queries are always opened as snapshots and cannot be updated.

See Also   For more information on pass-through queries, search the Help index for “pass-through queries.”

Using Stored Procedures

In some environments, your access to server data is limited to a set of server-based stored procedures. You must carry out all data requests and updates through these stored procedures; you have no direct access to the remote tables. In such an environment, you use pass-through queries exclusively.

Your server may have two sets of stored procedures defined: one to retrieve data and one to update data. If you don’t need to update data and only want to retrieve data, you can create a pass-through query for each stored procedure you want to call. You can then base other queries, forms, and reports on these queries as if they were linked tables.

However, if you need to update data in this type of environment, you can collect the user’s input locally and then send the data to the server by running a pass-through query that calls the appropriate stored procedure. You may find either of the following two approaches helpful:

In either case, you need to write Visual Basic code to create a pass-through query that uses the name of the stored procedure and the values to be supplied from the form.

If the stored procedure runs an action query, you can determine whether the stored procedure ran successfully by examining the first element of the Fields collection of the Recordset object that the stored procedure is based on. If the value is 0, then the procedure ran successfully. Otherwise, the procedure did not run successfully.

For example, the following SQL Server stored procedure increases or decreases the royalty schedules in the Roysched table of the Pubs sample database included with Microsoft SQL Server. The amount of the increase or decrease is specified in the integer parameter named delta:

CREATE PROCEDURE change_royalty @delta int AS UPDATE roysched
	SET royalty = royalty + @delta

The following function calls the change_royalty stored procedure in the Pubs sample database, examines the first element of the Fields collection, and returns 0 if the stored procedure ran successfully.

Function intChangeRoyalty(intDelta As Integer) As Integer
	Dim dbs As Database, qdf As QueryDef
	Dim strConnect As String, rst As Recordset
	Dim strSQL As String
	On Error GoTo ErrorHandler
	Set dbs = CurrentDb
	strConnect = "ODBC;DSN=Pubs;UID=sa;PWD=;DATABASE=Pubs"
	strSQL = "declare @status int execute @status = change_royalty"
	strSQL = strSQL & intDelta & " select 'return value' = @status"
	Set qdf = dbs.CreateQueryDef("")
	qdf.Connect = strConnect
	qdf.ReturnsRecords = True
	qdf.SQL = strSQL
	Set rst = qdf.OpenRecordset(dbOpenSnapshot)
	' Examine the first element in the recordset's Fields collection.
	' If it is 0, the stored procedure was successful.
	If rst(0) = 0 Then 
		intChangeRoyalty = 0 
	Else
		intChangeRoyalty = -1
	End If
	Exit Function

ErrorHandler:
	MsgBox "Error " & Err & ": " & Err.Description
	intChangeRoyalty = -1
	Exit Function
End Function

Directly Accessing the Server

The third way to connect to a server is to access it directly in Visual Basic by using the OpenDatabase method with an ODBC connection string. This approach has several disadvantages, however. Although it’s possible to directly open snapshots and dynasets on a remote database, this is always much less efficient than using linked tables. When you link remote tables, Microsoft Jet caches locally a great deal of information about these tables, including field information, index information, and server capabilities. In contrast, when you access the remote tables directly, Microsoft Access has to ask the server for this information every time you run a query.

Note   You’ll want to access the server directly when you preconnect. For information on preconnecting, see “Preconnecting” later in this chapter.