
- •Using the Database Access extension
- •Tips on learning the Database Access extension
- •Getting on-line help
- •Getting technical support from ESRI
- •Visit ESRI on the Web
- •Exercise 1: Make a map of U.S. states, cities, and counties
- •Exercise 2: Find counties with many single family homes
- •Exercise 3: Find locations for an advertising campaign
- •Exercise 1: Identifying potential market cities in the United States
- •Exercise 2: Narrowing your search for new market cities
- •The common Database Access objects
- •The SDE interface objects
- •The ODBC interface objects
- •Adding a database theme to a view
- •Selecting features in a database theme
- •Working with selected features
- •Creating and working with database tables
- •Working with selected records in Database Tables
- •Modifying the source data
- •Using locks and transactions
- •Checking for errors
- •Creating new tables and spatial columns
- •Creating and working with database tables
- •Modifying the source data
- •Using locks and transactions
- •Checking for errors
- •Working with selected records
- •Setting up your computer for SDE
- •Set up your computer for ODBC
- •Creating new tables in the database
- •Index

92 Using ArcView Database Access
Creating and working with database tables
You can create an ODBC database table from the user interface by choosing Add Database Table from the project menu. When you create a database table you build an SQL Select statement to define the contents of the table. The script below creates a new ODBC connection, defines an SQL Select statement, and then creates a database table.
theCon = ODBCConnection.Make(“esri_odbc”,“business”,“Jdoe”,“myPsswd”) theQuery = QueryDef.Make(theCon)
theQuery.SetSQL(“Select customers.* From Customers”) theQuery.SetKeyColumn(“”)
theQuery.SetKeyTable(“”)
theDBTable = DBTable.Make(theQuery) theDBTable.SetName(“Customers”) theDBTable.GetWin.Open
This script connects to a relational database that has databases of tables. The database containing the Customers table is called business. The select statement chooses all the columns in the Customers table using the asterisk “*” character. The SetKeyColumn and SetKeyTable requests are used to specify a column from a table in the SQL Select statement to be used for creating a keyset. To create a forward only scrolling database table, the KeyTable and KeyColumn are set to null strings as shown above.
From the user interface you can change a database table’s query using the Database Table Properties dialog. To see only the customers in the southwest region you would type “Where region = ‘SW’” after the existing query, then click OK. The script below makes the same change to an existing database table.
theDBTable = av.FindDoc(“Customers”) theQuery = theDBTable.GetQueryDef
theQuery.SetSQL(“Select customers.* From Customers Where region = ‘SW’”) theDBTable.GetVTab.Refresh
If you want to select records in this table, you have to convert it to a keyset database table. From the interface you would do this using the Database Table Properties dialog. The script below shows how to accomplish the same task with Avenue. Once you run this script, the selection tools in the user interface will become enabled when the Customers table is active.
theDBTable = av.FindDoc(“Customers”) theQuery = theDBTable.GetQueryDef theQuery.SetKeyTable(“Customers”) theQuery.SetKeyColumn(“Cust_ID”) theDBTable.GetVTab.Refresh
In the previous scripts, we used the notation customers.* to select all columns in the Customers table. This was used because keyset database tables require that you specify all columns using the tablename.* notation. If you are using forward only scrolling tables, the * notation will also work.
Chapter 6 Using Avenue to manipulate ODBC objects |
93 |
Stepping through a database table’s records
You can step through each record in a database table using an ODBCRecordSet. When you open a RecordSet, the current record is positioned above the first record. The first time through the loop the Next request positions the first record as the current record. Each subsequent pass through the while loop advances the current record to the next record in the set. You should close the RecordSet when you are finished accessing records so the memory can be freed for other use.
The following script shows how to read data from an ODBCRecordSet to create a list of customer names.
theDBTable = av.FindDoc(“Customers”) theQuery = theDBTable.GetQueryDef theRSet = theQuery.OpenRecordSet theField = theRSet.FindField(“customer”) theCustomers = {}
while (theRSet.Next)
custName = theRSet.GetValue(theField).Clone theCustomers.Add(custName)
end theRSet.Close
msgbox.listAsString(theCustomers, “Customer List”, “Southwest Region”)
The RecordSet has a set of Field objects representing the columns selected by the query, and one value object of the appropriate data type for each field. GetValue returns a string containing the RecordSet’s Value object for the customer field; each object’s value represents one of the current record’s values. GetValue returns the value object for one Field. You only need to get the RecordSet’s value objects once. Each time through the loop, when the Next request changes the current record, the value of each Value object will automatically change.
ArcView recycles the value objects for each record in the RecordSet because if your query retrieved a large number of rows, and if new objects were created for each record’s values, your computer could run out of memory. The script above clones the customer name before adding it to the list to keep names from each selected record. Otherwise, the list would contain many string objects all pointing to the name value in the current record; each element in the name list would have the same value.
Field objects in ArcView have many properties, but changing them has no impact on the RecordSet’s contents, which are selected by its QueryDef. The Fields merely let you access the values for a specific column. Closing the RecordSet deletes its field and value objects.
The script below shows how to use a recordset to total the sales to customers in the southwest region.

