Build Strong Relationships: April 01, 1991 - Straley, Stephen J. Tamburrino, Jim
Build Strong Relationships: April 01, 1991 - Straley, Stephen J. Tamburrino, Jim
Let's return to the basics of the language and the theory of application development to show how to solve
database management issues with Clipper. The advantage of a relational database is the ability to relate data
on common keys. Information can be placed in separate tables to avoid duplicating information and to allow for
easier editing.
In other words, where one database or table may contain customer name and address information, another
database for the same customers needn't carry duplicate information in order to print an invoice. Determining
the links among the various databases in an application takes time, careful thought, and a constant reworking
of the algorithm. Each database is nothing more than a table of information. The construction of the file is
based on various fields and records.
A record in a database is a complete collection of all of the fields for a single entry in a database, and can be
thought of like this:
You can build a database file such as this in two ways. To create a database outside of the application, you can
use an interpreter, such as dBASE, or a utility program like Clipper's DBU.EXE. The source code for this
program comes with the package and only needs to be compiled and linked.
The other method is from within an application. There are two programming approaches. One is to use the
CREATE command to build a STRUCTURE EXTENDED database, a separate database with four fields:
FIELD_NAME, FIELD_TYPE, FIELD_LEN, and FIELD_DEC. By adding records and filling in the field information,
you can create the structure of a database through programming. Consider the following extract:
CREATE Temp
USE Temp
APPEND BLANK
REPLACE Temp->field_name WITH "DEMO", ;
Temp->field_type WITH "C", ;
Temp->field_len WITH 10, ;
Temp->field_dec WITH 0
APPEND BLANK
REPLACE Temp->field_name WITH "AGE",;
Temp->field_type WITH "N",;
Temp->field_len WITH 2,;
Temp->field_dec WITH 0
APPEND BLANK
REPLACE Temp->field_name WITH "BDATE", ;
Temp->field_type WITH "D", ;
Temp->field_len WITH 8, ;
Temp->field_dec WITH 0
CLOSE DATABASES
CREATE Newfile FROM Temp
ERASE Temp.dbf
In this example, you'll add three records to the Temp database. These records are field definitions created with
the CREATE FROM command. The file NEWFILE consists of a character field, "Demo," a numeric field, "Age,"
and a date field, "Bdate." A few things should be noted: First, you don't need to use the REPLACE command
in Clipper 5.0, since it's changed by the preprocessor to simple assignment statements. For example, the first
REPLACE command would look like this:
Temp->field_name := "DEMO"
In addition, combining the assignments on one line doesn't speed up the process. You could place all of the
assignments, one after another, on separate lines (suggested for clarity) and the processing will neither speed
up nor slow down.
And, in order to CREATE the database, you need to close the STRUCTURE EXTENDED database, in this case the
Temp file. In this example, the CLOSE DATABASES command is used; however, a simple USE command would
suffice. The one problem with this approach is unnecessary disk access.
In Clipper 5.0, the new function, DBCREATE(), lets you create a database file from an array of a database
structure. In other words, the same example above would look like this with the DBCREATE() function:
Here, Clipper 5.0 arrays hold the database structure that reduce the demand placed on the hard disk to
CREATE the STRUCTURE EXTENDED file as well as to erase it at the end of the routine. In addition, you don't
need to flush the internal buffers with either a USE or a CLOSE DATABASES command--none are open.
Once you build the database, you'll create an index file. Index files help you to "look up" information within a
database file quickly. For example, when you create a customer list, you'll probably want to print it in
alphabetical order by name, and be able to look up a customer by the assigned account number. How can you
show the same information sorted in two different ways? Do you have to resort the file each time you want to
use it differently? By building and maintaining an index file for each sort order or search criteria, you can
effectively sequence the information without changing the actual record order in the DBF file. Clipper supports
a maximum of 15 index files for each open and active database file.
The index key is the expression that defines the logical order of the records. It consists of a list of key values
and pointers to the corresponding records in the DBF. The key can be as simple as a single field or combination
of fields.
In Clipper, the value of a user-defined function (UDF) can be the key (or any part of the index key). It's
important that all of the keys be the same length. If you trim a field, you must pad the entire expression back
out to maintain the length.
All versions of Clipper have a "phantom record," an empty record of all of the fields, hidden in memory. It's
used in maintaining indexes and APPEND’ing blank records, and is often seen at the beginning or end of a
database after a BOF() or EOF() condition is tripped.
By trimming on a blank character field, the length of the field becomes a NULL byte and will cause erroneous
results. In addition, in Clipper 5.0, the ALLTRIM() function isn't really a function. To avoid past woes, it was
removed and is now handled by the preprocessor. The preprocessor removes every occurrence of ALLTRIM()
and replaces it with an LTRIM(TRIM()) combination. However, if the index header key retains the ALLTRIM()
reference, a runtime error occurs.
The length of the key expression can be up to 250 characters and is stored in the index file header, starting at
byte 22. The REINDEX command should never be used, since it uses the index file header to macro-expand the
key values. However, if the index file header is corrupted, the REINDEX command has little meaning. A final
word about index files: the SET ORDER TO 0 command should be used to "turn off" active indexes when locking
records in a network environment. These tips will be discussed more in future articles.
To start with, let's build an index of our existing CUSTOMER database listed above:
INDEX ON Customer->id_code + ;
Customer->name TO Customer
Here, two index files are built, one as a concatenation of two fields with the other as a value from a function.
Notice the database alias name used in conjunction with the field names. In Clipper 5.0, tighter data
declaration standards are used and as such, the implication of working with a field in this command is not
carried over to Clipper 5.0, especially when using various compiling switches. In other words, if you use the /V
compiling switch and remove all the "Customer->" references from the INDEX ON command
above, Clipper generates, in part, this runtime error:
As you tackle the concept of an index file, so must you tackle the practical design of a relation. You build a
relation on a field or expression in one database as you would find it in another. The value of the field or
expression in the "parent" database is searched for in the "child" database. You build the child database index
order on the expression value from the parent database. When you move from record to record in the parent
database, you do an automatic SEEK evaluation in the child database. Here's one possible relation:
The NEW clause is equivalent to the SELECT 0 command, which automatically uses the next available work area
for this particular database. The order of the indexes listed is important. Here, the scanning order through the
Customer database is on the Customer not the Keycode. However, you'll find a similar key structure in the
Invoice database and, in particular, the Invcode index file. The value of the expression:
STR( Customer->key_nbr, 10 )
is used to SEEK on values in the INVOICES work area, whose controlling index is the Invcode index file. The
expression is required since a relation set on a numerical value is assumed to be a link to that record number in
the child database.
In a typical application, things get more complicated. The big advantage to a relational database model is the
ability to relate files in several directions. In the SET RELATION command, the ADDITIVE clause allows more
than one database to have active relationships. Turning back to the previous example, the Invoices files could
be nothing more than a file of invoice header information, with the detailed line-item information stored in
another database. The ADDITIVE relation would be linked from Invoices to LineItem, for example, with the
controlling relation still being from Customers to Invoices. In the following example, five databases have been
related together:
You can have up to eight child relations from any parent database.
Next time, we'll look at simple models including using a MASTER database to relate databases together in an
application rather than using key fields from indexes to do the same thing. In addition, we'll look at work area
alias names using the same database in two work areas and the concept of filters.
Stephen J. Straley, formerly at Nantucket, is the author of Programming with Clipper 5.0 published by
Bantam, and From the desk of Steve Straley, published by Four Seasons Publishing Co., Inc. Jim
Tamburrino, formerly with Bell-South Services, is president of LMT Computer Services, Inc. Steve and
Jim conduct the Steve Straley Clipper 5.0 Seminars, produced by Four Seasons Publishing Co., Inc.
and may be contacted at (212) 599-2141 or on CompuServe (74105,756).
http://www.accessmylibrary.com/coms2/summary_0286-9230372_ITM