|< Day Day Up >|| |
Clicking the Run Query button on the Excel2k3 VBA Query command bar runs the query currently selected in the ComboBox on the command bar.
In the ThisWorkbook module, the RunDatabaseQuery routine, shown here, builds a connection string using the BuildConnectionString function and gets the query string from the combo box on the command bar using the GetDBQuery routine. The Trim function is used to delete any unnecessary blanks as the beginning and the end of the strings.
For more information on using text functions to clean up your data, see Chapter 9, 'Manipulating Data with VBA'.
Dim c As String
Dim q As String
c = Trim(BuildConnectionString)
q = Trim(GetDBQuery)
If Len(c) = 0 Then
ElseIf Len(q) = 0 Then
RunQuery c, q
The length of each temporary variable holding the connection string and the query is verified to be non-zero. If the length is zero, the appropriate form is displayed to the user to fill in the necessary information. When the form is closed, the user must hit the Run Query button to try the query again.
Assuming that there is information in the connection string and the query string, the RunQuery routine is called to execute the query with both the connection string and the query string passed as parameters.
The following BuildConnectionString routine creates a connection string from information previously stored in the Windows registry. The routine, which is located in the ThisWorkbook module, begins by declaring a number of temporary variables that will hold the information extracted from the registry, along with another temporary variable c that will hold final return value from the function.
Function BuildConnectionString() As String
Dim c As String
Dim DBName As String
Dim DBPassword As String
Dim DBPath As String
Dim DBServer As String
Dim DBType As Long
Dim DBUserId As String
Dim DBWindowsAuth As Boolean
c = ""
DBType = GetSetting("Excel2k3 VBA", "Query", "DBType", 0)
Select Case DBType
DBPath = GetRegistryValue("DBPath", "<enter path to database file>")
If Len(DBPath) <> 0 Then
c = "Provider=Microsoft.Jet.OLEDB.4.0"
c = c & ";Data Source=" & DBPath
DBWindowsAuth = GetSetting("Excel2k3 VBA", "Query", _
DBName = GetRegistryValue("DBName", "<enter database name>")
DBPassword = GetRegistryValue("DBPassword", "<enter password>")
DBServer = GetRegistryValue("DBServer", "<enter database server>")
DBUserId = GetRegistryValue("DBUserId", "<enter userid>")
If Len(DBServer) = 0 Then
DBServer = "localhost"
If Len(DBName) <> 0 Then
c = "Provider=SQLOLEDB.1"
c = c & ";Data Source=" & DBServer
c = c & ";Initial Catalog=" & DBName
If DBWindowsAuth Then
c = c & ";Integrated Security=SSPI"
ElseIf Len(DBUserId) <> 0 And Len(DBPassword) <> 0 Then
c = c & ";User line-height:1"> c = c & ";Password=" & DBPassword
c = ""
c = GetRegistryValue("ConnectionString", "<enter connection string>")
BuildConnectionString = c
After setting c to an empty string, the routine grabs the type of database from the registry and stores it in DBType. This variable is then incorporated into a Select Case statement, which builds different connection strings depending on the type of database being used.
If an Access (Jet) database is being used, the DBPath value is extracted from the Windows registry using the GetRegistryValue helper function. This function takes two parameters, the key and the default value. If the value extracted from the registry is different than the default value, an empty string will be returned.
If GetRegistryValue returned an empty string (len = 0), c remains an empty string. Otherwise, the appropriate connection string is created for an Access database using the value extracted from the registry.
The same approach is used for SQL Server databases (DBType = 1). The value for DBWindowsAuth is extracted directly from the registry because its default value is not a string, whereas the values for DBName, DBPassword, DBServer, and DBUserId are extracted from the registry using the GetRegistryValue routine.
Unlike Access connection strings, the routine attempts to substitute intelligent values in case the user hasn't supplied a default value. For instance, if the length of DBServer is zero, the program assumes that the user is running the query against the local computer. If the length of DBName isn't zero, the program attempts to build a partial connection string using DBName and DBServer. Then, if Windows authentication is used, Integrated Security=SSPI is appended to the connection string and the information in DBUserId and DBPassword is ignored.
If DBWindowsAuth is False, the DBUserId and DBPassword are checked to see if they contain a value. If both contain information, these fields are appended to the connection string. If one of these fields doesn't have any information, c is set to the empty string, destroying the partial connection string that already exists.
If the user selected Advanced on the DBInfo form, the ConnectionString value is extracted from the registry using the GetRegistryValue helper function. No further checking is required here because GetRegistryValue ensures that an empty string is returned if the default value is retrieved from the registry.
Finally, the routine ends by returning the temporary variable c as the value of the function.
The GetRegistryValue helper function calls the GetSetting function to retrieve the desired key from the registry. If the return value is the same as the supplied default value, the return value is set to the empty string.
Function GetRegistryValue(key As String, default As String) As String
Dim r As String
r = GetSetting("Excel2k3 VBA", "Query", key, default)
If r = default Then
r = ""
GetRegistryValue = r
Getting the query string from the combo box on the command bar follows the same basic approach discussed elsewhere in this chapter. After locating the appropriate command bar, the FindControl method is used to search for the specific control containing the combo box. The following function is also located in the ThisWorkbook module:
Function GetDBQuery() As String
Dim c As CommandBar
Dim cc As CommandBarComboBox
On Error Resume Next
Set c = Application.CommandBars("Excel2k3 VBA Query")
Set cc = c.FindControl(, , "Excel2k3 VBA Query Statement")
If Not cc Is Nothing Then
GetDBQuery = cc.Text
ElseIf cc.Text = "<enter a query>" Then
GetDBQuery = ""
GetDBQuery = ""
The main benefit of this routine is that the query string is compared to the default value that was loaded when the program began. If it is, the function will return an empty string, indicating that the user should be prompted to enter a query.
Once the user has supplied values for the connection string and the query string, which have passed some simple edit checks, the RunQuery routine, located in the ThisWorkbook module, is called to get the information from the database.
Sub RunQuery(c As String, q As String)
Dim cn As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
On Error Resume Next
Set cn = New ADODB.Connection
cn.ConnectionString = c
If Err.Number <> 0 Then
MsgBox "Connection error: " & Err.Description
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cn
cmd.CommandText = q
cmd.CommandType = adCmdText
Set rs = New ADODB.Recordset
Set rs.Source = cmd
If Err.Number = 0 Then
MsgBox "Query error: " & Err.Description
To execute the query, this routine uses three ActiveX Data Object (ADO) database objects: a Connection object, a Command object, and a Recordset object. Each is declared at the start of this routine. Next, error checking is disabled by using the On Error Resume Next statement because the routine checks for errors after any critical statement.
The first step in retrieving rows from a database is to establish a connection to the database. A new instance of the ADODB.Connection object is created, and the connection string value that's passed to this routine is assigned to the Connection object's ConnectionString property. After instantiating the Connection object, the Open method is used to open a connection to the database.
Out with the New
If there was a problem opening the connection, an error message is displayed to the user and the Exit Sub statement is used to leave the subroutine with any further processing.
Next a new instance of the ADODB.Command object is created. The newly opened Connection object is assigned to the ActiveConnection property, and the query is assigned to the CommandText property. Finally, the CommandType property is set to adCmdText, meaning that the Command object contains an SQL statement.
A new ADODB.Recordset object is created, and the Source property is set to the Command object that was just initialized. The Connection object's Errors collection is explicitly cleared, and then the Recordset object's Open method is called.
Any errors that occur while opening the Recordset are trapped, and an error message is displayed to the user. Otherwise, the CopyRows subroutine is called to copy the rows from the Recordset object to the current worksheet.
Finally, the Recordset object and the Connection object are closed (in that order). These steps release any resources held by those objects back to the operating system.
Close Your Connections
Once you have a Recordset that contains rows from the database, the only step left is to copy the rows to your worksheet one row at a time. The CopyRows routine in the ThisWorkbook module relies on three local variables: i and j, which contain pointers to the current cell row and the column on the worksheet, and f, which contains a field from the Recordset object.
Sub CopyRows(rs As ADODB.Recordset)
Dim i As Long
Dim j As Long
Dim f As ADODB.Field
i = 1
Do While Not rs.EOF
j = 1
For Each f In rs.Fields
Cells(i, j) = f.Value
j = j + 1
i = i + 1
After the space for the variables has been reserved, the entire worksheet is cleared by selecting all the cells on the worksheet (Cells.Select) and then clearing the selection with the ClearContents method. Then the variable i is set to 1, which points at the first row in the worksheet.
Next a loop is set up that iterates through each row in the Recordset object. This loop continues until the EOF method returns True, meaning that the current record pointer has moved beyond the last row contained in the Recordset.
Inside the loop, j is set to 1, which points to the first column in the worksheet. A For…Each loop is used with the variable f to retrieve each Field object from the recordset's Fields collection. The value of the field is copied directly from the Value property to the appropriate cell pointed by i and j. After a field is copied, j is incremented to point to the next column.
Once all the fields for a particular row have been copied, the MoveNext method is used to reposition the current record pointer to the next record. Also i is incremented to point to the new row in the worksheet.
|< Day Day Up >|| |