94 Using ArcView Database Access
theDBTable = av.FindDoc(“Customers”) theQuery = theDBTable.GetQueryDef theRSet = theQuery.OpenRecordSet theField = theRSet.FindField(“Sales”) total = 0
while (theRSet.Next)
total = total + theRSet.GetValue(theField)
end theRSet.Close
msgbox.info(total.AsString, “Total Sales in the Southwest Region”)
Instead of calculating the total sales using a RecordSet, you could create a new query with an SQL statement where the database calculates the total for you. The script below shows how.
theDBTable = av.FindDoc(“Customers”)
theCon = theDBTable.GetQueryDef.GetConnection theQuery = ODBCQueryDef.Make(theCon)
theQuery.SetSQL(“Select SUM(Sales) From customers Where region = ‘SW’”) theRSet = theQuery.OpenRecordSet
theRSet.Next
total = theRSet.GetRow.Get(0) theRSet.Close
msgbox.info(total.AsString, “Total Sales in the Southwest Region”)
Selecting columns from the database
While queries that use SetSelectColumns, SetFromTables and SetWhereClause are like SQL, there are several SQL standards that aren’t supported with them. For example, you can’t use an asterisk “*” with the SetSelectColumns request to choose all columns in the selected tables. Similarly, you can’t assign aliases to columns and tables in the SetSelectColumns and SetFromTables requests, then use those aliases elsewhere in the statement. You must use these queries, if you plan on editing the data in the database.
When you provide an alias for a column in a query, ArcView names the column with the alias you provide, but it doesn’t keep its real name or the calculation. In a database table, you’ll see the column of values, but you won’t be able to get statistics for this column from the user interface because ArcView doesn’t know how to get the original data in the column.
If you define a column like Total*100 and export the database table to a dBASE file, the column’s name will not be accurately represented. In the database table, a field representing the column above will have a field name and alias of Total*100 as expected. Field names in dBASE can’t include characters like * so the corresponding column will be written to the dBASE file with the name Total_100. Also, since dBASE allows a maximum of 10 characters in a field name, any columns in the database table with more than 10 characters will be truncated when exported.
Chapter 6 Using Avenue to manipulate ODBC objects |
95 |
In this script, a new ODBCQuerydef object was created from an existing connection, and an SQL statement which uses the SUM function is applied to it. The SUM function totals the values in the Sales column for each record selected by the Where clause. There are many SQL functions and operators that let you summarize the values in a table. The GroupBy operator lets you summarize the values in one column for each unique value in another column.
Modifying the source data
To modify the source data you need to have the appropriate permissions. Insert permission is needed to add records to a table, update permission to change records in a table, and delete permission to remove records from a table. The database administrator grants permissions for each user; therefore, your connection determines whether or not you can modify the database.
With a query you can edit the source data using RecordSet requests if the query selects columns from one table only. If the query joins two tables together, the CanUpdate request will return false. If you use a querydef object, you must use the SetSelectColumns, SetFromTables, and SetWhereClause requests to specify the table, fields, and rows that you wish to edit. A QueryDef object created by the Add Database Table dialog uses the SetSQL request to define the query instead of SetSelectColumns, SetFromTables, and SetWhereClause. For this reason, recordsets created from these querydefs can’t be used to edit data. The following sections illustrate how to modify the source data using RecordSet requests.
Adding records to the database
Suppose you have a table containing highway information. There is a proposed construction plan to add a new highway, number 55.
To load new data into the database you need to use the AddNew, Update, and EndUpdate requests. The AddNew request prepares the RecordSet for creating new rows in the database. The Update request sends a value for each of the RecordSet’s fields to the database and places them in a new record in the table. Use the EndUpdate request after all new rows have been sent to the database; it completes the AddNew request and ensures that ODBC has sent all new records to the database.
‘define the query
theQuery = QueryDef.Make(theCon) theQuery.SetSelectColumns({“KeyCol”,“Name”}) theQuery.SetFromTables({“Highways”}) ‘prepare RecordSet for adding records theRSet = theQuery.OpenRecordSet
if (theRSet.CanUpdate) then theRSet.AddNew

96 Using ArcView Database Access
theRSet.SetRow({101, “Highway 55”}) theRSet.Update
theRSet.SetRow({102, “Albion Road”}) theRSet.Update
theRSet.EndUpdate
end theRSet.Close
The SetRow request assigns values to the value objects for each field in the RecordSet. The order of values in the SetRow request must be the same as the columns in the SetSelectColumns request. If the RecordSet had other fields, you would use null objects for the appropriate data types as placeholders in the list of values. Instead of the SetRow request, you can assign values to the value objects with the SetValue request by changing the script as follows.
if (theRSet.CanUpdate) then
nField = theRSet.FindField(“Name”) kField = theRSet.FindField(“KeyCol”) theRSet.AddNew theRSet.SetValue(nField, “Highway 55”) for each rec in 103..106
theKey = rec theRSet.SetValue(kField, theKey) theRSet.Update
end theRSet.EndUpdate
end
This version of the script sets the RecordSet’s name field to the value Highway 55 once. Each time through the “for each” loop the script changes the value in the KeyCol column. The Update request creates a new record containing the current value of the KeyCol column and the constant Name value. If the Highways table has other fields, null values would be stored in the database for them.
Editing records in the database
Suppose that later you want to edit the contents of the Highways table to add the description “Proposed” for the new Highway 55 records.
To change records in the database you need to use the Edit, Update, and EndUpdate requests. The Edit request prepares the RecordSet to change the records identified by its Where clause. The Update request replaces values in each identified record with the current value for each field in the RecordSet. Use the EndUpdate request after all changes have been made; it completes the editing process and ensures that ODBC has sent all changes to the database.
There are two ways to edit a table’s contents. You can loop through a table’s records to check for errors in the data, or you can know in advance that you want to change specific records in the table. The following script shows how to edit the current record
Chapter 6 Using Avenue to manipulate ODBC objects |
97 |
while looping through a RecordSet. From an ODBCTable representing the Highways table, the script opens a RecordSet that will have fields for all columns in the table.
‘open the recordset to update the Description field theTable = ODBCTable.Make(theCon, “Highways”) theRSet = theTable.OpenRecordSet(“”)
if (theRSet.CanUpdate) then theFields = theRSet.GetFields
nameIndex = theFields.Find(theRSet.FindField(“Name”)) keyIndex = theFields.Find(theRSet.FindField(“KeyCol”)) descField = theRSet.FindField(“Description”)
theRow = theRSet.GetRow while (theRSet.Next)
‘get current record’s values, edit if it’s a Highway 55 record hwyName = theRow.Get(nameIndex)
if (hwyName = “Highway 55”) then
‘identify which highway 55 record you’re editing with the key keyValue = theRow.Get(keyIndex)
theRSet.Edit(“KeyCol = “+keyValue.asstring) theRSet.SetValue(descField, “Proposed”) theRSet.Update
end
end theRSet.EndUpdate
end theRSet.Close
This script will edit the current record if it has a Highway 55 record. To edit the current record, the script needs to construct a Where clause that uniquely identifies it. This script uses the Key value in the Where clause because it’s unique for each record in the table.
In this script, the RecordSet has fields for all columns in the table. You only want to change the value in one column, but you need to read values in other columns to find out which records you need to edit. The Next request sets the value object for each field in the list to the current record’s original values. The SetValue request changes the value object for the Description field to the new value, Proposed. The Update request changes the values in all columns, but only the value in the Description column will be different afterwards.
This script only requires that the Name, Key, and Description columns be represented in the RecordSet. To avoid writing values to the database that don’t need to be changed, create a query with the SetSelectColumns, SetFromTables, and SetWhereClause requests that chooses the Name, Key, and Description columns only.
The following script illustrates how you can edit records without looping through a RecordSet. You know in advance that you want to change the Description value for all the records named Highway 55. Because you want to make the same change for each of the Highway 55 records, you can change them all in one step.
‘define the query

98 Using ArcView Database Access
theQuery = QueryDef.Make(theCon) theQuery.SetSelectColumns({“Description”}) theQuery.SetFromTables({“Highways”})
‘open the record set and change the description field for ‘all Highway 55 records in the table
theRSet = theQuery.OpenRecordSet if (theRSet.CanUpdate) then
descField = theRSet.FindField(“Description”) theRSet.Edit(“Name = ‘Highway 55’”) theRSet.SetValue(descField, “Proposed”) theRSet.Update
theRSet.EndUpdate
end theRSet.Close
This script changes the Description value for all records in the Highways table whose name is Highway 55. Because you don’t need to read any values from the database to edit those records, you don’t need to use the Next request.
It is essential that the QueryDef select only the columns whose values will be changed. If this query selected additional columns from the table but didn’t set their values, the current record’s Value objects would all contain null values except for the Description value. That’s because this script doesn’t use the Next request. When executing Update, the original values for all columns in the RecordSet are replaced; the additional columns would no longer have any values in the records selected by the Edit request.
The above examples assume that the only Highway 55 records in the Highways table are those associated with the proposed highway. Suppose the Highways table contains roads for California and Arizona, that California has a Highway 55, Arizona doesn’t, and the proposed Highway 55 is in Arizona. Both example scripts in this section would have to be modified to change only the Highway 55 records in Arizona.
The first script would have to read values from the State column as well to ensure the current record’s Highway 55 was in Arizona. Its Where clause for the Edit request is still correct because the Key value is unique for each record. The second script’s Where clause for the Edit request would have to change to choose the Highway 55 records from Arizona only; for example, “Name = ‘Highway 55’ and State = ‘Arizona’”. The Edit request’s Where clause needs to include the State = ‘Arizona’ criterion even if the query’s Where clause selected highways from Arizona only.
If you create a query using an SQL Select statement (SetSQL request), you can loop through the selected records with a RecordSet, but you can’t use RecordSet requests to modify the source data. The RecordSet.CanUpdate request will return false. Instead, you need to create another query that has an SQL Insert, Update, or Delete statement. The script below shows how.
theQuery = ODBCQueryDef.Make(theCon)
theQuery.SetSQL(“Update Highways Set Name = ‘Highway 50’ Where Name = ‘Albion Road’”)
Chapter 6 Using Avenue to manipulate ODBC objects |
99 |
theQuery.Execute
This script changes a street’s name from Albion Road to Highway 50. Use the Execute request to send the database an SQL statement that doesn’t retrieve records. The Querydef class can also be used to create tables or indexes by using the appropriate SQL statement in the SetSQL request and then using the Execute request to execute the SQL statement.
Deleting records in the database
Suppose Arizona’s proposed Highway 55 project is cancelled. The following script shows how you can delete records associated with this project from the Highways table.
theQuery = QueryDef.Make(theCon) theQuery.SetSelectColumns({“Description”}) theQuery.SetFromTables({“Highways”}) theRSet = theQuery.OpenRecordSet
if (theRSet.CanUpdate) then
theRSet.Delete(“Name = ‘Highway 55’ and State = ‘Arizona’”)
end theRSet.Close
The Delete request removes the records identified by its Where clause from the database. You don’t use the Update or EndUpdate request with the Delete request.
Creating new tables in the database
There are no requests provided with the ODBC classes to create new tables in the database. This is because there is no standard way of creating a table in a database using ODBC. To create a new table, you must use the SetSQL and Execute requests to execute a database-specific command. The script below creates a new table in an Oracle database that will contain information about secondary roads.
‘define the query
theQuery = QueryDef.Make(theCon)
theQuery.SetSQL(“Create table secondary (keycol number(5), name varchar2(30), description varchar2(50), state varchar2(30))”) ok = theQuery.Execute
if (ok.Not) then
MsgBox.Error(theCon.GetErrorMsg,“Error creating secondary table”)
end