Delphi - Database Application Developer's Book - Delphi For Windows PDF
Delphi - Database Application Developer's Book - Delphi For Windows PDF
Developers Guide
Delphi for Windows
C h a p t e r 1
I n t r o d u c t i o n
Copyright
Agreement
Delphi enables you to create robust database applications quickly and easily. Delphi
database applications can work directly with desktop databases like Paradox, dBASE,
the Local InterBase Server, and ODBC data sources. The Delphi Client/Server edition
also works with remote database servers such as Oracle, Sybase, Microsoft SQL Server,
Informix, InterBase, and ODBC data sources. Delphi client applications can be scaled
easily between mission critical network-based client/server databases, and local
databases on a single machine.
This chapter introduces Delphis database tools, including the Data Access and Data
Controls component pages, the Fields Editor, the Database Desktop, and the Database
Forms Expert.
You also need to have a working knowledge of the Database Management System
(DBMS) your Delphi database applications access, whether it is a desktop database such
as dBASE or Paradox, or an SQL server. For information specific to building
client/server applications with Delphi, see Chapter 6, Building a client/server
application.
This book assumes you have a basic understanding of relational databases, database
design, and data management. There are many third-party books covering these topics
if you need to learn more about them.
Introduction
ReportSmith
Delphi IDE
Database
Desktop (DBD)
Delphi Application
BDE
Configuration
Utility
Report
SQL Links
Paradox
dBASE
ODBC Drivers
ReportSmith Drivers
ASCII
InterBase
for Windows
Oracle
Sybase
Informix
InterBase
...
Tool
Purpose
Table 1.1
Tool
Purpose
ReportSmith
Borland Database Engine (BDE)
These features enable you to build database applications with live connections to
Paradox and dBASE tables, and the Local InterBase Server through the BDE. In many
cases, you can create simple data access applications with these components and their
properties without writing a line of code.
The BDE is built into Delphi components so you can create database applications
without needing to know anything about the BDE. The Delphi installation program
installs drivers and sets up configuration for Paradox, dBASE, and the Local InterBase
Server, so you can begin working with tables native to these systems immediately. The
BDE Configuration Utility enables you to tailor database connections and manage
database aliases.
Advanced BDE features are available to programmers who need more functionality.
These features include local SQL, which is a subset of the industry-standard SQL that
enables you to issue SQL statements against Paradox and dBASE tables; low-level API
function calls for direct engine access; and ODBC support for communication with other
ODBC-compliant databases, such as Access and Btrieve.
Delphi includes Borland ReportSmith, so you can embed database report creation,
viewing, and printing capabilities in Delphi database applications. Delphi also includes
the Database Desktop (DBD), a tool that enables you to create, index, and query desktop
and SQL databases, and to copy data from one source to another. For more information
about ReportSmith, see Creating Reports. For more information about the DBD, see
Appendix A, Using Database Desktop.
The Local InterBase Server is a single-user, multi-instance, 16-bit, ANSI SQL-compliant,
Windows-based version of Borlands 32-bit InterBase SQL server that is available for
Novell NetWare, Windows NT, and Unix. For more information, see the Local InterBase
Server Users Guide.
The following table lists the additional database features available in the Client/server
edition of Delphi. These features extend Delphis database capabilities to access remote
Introduction
SQL database servers such as Sybase, Microsoft SQL Server, Oracle, Informix, and
InterBase.
Table 1.2
Tool
Purpose
SQL Drivers
Both SQL Links and ReportSmith provide native drivers that connect Delphi
database applications to remote SQL database servers, such as Oracle, Sybase,
Microsoft SQL Server, Informix, and InterBase.
Creates SQL statements by visually manipulating tables and columns.
SQL Links provide Delphi applications with SQL access to data residing on remote
servers, including Sybase, Microsoft SQL Server, Oracle, and Informix. When an SQL
Link driver is installed, SQL statements are passed directly to the server for parsing and
execution. For more information about using passthrough SQL, see Chapter 5, Using
SQL in applications.
What is a database?
Delphi programmers should understand some basic concepts about databases, data,
and data access, before building database applications. A database consists of one or
more tables, where each table contains a series of columns into which records (also
called rows) are stored. Each record is identical in structure. For example, a database
of addresses consists of a table with name, street address, city, state, and zipcode
columns. The intersection of a single column and row is referred to as a field. Fields
contain values. The following figure illustrates these concepts:
Figure 1.2
Structure of a table
Column names
CustNo
Current field
Name
Street
City
PO Box Z-547
Freeport
1 Neptune Lane
Kato Paphos
Current record
Records
The current field is one field in a single record. The current record is a single record in a
multi-record set that is the focus of attention. For example, some Delphi database
applications display multiple columns and records in a grid format for editing. As far as
Delphi controls are concerned, only one field in a single record is current, meaning
that editing tasks affect only the data in that field.
Different databases vary widely in structure. A database in Paradox consists of one or
more files, each of which contains a single table or index, but an SQL relational database
on a remote server generally consists of a single file that contains all tables, indices, and
other database structures. Delphis Data Access and Data Control components
encapsulate the underlying structure of the databases your application uses, so that
your application can present the same interface to an end user whether it accesses a local
Paradox file or a database on a remote SQL server.
The information in most databases is constantly changing. When you access a
networked database from a Delphi application, many users may be accessing and
updating the database at the same time. When any database application accesses a
database, whether to process a query or generate a report, the application receives a
snapshot of the database as it was at the time the application accessed the database. An
applications view of data may differ from the data currently in the database, so
database applications should always be robust enough to react to such data changes. For
more information about building client/server applications that access remote data, see
Chapter 6, Building a client/server application.
What is data?
In this book, data refers to information stored in a database. Data may be a single item
in a field, a record that consists of a series of fields, or a set of records. Delphi
applications can retrieve, add, modify, or delete data in a database.
Introduction
Data sources
Delphi database applications get their data through the BDE. The different data sources
(not to be confused with the TDataSource component) that the BDE can use are shown in
Table 1.3.
Table 1.3
Data source
Description
File extension
Paradox
.DB
dBASE
ASCII files
Local InterBase Server
SQL Database Server: Oracle, Sybase,
Microsoft SQL Server, Informix, InterBase
ODBC data sources
.DBF
.TXT
.GDB
Depends on server
The following figure illustrates how Data Access and Data Control components relate to
data, to one another, and to the user interface in a Delphi database application:
Figure 1.3
TTable
TDataSource
TDBEdit
TDBCheck
Data
TQuery
TDataSource
TDBGrid
TDBEdit
TDBCheck
BDE
(User Interface)
Delphi Form
As this figure illustrates, a form usually contains at least three database components: a
dataset component (TTable and TQuery in the figure) that communicates with the BDE; a
TDataSource component that acts as a conduit between a dataset component and the
user interface; and one or more data control components, such as TDBEdit or TDBGrid,
that enable a user to browse, edit, or enter data.
When building a database application, you place data access components on a form,
then assign them properties that specify the database, table, and records to access. They
provide the connection between a data source and Data Control components.
At run time, after an application is built and compiled, data access objects are not visible,
but are under the hood, where they manage data access.
Introduction
The following table lists the data access objects on the Data Access page, and briefly
describes how they are used:
Table 1.4
Component
Purpose
TDataSource
TTable
TQuery
TStoredProc
TDatabase
TBatchMove
TReport
Four data access components deserve special mention. Most forms provide a link to a
database with a TTable or TQuery component (or through a user-defined component
based on the normally hidden abstract class, TDataSet, of which TTable and TQuery are
descendents). Other forms provide a link to a database with TStoredProc, also a
descendent of TDataSet. In turn, all forms must provide a TDataSource component to
link a TTable, TQuery, or TStoredProc component to data control components that
provide the visible user interface to the data.
TTable, TQuery, (and TStoredProc, when it returns a result set) contain a collection of
TField components. Each TField corresponds to a column or field in the table or query.
TFields are created
Automatically, when TTable, TQuery, or TStoredProc are activated.
At design time, using the Fields editor.
For more information about TFields and the Fields editor, see Chapter 3, Using data
access components and tools. For more information about TStoredProc, see Chapter 6,
Building a client/server application.
Understanding TTable
The TTable component is the easiest way for a programmer to specify a database table
for access. To put a TTable component on a form:
Note
An alias can also be used for local Paradox and dBASE tables. You can choose an alias
from a drop-down list in the Object Inspector.
5 Enter the name of the table to use in the TableName property of the Object Inspector
window, or you can also choose a table from the drop-down list instead of entering
the name.
By default, a TTable component accesses every column in a table when you activate it.
When a visual component, such as TDBEdit, is associated with a TTable object, it can
display any field in the table. Multi-column visual components, such as TDBGrid, access
and display columns in the table using the tables TField list.
If you double-click a TTable component on a form, you invoke the Fields Editor. The
Fields Editor enables you to control the way Data Control components display data. It
can
Create a static model of a tables columns, column order, and column type that does
not change even if changes are made to the underlying physical table in the database.
Provide convenient, readable, and efficient component names for programmatic
access.
Specify the order in which fields are displayed and which fields to include.
Specify all display characteristics of fields.
Add custom validation code.
Create new fields for display, including calculated fields.
For complete information about the Fields Editor, see Chapter 3, Using data access
components and tools.
Understanding TQuery
The TQuery component provides a tool for data access using SQL statements, such as a
SELECT statement, to specify a set of records and a subset of columns from a table.
TQuery is useful for building local SQL queries against Paradox and dBASE data, and
for building client/server applications that run against SQL servers.
To put a TQuery component on a form:
Introduction
With Delphi Client/Server, you can right-click a TQuery component on a form, then
select the Visual Query Builder from the pop-up menu. The Visual Query Builder
enables you to connect to a database and build an SQL statement interactively. For
complete information about the Visual Query Builder, see the online Help.
If you double-click a TQuery component, you invoke the Fields Editor. The Fields Editor
enables you to control the way Data Control components display data. For complete
information on TQuery and the Fields Editor, see Chapter 3, Using data access
components and tools.
Understanding TDataSource
Every dataset that supplies a data control component must have at least one
TDataSource component. TDataSource acts as a bridge between one TTable, TQuery, or
TStoredProc component and one or more data control components that provide a visible
user interface to data.
TTable and TQuery can establish connections to a database through the BDE, but they
cannot display database information on a form. Data Control components provide the
visible user interface to data, but are unaware of the structure of the table from which
they receive (and to which they send) data. A TDataSource component bridges the gap.
To put a TDataSource component on a form:
TDataSource is also used to link tables or queries in a master/detail form. For more
information about master/detail forms, see Chapter 2, Building a sample database
application: MASTAPP.
Many data controls are data-aware versions of component classes available on the
Standard page of the Component palette. In addition to standard component
functionality, data controls can display data from a field in a database table, or send new
or modified data from a form to a database table.
10
The following table lists the data controls on the Data Control page.
Table 1.5
Component
Purpose
TDBNavigator
Data-aware navigation buttons that move a tables current record pointer forward or
backward; start Insert or Edit mode; post new or modified records; cancel Edit
mode; and refresh display to retrieve updated data.
Data-aware label that can display a field from a currently active record.
Data-aware edit box that can display or edit a field from a currently active record.
Data-aware check box that can display or edit a Boolean data field from a currently
active record.
Data-aware list box that can display values from a column in a table.
Data-aware combo box that can display or edit values from a column in a table.
Data-aware radio group populated with radio buttons that can display or set
column values.
Data-aware custom grid that enables viewing and editing data in a tabular form
similar to a spreadsheet; makes extensive use of TField properties (set in the Fields
Editor) to determine a columns visibility, display format, ordering, etc.
Data-aware memo box that can display or edit text BLOB data from a currently
active record.
Data-aware image box that can display, cut, or paste bitmapped BLOB images to
and from a currently active record.
Data-aware list box that displays values mapped through another table at run time.
Data-aware combo box that displays values mapped through another table at run
time.
TDBText
TDBEdit
TDBCheckBox
TDBListBox
TDBComboBox
TDBRadioGroup
TDBGrid
TDBMemo
TDBImage
TDBLookupList
TDBLookupCombo
Data control components make up a consistent visual user interface for Delphi database
applications, whether the application accesses a local database file, or a remote database
server. To see how data control components are used in an application, see the
subsequent chapters of this book. For a complete description of each data control
component and its properties, see the online VCL Reference.
Introduction
11
Inexperienced database applications programmers can use the Database Forms Expert
to learn how to build database forms. Experienced database applications programmers
can use it to speed application development. To learn how to use the Database Forms
Expert when building an application, see Chapter 2, Building a sample database
application: MASTAPP.
12
Development scenarios
Since an applications design usually depends on the structure of the database it will
access, the database must be defined before the application can be developed.
Note
Database development (also called data definition) is a part of the overall development
process, but is beyond the scope of this manual. For more information, refer to the
numerous books about relational database design.
There are four possible scenarios for Delphi database application development:
The database does not yet exist or must be re-defined.
Use the Database Desktop utility to define Paradox and dBASE tables. For more
information, see Appendix A, Using Database Desktop.
For SQL servers, use the tools provided with the server or the Database Desktop.
For example, for the Local InterBase Server or an InterBase Workgroup Server, use
Windows ISQL. For more information, see the Local InterBase Server Users Guide
and the InterBase Data Definition Guide.
The database exists on a desktop or LAN data source (Paradox or dBASE) and the
database will access it there. If the BDE and the data source are on the same machine
as the application, then the application is a standalone (not client/server) application.
The database exists on a desktop data source, and is being upsized to an SQL server.
This scenario is discussed in Appendix C, Using local SQL.
The database exists on an SQL server and the application will access it there. This is a
standard client/server application. For information specific to developing a client/
server application, Chapter 6, Building a client/server application.
Introduction
13
There are database and application tasks in each of these phases. Depending on the size
and scope of the development project, the database and application tasks may be
performed by different individuals or by the same individual. Often, one team or
individual will be responsible for the database tasks of the project, and another team or
individual will be responsible for the application tasks.
Figure 1.6
Development cycle
Design
Development
Implementation
cycle
Deployment
For client/server applications, the database and application tasks become more distinct,
since they run on different platforms, often with different operating systems (for
example, a Unix server and Windows 3.1 client).
When development responsibilities are thus divided it is important to clearly delineate
in the design phase which functions will be performed by the database server and
which will be performed by the client application. Usually, the functional lines are clear
cut. But database processes such as stored procedures can sometimes perform functions
that can also be performed by the client application. Depending on the expected
deployment configuration, application requirements, and other considerations, the
design can allocate such functions to either client or server.
It is also important to realize that database application development is by its nature an
iterative process. Users may not fully understand their own needs, or may define
additional needs as development proceeds. User interface elements are always refined
as they are used. Also, changing business needs will change requirements over time.
Generally, a number of iterations through the development cycle will be required before
an application can meet a significant portion of its requirements.
Design phase
The design phase begins with requirements definition. In consultation with
knowledgeable end users, define the functional specifications for the database and
applications. Determine which aspects of the functional requirements will be
implemented in the database design, and which aspects will be implemented in the
applications.
For client/server applications, often certain functions can be performed either by the
server or by the application; for example, a complex mathematical transform function
could be performed either by the client application or by a stored procedure on the
server. The hardware deployment configuration will generally determine whether such
14
functions are best performed on the server or client. For example, if the client platforms
are expected to be low-end desktop PCs, and the server platform is expected to be a
high-end workstation, then it will probably be best to run computation-intensive
functions on the server. If the hardware configuration changes, then it is possible to
move the function between client and server in a later iteration.
Implementation phase
In the implementation phase, you use Delphi to build and test the application conceived
in the design phase. During the implementation phase, you should use a duplicate data
source, that is, a data source that has the same essential structure as the production
database, but with a small subset of representative data. It is not recommended to
develop an application against a production database, since the untested application
may corrupt the data or otherwise interfere with normal database activities.
If your application will ultimately be deployed to use a desktop data source, make
copies of the required tables with the Database Desktop, and populate them with
representative dummy data.
If the application will ultimately be deployed to use a remote data source (an SQL
server), then you can take two approaches during the implementation phase:
Develop and test the application against a non-production database on the Local
InterBase Server.
Develop and test the application against a non-production database on the server.
The first approach has the advantage that is isolated on the development platform(s),
and so will not interfere with other server activities. It will not consume server resources
or increase network traffic. Its primary disadvantage is that only standard SQL server
features can be used and tested during this phase, if you are using a server other than
InterBase for the deployed application.
The second approach enables you to surface all server-specific features, but will
consume network and server resources during testing. This approach can be dangerous,
since it is conceivable that a programmer error could cause a server to crash during
testing.
Deployment phase
In the deployment phase, the client/server application is put to the acid test: it is handed
over to end users. To ensure that the applications basic functionality is error-free,
deploy a prototype application before attempting to deploy a production application.
Since the ultimate judges of an applications efficacy are its users, developers must be
prepared to incorporate changes to applications arising from their suggestions,
changing business needs, and for general enhancement (for example, for usability).
Sometimes application changes may require changes to the database, and conversely,
changes to the database may require application changes. For this reason, application
developers and database developers should work together closely during this phase. As
features and enhancements are incorporated into the application, the application moves
iteratively closer to completion.
Introduction
15
Deploying an application
Deploying an application means giving it to the end users, and providing the necessary
software they need to use the application in a production environment. Non-database
applications require only an .EXE file to runDelphi applications do not require a run
time interpreter or DLL.
Typically, when deploying a database application, you will create a package that
includes all the files that end users need to run the application and access data sources.
These files include
If you are distributing the files on disks, you will generally want to compress them with
a standard file compression utility, and provide the utility on the disk. You may also
want to build a simple installation application to install the files for your users. For
complex applications, you may want to use one of the many commercially-available
installation programs.
Important
Before distributing any files, ensure that you have the proper redistribution rights. As
described in the Delphi license agreement, Delphi provides distribution rights for the
BDE (including Paradox and dBASE support). Delphi Client/Server includes
distribution rights for Borland SQL Links for Windows. Licenses for distribution of the
Local InterBase Server are available from Borland.
For information on deploying support for remote server access, see Chapter 6, Building
a client/server application. For client/server applications, you also must ensure that
the necessary communications software (for example, TCP/IP interface) is installed on
the client platforms. This software is provided with databases servers. For more
information, see your server documentation.
16
required to run your application, but you must still distribute all the files in the
Redistributable BDE.
For example, if your application needs access only to Paradox files, you can advise your
users not to deploy the dBASE driver. The minimum BDE configuration for accessing a
Paradox database requires about 500 Kbytes.
Note
For more information on deployment, refer to the file DEPLOY.TXT installed to the
DELPHI\DOC directory by default.
Table 1.6
File name
Description
IDAPI01.DLL
IDBAT01.DLL
IDQRY01.DLL
IDASCI01.DLL
IDPDX01.DLL
IDDBAS01.DLL
IDR10009.DLL
ILD01.DLL
IDODBC01.DLL
ODBC.NEW
ODBCINST.NEW
TUTILITY.DLL
BDECFG.EXE
BDECFG.HLP
IDAPI.CFG
Language drivers
The BDE provides the ability to localize applications with language drivers. The
language driver DLL loads the drivers specified by Paradox or dBASE tables or in
IDAPI.CFG for server databases. The language drivers are files with extension .LD
installed to the LANGDRV sub-directory of the BDE directory.
Important
For language drivers to load correctly, the WIN.INI file must have the following entry,
assuming the default installation directory:
[Borland Language Drivers]
LDPath = C:\DELPHI\IDAPI\LANGDRV
Introduction
17
ODBC Socket
The BDE comes with an ODBC Socket. It has been certified with Microsofts 2.0 ODBC
Driver Manager. If you have a different version of the ODBC Driver Manager:
Back up your existing ODBC.DLL and ODBCINST.DLL
Copy the version 2.0 files, ODBC.NEW and ODBCINST.NEW, from your BDE
directory to your WINDOWS\SYSTEM directory.
Rename these files to ODBC.DLL and ODBCINST.DLL.
Note
18
The ODBC 2.0 Driver Manager does work with ODBC 1.x ODBC drivers.
Chapter
Chapter 2
This material assumes you know how to use Delphi; it tells you what to do to perform
certain tasks. For more details (that is, to find out why), follow the cross-references in the
For more information section that follows each example. In particular, see Chapter 3,
Using data access components and tools.
The tutorial consists of the following sections:
Building forms describes how to use the Database Form Expert to create database
forms, including single-table and master-detail forms. It also describes how to
enhance forms by adding components and code by hand.
Working with fields describes how to read and write field values, how to search for
values and do table lookups, and how to format data displayed to the user. It also
describes how to work with calculated fields.
Using queries and ranges describes how to use SQL queries and set ranges to select
a subset of the data in one or more tables.
Printing reports and forms describes how to print ReportSmith reports and Delphi
forms.
Building forms
The material in this section focuses on database issues. To learn about general
application building with Delphi, see the Users Guide. The forms described here are the
19
basis for a database application called MASTAPP, designed to meet the record-keeping
needs of the fictitious Marine Adventures & Sunken Treasures company (MAST).
MAST sells diving equipment and arranges diving expeditions. MASTAPP tracks
information about customers, orders, inventory, and vendors.
The tutorial starts with a simple codeless form for viewing and editing table data, and
works up to a full-featured invoice form containing several tables, data-aware
components, and other advanced Delphi features. All the forms, tables, and related files
are installed by default in C:\DELPHI\DEMOS\DB\MASTAPP. During a default
installation of Delphi, an alias, DBDEMOS, that points to the MASTAPP directory is
created for you, or you can create your own alias using the BDE configuration utility
(see Appendix B). The following figure shows the forms and tells where they are
described in this chapter:
Figure 2.1
Note
For general information about building Delphi forms, see the Users Guide.
MASTAPP aliases
All TTable and TQuery components used in example code in this chapter set their
DatabaseName property to DBDEMOS. In contrast, the complete demo in the MASTAPP
directory does the following to facilitate porting:
1 The main form (MAIN.PAS) has a TDatabase component with its AliasName property
set to DBDEMOS and DatabaseName property set to MAST.
2 All datasets on all forms have their Database properties set to MAST. Now all forms
can use a different BDE alias simply by changing the main forms TDatabase
components AliasName property.
20
What to do
1 Choose Help|Database Form Expert to open the Form Expert.
2 Specify a table, fields, and field layout as shown in the following figure. The Form
Expert creates the form.
3 Press F9 to run the form. Click the navigator control buttons to move through the
records in the table.
Figure 2.2
21
How it works
The Database Form Expert builds a single-table form to match your specifications, and
adds a tool bar of navigation controls. The form shown in the following figure is the
basis for the full-featured BRPARTS.DFM form in the MASTAPP application. The
important relationships in a data-aware form like this one are the links between the
underlying data, the nonvisual components, and the data controls that display data to
the user.
Figure 2.3
A single-table form
TDBNavigator control linked
to the table
The form contains one TTable component. The expert links it to the Parts table by setting
the properties listed in the following table. A TTable component establishes a connection
to a table in a database.
Table 2.1
Property
Value
Remarks
Active
False
DataBaseName
MAST
Name
TableName
Form1
PARTS.DB
The form contains one TDataSource component. The expert links it to the TTable
component by setting the properties listed in the following table. A TDataSource
component acts as a bridge between one dataset component (TTable in this case) and one
or more data-aware controls that provide a visible interface to data.
Table 2.2
22
Property
Value
Remarks
AutoEdit
True (default)
When AutoEdit is True, Delphi puts the TDataSource into Edit state
automatically when the user changes a value in a linked control.
To make a TDataSource read-only, or to control when to enter Edit state,
set AutoEdit to False.
Table 2.2
Property
Value
Remarks
DataSet
Name
Table1
DataSource1
The form contains one TDBGrid control. The expert links it to a TDataSource component
by setting the properties listed in the following table. By default, a TDBGrid includes all
the fields (columns) in a table. To limit the columns displayed by a TDBGrid, doubleclick on its associated TTable component to invoke the Fields Editor (see page 30).
Table 2.3
Property
Value
Remarks
DataSource
DataSource1
The form contains one TDBNavigator control. This control moves a tables current record
pointer forward or backward, starts Insert or Edit state, posts new or modified records,
etc. The expert links this control to the Parts table by setting the properties listed in the
following table.
Table 2.4
Property
Value
Remarks
DataSource
DataSource1
VisibleButtons
The expert does more than create a form and components. It also generates a line of code
to open the table at run time in case you do not activate the table at design time. For
example, the expert creates TTable components with the Active property set to False.
Thats why the various TDBEdit controls arent displaying data. You could set Active to
True, and the controls would display data from the first record. Instead, the Form
Expert generates the following code to open the table at run time.
procedure TEditPartsForm.FormCreate(Sender: TObject);
begin
Table1.Open;
end;
This code is hooked to the forms OnCreate event, so Delphi executes it before creating
the form. As a result, the table is opened before the form is displayed.
Note
Code created by the Form Expert is like code you type yourself. If you rename
components created by the expert, be sure to update your source file everywhere the
renamed component occurs. Name changes to components that Delphi originates (for
example, in the type declaration) are changed automatically for you by Delphi.
23
What to do
When you use the Database Form Expert, building a master-detail form is much like
building a single-table form (for details, see page 21).
24
6 Press F9 to run the form. Click the navigator control buttons to move through the
records in the table.
Figure 2.4
How it works
The expert builds a master-detail form much as it builds a single-table form (for details,
see page 22). It creates TTable components and TDataSource components for the master
table and the detail table and links them to the underlying data by setting properties.
The expert creates controls to display the data from each table, and sets properties to
link them to the corresponding TDataSource component. The expert also creates a
TDBNavigator control linked to the master table.
25
Figure 2.5
A master-detail form
Detail TTable and
TDataSource
TDBNavigator control,
linked to master table
What distinguishes a master-detail form is the link between the tables. For each record
in the master table, the form displays all corresponding records in the detail table. Such
a link is called a one-to-many relationship (see page 76 for more information). Delphi
creates this relationship by setting properties of the TTable component linked to the
detail table.
Table 2.5
Property
Remarks
IndexFieldNames
Specifies the columns used to order the records in the table. You can also specify an
index by name using the IndexFields property. For more information, see page 74.
Specifies which fields in the master table to link to. Use a semicolon to separate
multiple field names. For more information, see page 76.
Specifies the TDataSource component linked to the master table. This data source
provides a restricted view of the data in the detail table based on the values of the
fields specified in MasterFields. For more information, see page 76.
MasterFields
MasterSource
The following table lists important properties for each component and control.
Table 2.6
Component
Property
Value
Remarks
TTable
(master)
Active
False
DataBaseName
MAST
Name
TableName
CUSTOMER.DB
DataSet
Name
Active
False
TDataSource
(master)
TTable (detail)
26
Table 2.6
Component
Property
Value
Remarks
DataBaseName
MAST
IndexFieldNames
CustNo
MasterFields
CustNo
MasterSource
Name
TableName
ORDERS.DB
DataSet
Name
TDBGrid
(master)
TDBGrid
(detail)
DataSource
DataSource
TDBNavigator
DataSource
TDataSource
(detail)
What to do
1 Choose Help|Database Form Expert to open the Form Expert.
2 In the first panel, specify a master-detail form that uses TTable objects.
27
3 In subsequent panels, specify the master table (CUSTOMER.DB), fields (use them
all), and field layout (horizontal).
4 Specify the detail table (ORDERS.DB), fields (all), and field layout (horizontal).
5 Specify fields to link the master and detail tables: choose CustNo for the
IndexFieldNames property and link the CustNo fields in each table. For details, see
step 6 on page 25.
6 Tell the expert to create the form.
7 Move components around to make room at the bottom of the form. You may have to
change the Align property of some controls from alClient to alNone.
8 Place a TTable component, a TDataSource component, and a TDBGrid component as
shown in the following figure. (The TTable and TDataSource are on the Data Access
components page; the TDBGrid is on the Data Controls page.) These components
represent the third table in the one-many-many link. In this example its the Items
table.
28
9 To create the link, set properties of these new components as shown in the following
table.
Figure 2.6
One-many-many form
TTable3, linked
to ITEMS.DB
TDataSource3,
linked to TTable3
TDBGrid3,
linked to
TDataSource3
Table 2.7
Component
Property
Value
Remarks
TTable
(third table)
Active
True
DataBaseName
MAST
IndexFieldNames
OrderNo
MasterFields
OrderNo
MasterSource
Name
TDataSource
(third table)
TDBGrid
(third table)
TableName
ITEMS.DB
DataSet
Name
DataSource
29
How it works
A one-many-many form links data from three tables. The first table in the link (the
Customer table) is the master table. The second table (Orders) does double duty: its the
detail table for the first table and the master table for the third table. The third table
(Items) is a detail table for the second table. In this example, you can link these tables
quickly and easily by setting properties because secondary indexes were specified for
the tables when they were created.
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields
of CUSTOMER.DB in a grid. For detailed instructions, see page 21.
2 To make the grid display data at design time, use the Object Inspector to change the
TTable components Active property to True.
30
3 Open the Fields Editor by double-clicking the TTable component. By default, the list
of fields is empty, as shown in the following figure:
Figure 2.7
4 Click Add to open a dialog box listing the fields in the Customer table. By default, all
fields are selected. Click CustNo to select it, then control-click to select the Company,
Phone, and LastInvoiceDate fields, then click OK to confirm your choices and close
the dialog box. In the form, the grid changes: instead of displaying all fields, it
displays the only the fields you selected.
Figure 2.8
5 Use the Fields Editor to change the field order as follows: Click LastInvoiceDate in
the list of fields, then drag it to the third place in the list, between Company and
Phone. In the form, the grid changes to display columns in their new order.
6 Close the Fields Editor by choosing Close from the Control menu.
7 Press F9 to run the form. The grid displays the four fields in the order you specified.
How it works
This form is the basis for the full-featured CUSTORD.DFM form in the MASTAPP
application. By choosing fields in the Fields Editor, you can tell a TTable component
which fields to make available to the components that are linked to it. In effect, the
Fields Editor changes the logical structure of the table. The Fields Editor also addsTField
objects to the units type section (for example, CustCustNo: TFloatField;). More
accurately, it adds a descendant of the TField type appropriate for the data type of the
field. For example, when you add the CustNo field to the data set, Delphi adds a
TFloatField object; when you add the Company field, Delphi adds a TStringField, and so
on. This tutorial uses the general term TField when the specific data type is unimportant.
31
Note
Specifying a list of fields in the Database Form Expert is not the same as using the Fields
Editor to define a dataset. The expert places components and controls in a form to create
an initial layout, but you must use the Fields Editor to specify the fields in a data set. Use
TField components, not visual controls, to access fields programmatically.
Understanding the relationship between a TTable component, TField components, and
data-aware controls is crucial to building database applications with Delphi.
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields
of CUSTOMER.DB in a grid. For detailed instructions, see page 21. (If youre working
through these examples in sequence, you can use the form from the previous
example and skip to step 5.)
2 To make the grid display data at design time, use the Object Inspector to change the
TTable components Active property to True. This step is optional: it lets you see what
happens to the form as you use the Fields Editor.
3 Open the Fields Editor by double-clicking the TTable component. By default, the list
of fields is empty.
4 Click Add to open a dialog box listing the fields in the Customer table. By default, all
fields are selected. Control-click to select only the CustNo, Company, Phone, and
LastInvoiceDate fields, then click OK to confirm your choices and close the dialog
box. In the form, the grid changes: instead of displaying all fields, it displays the only
the fields you selected.
5 Click the CustNo field in the Fields Editors field list and view the properties and
values displayed in the Object Inspector. (To open the Object Inspector, choose
View|Object Inspector.) Notice that the components Name property is
Table1CustNo. Delphi generates this name automatically by appending the field
name to the name of the associated TTable component. Use this name to refer to the
TField component in code.
32
6 Change the Align property from taRightJustify (the default) to taCenter. In the form,
the grid changes: values in the CustNo column are centered.
Figure 2.9
How it works
When you select a field listed in the Fields Editor, you can use the Object Inspector to set
an invisible TField components properties, just as you would a visible control. Note that
a fields display attributes are properties of the TField component, not of the control that
displays the value! You only have to set a property once for the TField component.
Linked controls use the settings automatically. This is a guiding principle of Delphi
database applications: use TField components to work with database fields.
The following table lists important TField design-time properties.
Table 2.8
Property
Remarks
Alignment
Calculated
DisplayLabel
DisplayWidth
DisplayFormat
and EditMask
FieldName
Index
Name
ReadOnly
Visible
33
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields
of CUSTOMER.DB in a grid. For detailed instructions, see page 21.
2 Use the Object Inspector to change the forms Name property to TutorialForm.
3 Open the Fields Editor by double-clicking the TTable component. By default, the list
of fields is empty.
4 Click Add to open a dialog box listing the fields in the Customer table. By default, all
fields are selected. Control-click to select only the CustNo, Company, Phone, and
LastInvoiceDate fields, then click OK to confirm your choices and close the dialog
box. The Fields Editor remains open.
5 Place a button control and a standard edit box anywhere in the panel that contains
the TDBNavigator control (you may need to resize the panel), then set the edit box
Name property to OutputField.
6 Attach the following code to the buttons OnClick event:
procedure TTutorialForm.Button1Click(Sender: TObject);
begin
OutputField.Text := Table1Company.Value;
end;
7 Press F9 to run the form. Click a field in the grid, then click the button. The text in the
edit control displays the value of the Company field for the current record.
How it works
The code in step 7 does a simple assignment: the edit controls Text property gets the
value of the TField component named Table1Company, where the TFields value is the
value of the corresponding field in the current record of the table.
Note
In code, refer to a TField by its component name, dont use the name of the field in the
table. For example, use Table1Company, not Company.
You can assign the TField components value directly to the Text property because
Table1Company is of type TStringField. An edit boxs Text property and a TStringFields
34
Value property are of compatible types, so you dont need to do a conversion. However,
the following code generates a type mismatch error at compile time, because
Table1CustNo is of type TFloatField.
OutputField.Text := Table1CustNo.Value; {Causes a type mismatch error.}
To display a numeric fields value in an edit box, convert the value as follows.
OutputField.Text := Table1CustNo.AsString;
This code uses the TField property AsString to read the field value and convert it to a
string before assigning it to the edit boxs Text property. TField components have the
following properties for converting values: AsBoolean, AsDateTime, AsFloat, AsInteger,
and AsString.
The following code shows examples of how to read field values, display them in edit
boxes, and assign them to variables.
var
CustNoDouble: Double;
CustNoInt: Integer;
CustNoString: String;
begin
{Display field value in edit control.}
OutputField.Text := Table1Company.Value; {Compatible types, no conversion.}
OutputField.Text := Table1CustNo.AsString; {Convert field value to compatible type.}
{Assign field value to variables.}
CustNoDouble := Table1CustNo.Value; {Compatible types, no conversion.}
CustNoInt := Table1CustNo.AsInteger; {Convert field value to compatible type.}
CustNoString := Table1CustNo.AsString; {Convert field value to compatible type.}
end;
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields
of CUSTOMER.DB in a grid. For detailed instructions, see page 21. (If youre working
through these examples in sequence, you can use the form from the previous
example and skip to step 5.)
2 Use the Object Inspector to change the forms Name property to TutorialForm.
35
3 Open the Fields Editor by double-clicking the TTable component. By default, the list
of fields is empty.
4 Click Add to open a dialog box listing the fields in the Customer table. By default, all
fields are selected. Control-click to select only the CustNo, Company, Phone, and
LastInvoiceDate fields, then click OK to confirm your choices and close the dialog
box.
5 Place a button control and a standard edit box anywhere in the panel that contains
the TDBNavigator control (you may need to resize the panel).
6 Attach the following code to the buttons OnClick event to change a companys name
in the CUSTOMER table based on the current value in the standard edit box:
procedure TTutorialForm.Button1Click(Sender: TObject);
begin
Table1.Edit;
Table1Company.Value := Edit1.Text;
Table1.Post;
end;
7 Press F9 to run the form. Type a value into the edit box, then click the button and
notice the value of the Company field in the current record in the grid. It should be
the same as the text in the edit box.
How it works
The code in step 6 does three things: it puts the table into Edit state, assigns a value to
the Company field of the current record, and posts the modified record back to the table
(which takes the table out of Edit state). As this example shows, there is a difference
between editing field values interactively using controls and editing field values in
code. By default, the AutoEdit property of a TDataSource component is set to True. A
user can type into a data-aware control to that data source and modify the value
immediately. When the user moves off that record, changes are posted automatically.
But, to modify TField component values based on values entered in a standard edit
control, or to perform table modifications in code, you need to explicitly switch to Edit
state, set the value, and post changes.
Note
You can safely call Edit even if youre already in Edit or Insert state. In such cases, calls
to Edit have no effect.
The TField component and the value you assign must be compatible. In the example, the
edit controls Text property is compatible with Table1Company, a TStringField.
However, the following code generates a type mismatch error at compile time, because
Table1CustNo is a TFloatField.
Table1CustNo.Value := OutputField.Text; {Causes a type mismatch error.}
To assign the text of an edit control to a numeric field, convert the text as follows.
Table1CustNo.AsString := OutputField.Text;
This code uses the TField property AsString to convert the text before assigning it
toTable1CustNo. TField components have the following properties for converting
values: AsBoolean, AsDateTime, AsFloat, AsInteger, and AsString.
36
The following code shows examples of how to assign field values, converting them if
necessary.
Table1CustNo.Value := 12340;
Table1CustNo.AsInteger := 4321;
Table1CustNo.AsString := 5678;
Table2CustNo.Value := Table1CustNo.Value; {Assign value of one TField to another.}
Table2.Fields[0] := Table1.Fields[0]; {Also assign value of one TField to another.}
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields
of ITEMS.DB in a grid. For detailed instructions, see page 21.
2 Use the Object Inspector to change the forms Name property to OrderForm, change
the TTable components Name property to Items, and change the TTable components
Active property to True.
3 In this forms CreateForm procedure, change Table1 to Items.
4 Open the Fields Editor by double-clicking the TTable component. By default, the list
of fields is empty.
5 Click Add to open a dialog box listing the fields in the Items table. By default, all fields
are selected. Click OK to add all the fields to the data set and close the dialog box. In
the form, the grid displays a column for each field in the data set.
37
6 Click Define to open the Define Field dialog box, then enter specifications for a
calculated field named ExtPrice as shown in the following figure:
Figure 2.10
7 Click OK to accept values and close the dialog box. In the form, an empty ExtPrice
column appears in the grid. You may have to scroll the grid to the right to see it.
8 Click Define again, then enter specifications for a second calculated field named
ItemsSellPrice. It, too, should be given a CurrencyField data type. Click OK.
9 Double click the OnCalcFields event of the TTable component to open the code
window, then enter the following code.
procedure TOrderForm.ItemsCalcFields(DataSet: TDataSet);
begin
if Parts.FindKey([ItemsPartNo]) then
begin
ItemsDescription.Value := PartsDescription.Value;
ItemsSellPrice.Value := PartsListPrice.Value;
end;
ItemsExtPrice.Value := ItemsQty.Value *
ItemsSellPrice.Value * (100 - ItemsDiscount.Value) / 100;
end;
10 Type F9 to run the form. The ExtPrice column fills with calculated values. A
calculated field does not display values at design time.
How it works
This form is the basis for the full-featured EDORDERS.DFM form in MASTAPP. It
demonstrates the two key aspects of creating a calculated field in Delphi: adding the
calculated field to a TTable components data set, and writing code to handle the TTable
components OnCalcFields event. Delphi sends an OnCalcFields event each time the
cursor for that table changes. The calculation accesses data through the TField
components created in the Fields Editor, not the controls placed in the form.
The example attaches code to the OnCalcFields event to update the value of the
calculated field. You can use the OnCalcFields event for other purposes; for example, to
do a lookup into another table, perform a complex calculation, or do real-time data
38
acquisition. However, in an OnCalcFields event, you can only assign values to calculated
fields.
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields
of CUSTOMER.DB. Specify a vertical layout and labels aligned left. For detailed
instructions, see page 21.
2 Use the Object Inspector to change the forms Name property to EdCustForm, change
the TTable components Name property to Cust, and change the TTable components
Active property to True. In the form, notice the Tax Rate fields display format
(example: 8.5).
3 In this forms CreateForm procedure, change Table1 to Cust.
4 Open the Fields Editor by double-clicking the TTable component. By default, the list
of fields is empty.
5 Click Add to open a dialog box listing the fields in the Customer table. By default, all
fields are selected. Click OK to add all the fields to the data set and close the dialog
box.
6 In the Field Editors list of fields, choose Tax Rate, then use the Object Inspector to
view the properties of the TFloatField named CustTaxRate. The DisplayFormat
property is blank.
7 In the Object Inspector, enter the following value for the DisplayFormat property of
CustTaxRate: 0.00%. In the form, the Tax Rate fields display format changes
(example: 8.50%).
39
How it works
Delphi provides several properties that specify a fields display format. The following
table lists some of the most frequently-used properties. Any data-aware control linked
to a TField component uses the TFields display properties.
Table 2.9
Property
Remarks
Alignment
Currency
Displays field value left justified, right justified, or centered within a data-aware control.
True, numeric field displays monetary values.
False, numeric field does not display monetary values.
Specifies the format of data displayed in a data-aware component. For more
information about valid patterns, see the online help.
The number of characters that a grid column uses to display this field in a grid.
Provides control over input characters for some fields types as they are displayed and
edited; for example, in working with commonly formatted values such as dates and
telephone numbers.
The name of the field in the underlying table; for example, CustNo.
The fields logical position in the data set (first position = 0).
Formed by appending the field name to the name of the TTable component. Example:
Given a TTable name of Customer and a field name of CustNo, the TFields name is
CustomerCustNo. This name is used for programmatic access to fields properties (for
example, CustomerCustNo.Value).
When True, the corresponding field can appear in linked grids.
DisplayFormat
DisplayWidth
DisplayFormat
and EditMask
FieldName
Index
Name
Visible
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields
of CUSTOMER.DB. (If youre working through these examples in sequence, you can
use the form from the previous example and skip to step 6.) Specify a vertical layout
and labels aligned left. For detailed instructions, see page 21.
2 Use the Object Inspector to change the forms Name property to EdCustForm, change
the TTable components Name property to Cust, and change the TTable components
Active property to True. In the form, notice the Phone field displays U.S phone
numbers (example: 808-555-0269).
3 In this forms CreateForm procedure, change Table1 to Cust.
40
4 Open the Fields Editor by double-clicking the TTable component. By default, the list
of fields is empty.
5 Click Add to open a dialog box listing the fields in the Customer table. By default, all
fields are selected. Click OK to add all the fields to the data set and close the dialog
box.
6 In the Fields Editors list of fields, choose Phone, then use the Object Inspector to view
the events of the TStringField named CustPhone.
7 Double-click the OnGetText event to open the code window, then add code to handle
the event as follows.
procedure TEdCustForm.CustPhoneGetText(Sender: TField;
var Text: OpenString; DisplayText: Boolean);
begin
if DisplayText then
begin
Text := CustPhone.Value;
Delete(Text, 4, 1);
Insert('(', Text, 1);
Insert(')', Text, 5);
end;
end;
In this sample code, DisplayText is True, meaning youre not actually editing the field in
question, but modifying the display of the field. When DisplayText is True, characters
that would be invalid for the user to enter, such as parentheses in this case, can be
inserted into the field for display purposes only.
8 Press F9 to run the form. The Phone fields display format changes (example:
(808)555-0269).
How it works
Use the OnGetText event to format field values. Delphi calls a TField components
OnGetText method whenever its about to display the value of a field onscreen, for
example, when redrawing a data-aware component. Delphi ignores a TField
components DisplayFormat property when you add code to its OnGetText event.
In this example, CustPhoneGetText copies the phone number string to variable Text, then
uses the Insert and Delete procedures to place parentheses around the first three digits.
This gives U.S. phone numbers a more traditional format: (713) 555-1212, instead of
713-555-1212 as stored in the file. The DisplayText property is True when a TField is
displaying data but is not available for editing. When a TField is in Edit state, DisplayText
is False.
Note
41
What to do
This example shows how to display a record in the Customer table by searching for a
customer number entered by the user.
1 Use the Database Form Expert to build a single-table form that displays fields from
CUSTOMER.DB. Specify a vertical layout and labels aligned left. For detailed
instructions, see page 21.
2 Place a button control in the panel that contains the TDBNavigator control.
3 Double-click the button to open a code window, then add code to handle the buttons
OnClick event as follows.
procedure TForm2.Button1Click(Sender: TObject);
var UserCustNo: String;
begin
UserCustNo := InputBox('Search', 'Enter a Customer Number:', ' ');
if not Table1.FindKey([UserCustNo]) then
MessageDlg('Not found.', mtInformation, [mbOK], 0);
end;
4 Add the Dialogs unit to the uses clause of your form unit. The InputBox function used
in the previous step resides in the Dialogs unit.
5 Press F9 to run the form. Click the button and enter a number in the input dialog box
(try 1560). If that number is a customer number in the table, Delphi displays the
corresponding record. Otherwise, it displays a dialog box.
How it works
FindKey takes an array, where each array value represents a value to search for in the
corresponding key field in the table. FindKey searches for the first array value in the first
key field, the second array value in the second key field, and so on. In this example, the
array contains one value, so FindKey searches for it in the first key field of the table,
which is CustNo.
The following example shows how to search for the name Frank P. Borland in a table
where the key fields are LastName, FirstName, and MiddleInital.
begin
if not Table1.FindKey(['Borland', 'Frank', 'P.']) then
MessageDlg('Not found.', mtInformation, [mbOK], 0);
end;
42
43
What to do (list)
The following steps describe how to create the drop-down list labeled Terms in the
Edorders form in MASTAPP. The Terms field specifies the payment terms for an order.
Allowed values are Prepaid, Net 30, and COD.
44
Property
Value
Remarks
DataField
DataSource
Items
Terms
OrdersSource
Prepaid
Net 30
COD
The name of the field in the table this control is linked to.
The TDataSource component this control is linked to.
Each list item is on its own line. In other words, when you enter list
items, press Enter after each item.
How it works
A TDBComboBox control works like a standard combo box control, but its linked to a
field in a table. Its Items property stores the list items. When the user chooses an item
from the list, that value is assigned to the corresponding data field in the current record.
You can add list items by hand at design time or specify them in code at run time.
What to do (lookup)
The following steps describe how to create the drop-down lookup list labeled SoldBy in
the Edorders form in MASTAPP. The combo box labeled SoldBy displays a list of
employee names, but it stores employee numbers. When the user chooses a name from
the list, Delphi looks up the corresponding employee number and writes that value to
the Orders tables.
Property
Value
Remarks
DataSource
DataField
LookupSource
OrdersSource
EmpNo
EmpsSource
LookupDisplay
FullName
LookupField
EmpNo
How it works
The TDBLookupCombo control dynamically accesses a column from a table (specified in
LookupDisplay) and displays it to the user. When the user chooses an item, Delphi finds
45
the value in the table specified in LookupSource. Then it reads the value of the field
specified in LookupField. Finally, it assigns that value to the field specified in DataField in
the table specified in DataSource.
In this example, Delphi fills a drop-down box with employee names from the FullName
field of the Employee table. FullName is a calculated field defined for the Employee table.
To see how FullName is calculated, select Employee TTable component, then examine its
OnCalcFields event. When the user chooses a name from the list, Delphi reads the
EmpNo field to get the employee number for that name. Then it assigns that value to the
EmpNo field of the Orders table.
What to do
1 Open the MASTAPP project, then open the Edorders form.
2 Double-click the TTable component named Orders to open the Fields Editor.
3 In the Fields Editors list of fields, click SaleDate, then use the Object Inspector to
view the events of the TDateTimeField component named OrdersSaleDate.
4 Double-click the OnValidate event to open the code window, then add code to handle
the OnValidate event as follows.
procedure TOrderForm.OrdersSaleDateValidate(Sender: TField);
begin
if OrdersSaleDate.Value > Now then
raise Exception.Create('Cannot enter a future date');
end;
How it works
To check field values after the user enters them, write code to handle the OnValidate
event of the appropriate TField component. The example code raises an exception if the
date a user enters is later than todays date. Make sure all fields are either initialized to a
valid value in an OnNewRecord event, or have their TField Required properties set to True.
46
1 Use Form Expert to build a form based on a query of the Customer table (for detailed
instructions, see page 21). Use only the CustNo, Company, and State fields (for
simplicity). Specify a grid layout.
2 Use the Object Inspector to set the TQuery components Active property to True. The
grid displays the query results (by default, the query selects all records).
3 Set the TQuery components Active property to False. The grid empties. (Active must
be False to change the query.)
4 Use the Object Inspector to display the TQuery components SQL property, and type
the following statement after the last line in the SQL statement in the String List
Editor window:
where State = "HI"
47
6 Set the TQuery components Active property to True. The grid displays only those
records where the value of the State field is HI. (Optional: Press F9 to run the form.)
Figure 2.12
How it works
Delphi reads the SQL statements assigned to the TQuery components SQL property and
passes them to the server without any intermediate interpretation. (Use double quotes
in SQL statements, not single quotes as in Pascal code.) The server executes the query
and returns the results to Delphi, and Delphi displays the result set in the grid.
Note:
1 Use Form Expert to build a form based on a query of the Customer table (for detailed
instructions, see page 21). Use only the CustNo, Company, and State fields (for
simplicity). Specify a grid layout. If youre working through these examples in
sequence, you can use the form from the previous example.
48
2 Use the Object Inspector to display the TQuery components SQL property, and type
the following statement after the last line in the SQL statement in the String List
Editor window:
where State = :State
3 The SQL statement in the previous step contains the field name State and the
parameter State (a parameter is an arbitrary string preceded by a colon). Click OK to
close the String List Editor.
4 Right-click the TQuery component, then choose Define Parameters from the pop-up
menu. The Define Parameters dialog box opens, ready for you to assign a field type
and a value to the parameter State.
5 Choose a field type of String, and enter a value of FL, then click OK to close the dialog
box.
Figure 2.13
6 Set the TQuery components Active property to True. The grid displays the query
results (all records where State = FL).
7 Place a button control in the panel that contains the TDBNavigator control.
8 Double-click the button to open a code window, then write the following code to
handle its OnClick event.
procedure TForm2.Button1Click(Sender: TObject);
begin
Query1.DisableControls;
try
Query1.Active := False;
Query1.Params[0].AsString := 'HI';
Query1.Active := True;
finally
Query1.EnableControls;
end;
end;
9 Press F9 to run the form, then click the button. The grid displays the query results (all
records where State = HI).
How it works
In a SQL statement, a string preceded by a colon (like :State in the example) represents a
parameter. At design time, Delphi recognizes parameters and displays them in the
49
Define Parameters dialog box. Then at run time, it assigns the specified values to the
corresponding parameters.
You can assign values to query parameters at run time using the Params property. It
stores parameter values in an array, where an index of 0 represents the first parameter,
an index of 1 represents the second parameter, and so on. So, this statement assigns the
value HI to the first parameter.
Query1.Params[0].AsString := 'HI';
You need to set the TQuery components Active property to False before setting
parameter values, then set it to True again to update the query. The calls to
DisableControls and EnableControls, respectively, freeze and restore display capabilities of
controls linked to the TQuery component. This disables data-aware control while the
result set is updated.
Setting a range
This example explains how to select a set of records by setting a range (also called a
filter). To set a range on a Paradox or dBASE table, work with keyed (indexed) fields. To
set a range on a SQL table, you can specify the fields to be used as indexes using the
IndexFieldNames property.
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields
of CUSTOMER.DB in a grid. For detailed instructions, see page 21.
2 Use the Object Inspector to change the forms Name property to CustForm, change
the TTable components Name property to Cust, and change the TTable components
Active property to True.
3 In this forms CreateForm procedure, change Table1 to Cust.
4 Open the Fields Editor by double-clicking the TTable component. By default, the list
of fields is empty.
5 Click Add to open a list box for the fields in the Items table. By default, all fields are
selected. Click OK to add all the fields to the data set and close the list box. Close the
Fields Editor. In the form, the grid displays a column for each field in the data set.
6 Place a button control in the panel that contains the TDBNavigator control.
50
7 Double-click the button to open a code window, then add code to handle the buttons
OnClick event as follows.
procedure CustForm.Button1Click(Sender: TObject);
begin
Cust.DisableControls;
try
Cust.SetRangeStart;
CustCustNo.Value := 3000;
Cust.KeyExclusive := False;
Cust.SetRangeEnd;
CustCustNo.Value := 4000;
Cust.KeyExclusive := True;
Cust.ApplyRange;
finally
Cust.EnableControls;
end;
end;
8 Press F9 to run the form, then click the button. The grid displays records for customer
numbers from 3,000 to 3,999.
How it works
This example sets a range to include records for customer numbers from 3,000 to 3,999.
Setting a range on a table affects the values displayed in data-aware components linked
to that table. Thats why the routine in step 7 begins by calling Cust.DisableControls and
ends by calling Cust.EnableControls. DisableControls disables the display capabilities of
controls linked to the specified table; in effect, it freezes them. EnableControls restores the
controls to an active state.
Important
51
To run reports, the TReport component needs to locate the RS_RUN directory. You can
put the RS_RUN directory in your DOS PATH, or you can put an EXEpath = entry in
the Delphi RS_RUN.INI file.
1 Choose File|New Form to open the Browse Gallery, then choose Blank form and
click OK to create a blank form.
2 Place a TReport component anywhere in the form. (The TReport component is on the
Data Access components page.)
3 Use the Object Inspector to set the TReport components properties as shown in the
following table.
Table 2.12
Property
Value
Remarks
Preview
True
ReportDir
C:\DELPHI\
DEMOS\DB\
MASTAPP\REPORTS
CUSTLIST.RPT
ReportName
How it works
The Run method of TReport opens the run-time version of ReportSmith, which prints or
displays a report as specified by the TReport components properties. When youre
designing a form, you can double-click a TReport component to open the full version of
ReportSmith and build a report.
52
How it works
The Print method for the TForm class prints a form as it appears onscreen.
53
54
Chapter
Chapter 3
This chapter describes how to use key Delphi features and tools when building database
applications, including:
This chapter provides an overview and general description of data access components
in the context of application development. For in-depth reference information on
database components, methods, and properties, see the online VCL reference.
55
TComponent
TSession
TDatabase
TDataSource
TDataSet
TDBDataSet
TField
TTable
TStringField
TIntegerField
TQuery
This chapter describes most of these components and the tools that Delphi provides to
work with them. The TQuery component is described in Chapter 5, Using SQL in
applications. The TDatabase component is described in Chapter 6, Building a client/
server application.
56
TSession methods
Method
Returns
GetAliasNames
GetAliasParams
GetDatabaseNames
GetDriverNames
GetDriverParams
GetTableNames
For more information on these methods, see the online VCL Reference.
Using datasets
TTable and TQuery component classes are descended from TDataSet through
TDBDataSet. These component classes share a number of inherited properties, methods,
and events. For this reason, it is convenient to refer to them together as datasets, when
the discussion applies to both TTable and TQuery.
This section describes the features of datasets that are common to TTable and TQuery. A
subsequent section discusses features unique to TTable. Chapter 5, Using SQL in
applications describes features unique to TQuery.
Note
57
Dataset states
A dataset can be in the following states, also referred to as modes:
Table 3.2
Dataset states
State
Description
Inactive
Browse
Edit
Insert
SetKey
CalcFields
An application can put a dataset into most states by calling the method corresponding to
the state. For example, an application can put Table1 in Insert state by calling
Table1.Insert or Edit state by calling Table1.Edit. A number of methods return a dataset
to Browse state, depending on the result of the method call. A call to Cancel will always
return a dataset to Browse state.
CalcFields mode is a special case. An application cannot explicitly put a dataset into
CalcFields mode. A dataset automatically goes into CalcFields mode when its
OnCalcFields event is called. In OnCalcFields, an exception will occur if an application
attempts to assign values to non-calculated fields. After the completion of OnCalcFields,
the dataset returns to its previous mode.
The following diagram illustrates the primary dataset states and the methods that cause
a dataset to change from one mode to another.
58
Figure 3.2
Inactive
Insert
Append
Insert
Post
(Unsuccessful)
Close
Open
SetKey *
EditKey *
Browse
Post
(Successful)
Delete
Edit
SetKey
Cancel
GotoKey*, FindKey*
Post
Cancel
Delete
Post (Successful)
Edit
* TTable only
Post (Unsuccessful)
The State property specifies the current state of a dataset. The possible values
correspond to the above states and are dsInactive, dsBrowse, dsEdit, dsInsert, dsSetKey, and
dsCalcFields.
The OnStateChange event of TDataSource is called whenever the state of a data sources
dataset changes. For more information, see Using TDataSource events on page 78.
Both of these statements open the dataset and put it into Browse state.
Similarly, there are two ways to close a dataset:
Set the datasets Active property to False, either at design time through the Object
Inspector, or programmatically at run time. For example,
Query1.Active := False;
59
Navigating datasets
There are two important concepts in understanding how Delphi handles datasets:
cursors and local buffers. Each active dataset has a cursor, which is essentially a pointer to
the current row in the dataset. A number of rows of data before and after the cursor are
fetched by Delphi into the local buffer. Delphi will always fetch a number of rows into
the local buffer sufficient to display the current row, plus an additional number of rows
to reduce the refresh time as the user scrolls up or down in the dataset:
Table 3.3
Method or property
Description
First method
Last method
Next method
Prior method
BOF property
EOF property
MoveBy(n) method
Many of these methods are encapsulated in the TDBNavigator component. For more
information on TDBNavigator, see Chapter 4, Using Data Controls.
Similarly, the Prior method moves the cursor up (backward) by one row in the dataset.
For example, to move to the previous row in the table, a buttons OnClick text could be:
Table1.Prior
60
Similarly, the Last method moves to the last row in the dataset. To move to the last row
in the table, a buttons OnClick text could be:
Table1.Last
After this code executes, BOF is False, even if there are no records before the current
row. Once the table is open, Delphi can only determine BOF when an application
explicitly calls First or a call to Prior fails. Similarly, Delphi can only determine EOF
when an application explicitly calls Last or a call to Next fails.
The following code sample demonstrates a common technique for using the BOF
property:
while not Table1.BOF do
begin
DoSomething;
Table1.Prior;
end;
In this code sample, the hypothetical function DoSomething is called on the current
record and then on all the records between the current record and the beginning of the
dataset. The loop will continue until a call to Prior fails to move the current record back.
At that point, BOF will return a value of True and the program will break out of the
loop.
To improve performance during the iteration through the table, call the DisableControls
method before beginning the loop. This prevents data controls from displaying the
iteration through the table, and speeds up the loop. After the loop completes, call the
EnableControls method. Make sure to use a try...finally...end statement with the call to
EnableControls in the finally clause. Otherwise, an exception will leave the applications
controls inactive.
The same principles apply to the EOF property, which returns a value of True after:
An application opens an empty dataset
A call to a Tables Last method
A call to a Tables Next fails
61
The following code sample provides a simple means of iterating over all the records in a
dataset:
Table1.DisableControls;
try
Table1.First;
while not Table1.EOF do
begin
DoSomething;
Table1.Next;
end;
finally
Table1.EnableControls;
end.
In this case, the Next method and the EOF property are used together to reach the end of
the dataset.
Caution
If code like this were executed, the application would appear to freeze, since the same
action would be endlessly performed on the first record of the dataset, and the EOF
property would never return a value of True.
On an empty table, opening or executing any navigational methods will return True for
both BOF and EOF.
When using this function, keep in mind that datasets are fluid entities, and the record
which was five records back a moment ago may now be only four records back, or six
records, or an unknown number of records, because multiple users may by
simultaneously accessing the database and modifying its data.
Note
62
Method
Description
Edit
Puts the dataset into Edit state. If a dataset is already in Edit or Insert state, a call toEdit has
no effect.
Posts any pending data, moves current record to the end of the dataset, and puts the
dataset in Insert state.
Posts any pending data, and puts the dataset in Insert state.
Attempts to post the new or altered record to the database. If successful, the dataset is put
in Browse state; if unsuccessful, the dataset remains in its current state.
Cancels the current operation and puts the dataset into Browse state.
Deletes the current record and puts the dataset in Browse state.
Append
Insert
Post
Cancel
Delete
Post is not called implicitly by the Close method. Use the BeforeClose event to post any
pending edits explicitly.
Editing records
A dataset must be in Edit state before an application can modify records in the
underlying table. The Edit method puts a dataset in Edit state. When in Edit state, the
63
Post method will change the current record. If a dataset is already in Edit state, a call to
Edit has no effect.
The Edit and Post methods are often used together. For example,
Table1.Edit;
Table1.FieldByName('CustNo').AsString := '1234';
Table1.Post;
The first line of code in this example places the dataset in Edit mode. The next line of
code assigns the string 1234 to the CustNo field. Finally, the last line posts, or writes to
the database, the data just modified.
Deleting records
The Delete method deletes the current record from a dataset and leaves the dataset in
Browse mode. The cursor moves to the following record.
Canceling changes
An application can undo changes made to the current record at any time, if it has not yet
directly or indirectly called Post. For example, if a Table is in Edit state, and a user has
changed the data in one or more fields, the application can return the record back to its
original values by calling the Tables Cancel method. A call to Cancel always returns a
dataset to Browse state.
64
Method
Description
AppendRecord([array of values])
Table 3.5
Method
Description
InsertRecord([array of values])
SetFields([array of values])
Each method takes a comma-delimited array of values as its argument, where each
value corresponds to a column in the underlying table. The values can be literals,
variables, null, or nil. If the number of values in an argument is less than the number of
columns in a dataset, then the remaining values are assumed to be null.
For un-indexed tables, AppendRecord adds a record to the end of the table and
InsertRecord inserts a record after the current cursor position. For indexed tables, both
methods places the record in the correct position in the table, based on the index. In both
cases, the methods move the cursor to the records position.
SetFields assigns the values specified in the array of parameters to fields in the dataset.
The application must first perform an Edit to put the dataset in Edit state. To modify the
current record, it must then perform a Post.
Since these methods depend explicitly on the structure of the underlying tables, an
application should use them only if the table structure will not change.
For example, the COUNTRY table has columns for Name, Capital, Continent, Area, and
Population. If Table1 were linked to the COUNTRY table, the following statement
would insert a record into the COUNTRY table:
Table1.InsertRecord(['Japan', 'Tokyo', 'Asia']);
The statement does not specify values for Area and Population, so it will insert Null
values for these columns. The table is indexed on Name, so the statement would insert
the record based on the alphabetic collation of Japan.
To update the record, an application could use the following code:
Table1.Edit;
Table1.SetRecord(nil, nil, nil, 344567, 164700000);
Table1.Post;
This code assumes that the cursor will be positioned on the record just entered for Japan.
It assigns values to the Area and Population fields and then posts them to the database.
Notice the three nils that act as place holders for the first three columns, which are not
changed.
65
UpdateMode specifies which columns are included in the WHERE clause of an UPDATE
statement. If Delphi cannot find a record with the original values in the columns
specified (if another user has changed the values in the database), Delphi will not make
the update and will generate an exception.
The UpdateMode property may have the following values:
WhereAll (the default): Delphi uses every column to find the record being updated.
This is the most restrictive mode.
WhereKeyOnly: Delphi uses only the key columns to find the record being updated.
This is the least restrictive mode and should be used only if other users will not be
changing the records being updated.
WhereChanged: Delphi uses key columns and columns that have changed to find the
record being updated.
For example, consider a COUNTRY table with columns for NAME (the key), CAPITAL,
and CONTINENT. Suppose you and another user simultaneously retrieve a record with
the following values:
NAME = Philippines
CAPITAL = Nairobi
CONTINENT = Africa
Both you and the other user notice that the information in this record is incorrect and
should be changed. Now, suppose the other user changes CONTINENT to Asia,
CAPITAL to Manila, and posts the change to the database. A few seconds later, you
change NAME to Kenya and post your change to the database.
If your application has UpdateMode set to WhereKey on the dataset, Delphi compares the
original value of the key column (NAME = Philippines) to the current value in the
database. Since the other user did not change NAME, your update occurs. You think the
record is now [Kenya, Nairobi, Africa] and the other users thinks it is
[Philippines, Asia," Manila]. Unfortunately, it is actually [Kenya, , Asia,
Manila], which is still incorrect, even though both you and the other user think you
have corrected the mistake. This problem occurred because you had UpdateMode set to
its least restrictive level, which does not protect against such occurrences.
If your application had UpdateMode set to WhereAll, the Delphi would check all the
columns when you attempt to make your update. Since the other user changed
CAPITAL and CONTINENT, Delphi would not let you make the update. When you
retrieved the record again, you would see the new values entered by the other user and
realize that the mistake had already been corrected.
Bookmarking data
It is often useful to mark a particular location in a table so that you can quickly return to
it when desired. Delphi provides this functionality through bookmark methods. These
methods enable you to put a bookmark in the dataset, and quickly return to it later.
66
Notice the careful positioning of statements in this code. If the call to GetBookmark fails,
controls are not disabled. If it succeeds, the bookmark is always freed and controls are
always enabled.
67
the table or the data it contains might have changed. Refreshing a table can sometimes
lead to unexpected results. For example, if a user is viewing a record that has been
deleted, then it will seem to disappear the moment the application calls Refresh.
Similarly, data can appear to change while a user is viewing it if another user changes or
deletes a record after the data was originally fetched and before a call to Refresh.
Dataset events
Event
Description
BeforeOpen, AfterOpen
BeforeClose, AfterClose
BeforeInsert, AfterInsert
BeforeEdit, AfterEdit
BeforePost, AfterPost
BeforeCancel, AfterCancel
BeforeDelete, AfterDelete
OnNewRecord
OnCalcFields
For more information on these events and methods of the TDataSet component, refer to
the online VCL reference.
Abort a method
To abort a method such as an Open or Insert, raise an exception or call the Abort
procedure in any of the Before methods (BeforeOpen, BeforeInsert, and so on). For
example, the following code confirms a delete operation:
procedure TForm1.TableBeforeDelete (Dataset: TDataset);
begin
if MessageDlg('Delete This Record?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
Abort;
end;
Using OnCalcFields
The OnCalcFields event is used to set the values of calculated fields. The AutoCalcFields
property determines when OnCalcFields is called. If AutoCalcFields is True, then
OnCalcFields is called when:
The dataset is opened.
Focus moves from one visual component to another, or from one column to another
in a DBDataGrid.
68
Using TTable
TTable is one of the most important database component classes. Along with the other
dataset component class, TQuery, it enables an application to access a database table.
This section describes the most important properties that are unique to TTable.
Neither of these properties can be changed when a table is openthat is, when the
tables Active property is set to a value of True.
69
Searching a table
TTable has a number of functions that will search for values in a database table:
Goto functions
Find functions
The easiest way to search for values is with the Find functions, FindKey and FindNearest.
These two functions combine the functionality of the basic Goto functions, SetKey,
GoToKey, and GoToNearest, which are described first.
In dBASE and Paradox tables, these functions can search only on index fields. In SQL
tables, they can search on any fields, if the field name is specified in the IndexFieldNames
property of the TTable. For more information, see Indexes on page 74.
To search a dBASE or Paradox table for a value in a non-index field, use SQL SELECT
syntax with a TQuery component. For more information on using SQL and TQuery
components, see Chapter 5, Using SQL in applications.
The first line of code after begin puts Table1 in SetKey state. This indicates that the
following assignment to the tables Fields property specifies a search value. The first
column in the table, corresponding to Fields[0], is the index. In this example, the value
the application searches for is determined by the text the user types into the edit control,
Edit1. Finally, GoToKey performs the search, moving the cursor to the record if it exists.
GoToKey is a Boolean function that moves the cursor and returns True if the search is
successful. If the search is unsuccessful, it returns False and does not change the position
of the cursor. For example,
70
Table1.SetKey;
Table1.Fields[0].AsString := 'Smith';
if not Table1.GotoKey
then ShowMessage('Record Not Found');
If the search does not find a record with a first column matching Smith, the
ShowMessage function displays a dialog box with the Record Not Found message.
If a table has more than one key column, and you want to search for values in a sub-set
of the keys, set KeyFieldCount to the number of columns on which you are searching. For
example, if a table has three columns in its primary key, and you want to search for
values in just the first, set KeyFieldCount to 1. For tables with multiple-column keys, you
can search only for values in contiguous columns, beginning with the first. That is, you
can search for values in the first column, or the first and second, or the first, second, and
third, but not just the first and third.
GoToNearest is similar, except it finds the nearest match to a partial field value. It can be
used only for columns of string data type. For example,
Table1.SetKey;
Table1.Fields[0].AsString := 'Sm';
Table1.GoToNearest;
If a record exists with Sm as the first two characters, the cursor will be positioned on
that record. Otherwise, the position of the cursor does not change and GoToNearest
returns False.
If it is not searching on the primary index of a local table, then an application must
specify the column names to use in the IndexFieldNames property or the name of the
index to use in the IndexName property of the table. For example, if the CUSTOMER
table had a secondary index named CityIndex on which you wanted to search for a
value, you would need to set the value of the tables IndexName property to CityIndex.
You could then use the following syntax when you searching on this field:
Table1.IndexName := 'CityIndex';
Table1.Open;
Table1.SetKey;
Table1.FieldByName('City').AsString := Edit1.Text;
Table1.GoToNearest;
Because indexes often have non-intuitive names, you can use the IndexFieldNames
property instead to specify the names of indexed fields.
Each time an application calls SetKey, it must set all the field values for which it will
search. That is, SetKey clears any existing values from previous searches. To keep
previous values, use EditKey.
For example, to extend the above search to find a record with the specified city name in
a specified country, an application could use the following code:
Table1.EditKey;
Table1.FieldByName('Country').AsString := Edit2.Text;
71
FindNearest is similar to GotoNearest, in that it will move the cursor to the row with the
nearest matching value. This can be used for columns of string data type only.
Both of these functions work by default on the primary index column. To search the
table for values in other indexes, you must specify the field name in the tables
IndexFieldNames property or the name of the index in the IndexName property.
Note
With Paradox or dBASE tables, these methods work only with indexed fields. With SQL
databases, they can work with any columns specified in the IndexFieldNames property.
72
SetRangeStart indicates that subsequent assignments to field values will specify the start
of the range of rows to include in the application. SetRangeEnd indicates that subsequent
assignments will specify the end of the range of rows to include. Any column values not
specified are not considered. The corresponding methods EditRangeStart and
EditRangeEnd indicate to keep existing range values and update with the succeeding
assignments.
ApplyRange applies the specified range. If SetRangeStart has not been called when
ApplyRange is called, then the start range will be the beginning of the table; likewise, if
SetRangeEnd has not been called, the end range will be the end of the table. CancelRange
cancels the range filter and includes all rows in the table.
The SetRange function combines SetRangeStart, SetRangeEnd, and field assignments into
a single statement that takes an array of values as its argument.
Note
With Paradox or dBASE tables, these methods work only with indexed fields. With SQL
databases, they can work with any columns specified in the IndexFieldNames property.
For example, suppose there is a form with a TTable component named Cust, linked to
the CUSTOMER table. CUSTOMER is indexed on its first column (CustNo). The form
also has two Edit components named StartVal and EndVal, and you have used the Fields
Editor to create a TField component for the CustNo column. Then these methods could
be applied (for example, in a buttons OnClick event) as follows:
Cust.SetRangeStart;
CustCustNo.AsString := StartVal.Text;
Cust.SetRangeEnd;
if EndVal.Text <> '' then
CustCustNo.AsString := EndVal.Text;
Cust.ApplyRange;
Notice that this code first checks that the text entered in EndVal is not null before
assigning any values to Fields. If the text entered for StartVal is null, then all records
from the beginning of the table will be included, since all values are greater than null.
However, if the text entered for EndVal is null, then no records will be included, since
none are less than null.
This code could be re-written using the SetRange function as follows:
if EndVal.Text <> '' then
Cust.SetRange([StartVal.Text], [EndVal.Text]);
Cust.ApplyRange;
73
Table1.SetRangeStart;
Table1.FieldByName('LastName').AsString := 'Smith';
Table1.SetRangeEnd;
Table1.ApplyRange;
This will include all records where LastName greater than or equal to Smith. The
value specification could also be:
Table1.FieldByName('LastName').AsString := 'Sm';
This would include records which have LastName greater than or equal toSm. The
following would include records with a LastName greater than or equal to Smith and
a FirstName greater than or equal to J:
Table1.FieldByName('LastName').AsString := 'Smith';
Table1.FieldByName('FirstName').AsString := 'J';
Indexes
An index determines how records are sorted when a Delphi application displays data.
By default, Delphi displays data in ascending order, based on the values of the primary
index column(s) of a table.
Delphi supports SQL indexes, maintained indexes for Paradox tables, and maintained
.MDX (production) indexes for dBASE tables. Delphi does not support:
Non-maintained indexes on Paradox tables.
Non-maintained or .NDX indexes of dBASE tables.
The IndexFieldCount property for a dBASE table opened on an expression index.
The GetIndexNames method returns a list of the names of available indexes on the
underlying database table. For Paradox tables, the primary index is unnamed and
therefore not returned by GetIndexNames. To use a primary index on a Paradox table, set
the corresponding TTables IndexName to a null string.
IndexFields is an array of field names used in the index. IndexFieldCount is the number of
fields in the index. IndexFieldCount and IndexFields are read-only properties that are
available only during run-time.
Use the IndexName property to sort or search a table on an index other than the primary
index. In other words, to use the primary index of a table, you need do nothing with the
IndexName property. To use a secondary index, however, you must specify it in
IndexName.
For tables in a SQL database, the IndexFieldNames property specifies the columns to use
in the ORDER BY clause when retrieving data. The entry for this property is a
74
semicolon-delimited list of field names. Records are sorted by the values in the specified
fields. Sorting can be only in ascending order. Case-sensitivity depends on the server
being used.
For example, to sort customer records in an SQL table by zip code and then by customer
number, enter the following for the IndexFieldNames property:
ZipCode;CustNo
For Paradox and dBASE tables, Delphi will pick an index based on the columns
specified in IndexFieldNames. An error will occur if you specify a column or columns that
cannot be mapped to an existing index.
The IndexName and IndexFieldNames properties are mutually exclusive. Setting one
property clears the value of the other.
75
When CanModify is False, then the table is read-only, and the dataset cannot be put into
Edit or Insert state. When CanModify is True, the dataset can enter Edit or Insert state.
Even if CanModify is True, it is not a guarantee that a user will be able to insert or update
records in a table. Other factors may come in to play, for example, SQL access privileges.
The Field Link Designer provides a visual way to link master and detail tables. The
Available Indexes combo box shows the currently selected index by which to join the
two tables. For Paradox tables, this will be Primary by default, indicating that the
primary index of the detail field will be used. Any other named indices defined on the
table will be shown in the drop-down list.
76
Select the field you want to use to link the detail table in the Detail Fields list, the field to
link the master table in the Master Fields list, and then choose Add. The selected fields
will be displayed in the Joined Fields list box. For example,
OrderNo -> OrderNo
For tables on a database server, the Available Indexes combo box will not appear, and
you must select the detail and master fields to join manually in the Detail Fields and
Master Fields list boxes.
Using TDataSource
TDataSource acts as a conduit between datasets and data-aware controls. Often the only
thing you will do with a TDataSource component is to set its DataSet property to an
appropriate dataset object. Then you will set data controls DataSource property to the
specific TDataSource. You also use TDataSource components to link datasets to reflect
master-detail relationships.
77
Similarly, OnStateChange can be used to enable or disable buttons or menu items based
on the current state. For example,
procedure Form1.DataSource1.StateChange(Sender: TObject);
begin
InsertBtn.Enabled := (Table1.State = dsBrowse);
78
79
Fields Editor
The Fields list box displays the names of persistent TField components associated with
the data access component. The first time you invoke the Fields Editor on a particular a
TTable or TQuery component, the Fields list is empty because all TFields are dynamically
created. If any TField objects are listed in Fields, then data-aware components can only
display data from those fields. You can drag and drop individual TField objects within
the Field list box to change the order in which fields are displayed in controls, like
TDBGrid, that display multiple columns.
80
The navigator buttons at the bottom of the Fields Editor window enable you to scroll
through the records one at a time, and to jump to the first or last record of the dataset if
it is active.
The Add button enables you to see a list of column names in the physical dataset but not
already included in the Fields list, and to create new TField components for them.
The Define button enables you to create calculated fields. Fields created this way are
only for display purposes. The underlying physical structure of the table or data is not
changed.
The Remove button deletes the selected TFields. The Clear All button deletes all the
TFields shown in the Fields list.
The Available Fields list box shows all database fields that do not have persistent TFields
instantiated. Initially, all available fields are selected. Use the mouse to select specific
fields and then choose OK. The selected fields move to the Fields list box in the main
Fields Editor window.
Fields moved to the Available Fields list become persistent. Each time the dataset is
opened, Delphi verifies that each non-calculated field exists or can be created from data
in the database. If it cannot, an exception is raised, warning you that the field is not
valid, and the dataset is not opened.
81
82
For example, on Form1, the OnCalcFields event for a TTable component named Table1 is
TForm1.Table1CalcFields
1 Select the TTable or TQuery component from the Object Inspector drop-down list.
2 Choose the Object Inspector Events tab.
3 Double-click the OnCalcFields property to bring up or create a CalcFields procedure
for the TTable or TQuery component.
4 Write the code that sets the values and other properties of the calculated field as
desired.
TField properties
Property
Purpose
Alignment
Displays contents of field left justified, right justified, or centered within a data-aware
component.
True, field value can be calculated by a CalcFields method at run time.
False, field value is determined from the current record.
True, numeric field displays monetary values.
False, numeric field does not display monetary values.
Specifies the format of data displayed in a data-aware component.
Specifies the column name for a field in a TDBGrid.
Specifies the width, in characters, of a grid column that display this field.
Specifies the edit format of data in a data-aware component.
Limits data-entry in an editable field to specified types and ranges of characters, and
specifies any special, non-editable characters that appear within the field (hyphens,
parentheses, etc.).
Specifies the actual name of column in the physical table from which the TField
component derives its value and data type.
Specifies the order of the field in a dataset.
Specifies the maximum numeric value that can be entered in an editable numeric
field.
Calculated
Currency
DisplayFormat
DisplayLabel
DisplayWidth
EditFormat
EditMask
FieldName
Index
MaxValue
83
Table 3.7
Property
Purpose
MinValue
Name
ReadOnly
Specifies the minimum numeric value that can be entered in an editable numeric field.
Specifies the component name of the TField component within Delphi.
True: Field can be displayed in a component, but cannot be edited by a user.
False: Field can be displayed and edited.
Specifies the maximum number of characters that can be displayed or entered in a
string-based field, or the size of byte and var byte fields.
Long integer bucket available for programmer use in every component as needed.
True: Field is displayed by a TDBGrid component. User-defined components can also
make display decisions based on this property.
False: Field is not displayed by a TDBGrid component.
Size
Tag
Visible
Not all properties are available to all TField components. For example, a component of
type TStringField does not have Currency, MaxValue, or DisplayFormat properties. A
component of type TFloatField does not have a Size property.
Boolean properties, those that can be toggled between True and False, can be changed
by double-clicking the property in the Object Inspector. Other properties require you to
enter values or pick from drop-down lists in the Object Inspector. All TField properties
can also be manipulated programmatically.
While the purpose of most properties is straight-forward, some properties, such as
Calculated, require additional programming steps to be useful. Others, such as
DisplayFormat, EditFormat, and EditMask, are interrelated; their settings must be
coordinated. For more information about using the Calculated property, see
Programming a calculated field. For more information about using DisplayFormat,
EditFormat, and EditMask, see Formatting fields.
84
To use one of the sample masks, select it in the Sample Masks list box. You can then
customize the mask as desired by editing it in the Input Mask text field. You can test the
allowable input in the Test Input field. For more information, see the online Help.
Note
For the TStringField, the EditMask property is also used as a display format.
Formatting fields
Delphi provides built-in display and edit format routines and intelligent default
formatting for TField components. These routines and formats require no action on the
programmers part. Default formatting conventions are based on settings in the
Windows Control Panel. For example, using default Windows settings in the United
States, a TFloatField column with the Currency property set to True sets the DisplayFormat
property for the value 1234.56 to $1234.56, while the EditFormat is 1234.56. Only format
properties appropriate to the data type of a TField component are available for a given
component.
All TField component formatting is performed by the following routines:
Table 3.8
Routine
Used by . . .
FormatFloat
FormatDateTime
FormatInteger
TFloatField, TCurrencyField
TDateField, TTimeField, TDateTimeField
TIntegerField, TSmallIntField, TWordField
The format routines use the International settings specified in the Windows Control
Panel for determining how to display date, time, currency, and numeric values. You can
edit the DisplayFormat and EditFormat properties of a TField component to override the
default display settings for a TField, or you can handle the OnGetText and OnSetText
events for a TField to do custom programmatic formatting.
Event
Purpose
OnChange
OnGetText
OnSetText
OnValidate
OnGetText and OnSetText events are primarily useful to programmers who want to do
custom formatting that goes beyond Delphis built-in formatting functions, FormatFloat,
FormatDate, and so on.
TFields have a FocusControl method that enables an event to set focus to the first dataaware control associated with the TField. This is especially important for record-oriented
85
TField Type
AsString
AsInteger
AsFloat
AsDateTime
AsBoolean
TStringField
String type by
definition
Convert to Integer
if possible
Convert to Float if
possible
Convert to Date if
possible
TIntegerField
TSmallIntField
TWordField
TFloatField
TCurrencyField
TBCDField
TDateTimeField
TDateField
TTimeField
Convert to String
Integer type by
definition
Convert to Float
Not Allowed
Convert to
Boolean if
possible
Not Allowed
Convert to String
Round to nearest
integer value
Float type by
definition
Not Allowed
Not Allowed
Convert to String.
Content depends
on DisplayFormat
of Field
Not Allowed
DateTime type
by definition
Zero date or time
if not specified
Not Allowed
TBooleanField
Convert to String
True or False
Convert to String
(Generally only
makes sense for
TMemoField)
Not Allowed
Convert Date to
number of days
since 01/01/0001
Convert Time to
fraction of 24
hours
Not Allowed
Not Allowed
Not Allowed
Not Allowed
Not Allowed
Boolean type by
definition
Not Allowed
TBytesField
TVarBytesField
TBlobField
TMemoField
TGraphicField
The conversion functions can be used in any expression involving a TField component,
on either side of an assignment statement. For example, the following statement
converts the value of the TField named MyTableMyField to a string and assigns it to the
text of the Edit1 control:
Edit1.Text := MyTableMyField.AsString;
Conversely, this statement assigns the text of the Edit1 control to the TField as a string:
MyTableMyField.AsString := Edit1.Text;
86
Any properties of TField components that are available from the Object Inspector can
also be accessed and adjusted programmatically as well. For example, this statement
changes field ordering by setting the Index property of CustTableCountry to 3:
CustTableCountry.Index := 3;
Conversely, you can assign a value to a column a dataset in Edit mode by assigning the
appropriate Fields property to the value of a component. For example,
CustTable.Fields[6].AsString := Edit1.Text;
To make these assignments occur, you must enter them in an event such as a TButton
OnClick event, or an edit controls OnEnter event.
87
This method requires you to know the name of the column you want to access or if your
application works with tables that are not available at design time.
For example, the following statement assigns the value of the Country column in the
CustTable table to Edit2:
Edit2.Text := CustTable.FieldByName('Country').AsString;
Conversely, you can assign a value to a column a dataset in Edit mode by assigning the
appropriate FieldByName property to the value of a component. For example,
CustTable.FieldByName('Country').AsString := Edit2.Text;
To make these assignments occur, you must enter them in an event such as a buttons
OnClick or a Edit components OnExit event.
For more information about creating and using report variables, see Creating Reports.
Some important methods of TReport are listed in the following table:
Table 3.11
88
Method
Purpose
Run
RunMacro
Run a report.
Send a macro command to ReportSmith.
Table 3.11
Method
Purpose
Connect
SetVariable
ReCalcReport
Using TBatchMove
TBatchMove enables you to perform operations on groups of records or entire tables. The
primary uses of this component are
Downloading data from a server to a local data source for analysis or other
operations.
Upsizing a database from a desktop data source to a server. For more information on
upsizing, see Appendix C, Using local SQL.
TBatchMove is powerful because it can create tables on the destination that correspond to
the source tables, automatically mapping the column names and data types as
appropriate.
Two TBatchMove properties specify the source and a destination for the batch move
operation: Source specifies a dataset (a TQuery or TTable component) corresponding to
an existing source table. Destination specifies a TTable component corresponding to a
database table. The destination table may or may not already exist.
Property
Purpose
batAppend
Append records to the destination table. The destination table must already exist.
This is the default mode.
Update records in the destination table with matching records from the source table.
The destination table must exist and must have an index defined to match records.
If a matching record exists in the destination table, update it. Otherwise, append
records to the destination table. The destination table must exist and must have an
index defined to match records.
Create the destination table based on the structure of the source table. The
destination table must not already existif it does, the operation will delete it.
Delete records in the destination table that match records in the source table. The
destination table must already exist and must have an index defined.
batUpdate
batAppendUpdate
batCopy
batDelete
89
Table 3.13
To batch move data to an SQL server database, you must have that database server and
Delphi Client/Server edition with the appropriate SQL Link installed. For more
information, see the SQL Links for Windows Users Guide:
Physical data type translations from Paradox tables to tables of other driver types
From Paradox
type
To dBASE
type
To Oracle
type
To Sybase
type
To InterBase
type
To Informix
type
Alpha
Number
Money
Date
Short
Memo
Binary
Formatted memo
OLE
Graphic
Long
Time
DateTime
Bool
AutoInc
Bytes
BCD
Character
Float {20.4}
Float {20.4}
Date
Number {6.0}
Memo
Memo
Memo
OLE
Binary
Number {11.0}
Character {>8}
Character {>8}
Bool
Number{11.0}
Memo
N/A
Character
Number
Number
Date
Number
Long
LongRaw
LongRaw
LongRaw
LongRaw
Number
Character {>8}
Date
Character {1}
Number
LongRaw
N/A
VarChar
Float
Money
DateTime
SmallInt
Text
Image
Image
Image
Image
Int
Character {>8}
DateTime
Bit
Int
Image
N/A
Varying
Double
Double
Date
Short
Blob/1
Blob
Blob
Blob
Blob
Long
Character {>8}
Date
Character {1}
Long
Blob
N/A
Character
Float
Money {16.2}
Date
SmallInt
Text
Byte
Byte
Byte
Byte
Integer
Character {>8}
DateTime
Character
Integer
Byte
N/A
Table 3.14
Physical data type translations from dBASE tables to tables of other driver types
From dBASE
type
To Paradox
type
To Oracle
type
To Sybase
type
To InterBase
type
To Informix
type
Character
Number
others
Float
Date
Memo
Bool
Lock
OLE
Alpha
Short
Number
Number
Date
Memo
Bool
Alpha {24}
OLE
Character
Number
Number
Number
Date
Long
Character {1}
Character {24}
LongRaw
VarChar
SmallInt
Float
Float
DateTime
Text
Bit
Character {24}
Image
Varying
Short
Double
Double
Date
Blob/1
Character {1}
Character {24}
Blob
Character
SmallInt
Float
Float
Date
Text
Character
Character
Byte
90
Table 3.14
Physical data type translations from dBASE tables to tables of other driver types (continued)
From dBASE
type
To Paradox
type
To Oracle
type
To Sybase
type
To InterBase
type
To Informix
type
Binary
Bytes
Binary
Bytes
LongRaw
LongRaw
Image
Image
Blob
Blob
Byte
Byte (only for
temp tables)
Table 3.15
Physical data type translations from InterBase tables to tables of other driver types
From Interbase
type
To Paradox
type
To dBASE
type
To Oracle
type
To Sybase
type
To Informix
type
Short
Long
Float
Double
Char
Varying
Date
Blob
Blob/1
Short
Number
Number
Number
Alpha
Alpha
DateTime
Binary
Memo
Number {6.0}
Number {11.0}
Float {20.4}
Float {20.4}
Character
Character
Date
Memo
Memo
Number
Number
Number
Number
Character
Character
Date
LongRaw
Long
Small Int
Int
Float
Float
VarChar
VarChar
DateTime
Image
Text
SmallInt
Integer
Float
Float
Character
Character
DateTime
Byte
Text
By default TBatchMove matches columns based on their position in the source and
destination tables. That is, the first column in the source is matched with the first column
in the destination, and so on.
To override the default column mappings, use the Mappings property. This is a list of
column mappings (one per line) in one of two forms. To map the column, ColName, in
the source table to the column of the same name in the destination table:
ColName
Or, to map the column named SourceColName in the source table to the column named
DestColName in the destination table:
DestColName = SourceColName
If source and destination column data types are not the same, TBatchMove will perform
a best fit. It will trim character data types, if necessary, and attempt to perform a
limited amount of conversion if possible. For example, mapping a CHAR(10) column to
a CHAR(5) column will result in trimming the last five characters from the source
column.
As an example of conversion, if a source column of character data type is mapped to a
destination of integer type, TBatchMove will convert a character value of 5 to the
corresponding integer value. Values that cannot be converted will generate errors. See
Handling batch move errors on page 92.
91
You can also execute a batch move at design time by right clicking the mouse on a
TBatchMove component and choosing Execute. The MoveCount property keeps track of
the number of records that were moved when a batch move is executed.
92
The application must include the header files that reference the BDE: DBIPROCS.PAS
and DBITYPES.PAS. Then the code can make direct calls to the BDE application
programming interface.
BDE function calls often require parameters to specify the action to be performed.
Delphi provides access to these through the following properties of dataset components:
DBHandle is the handle for the database to which they are connected.
Handle is the handle for the underlying cursor on the database.
DBLocale and Locale are used for ANSI/OEM conversion for localization of
applications.
After performing a BDE call directly, it is a good idea to call Refresh to ensure that all
data-aware components are synchronized with their datasets.
Application examples
This section provides some brief examples of specific database tasks, illustrating some of
the material presented in the preceding sections.
1 Place two TTable, two TDataSource, and two TDBDataGrid components on a form.
2 Set the properties of the first TTable component as follows:
DatabaseName: DBDEMO (the alias for the directory with the MAST database).
TableName: CUSTOMER (the table containing customer records).
Name: CustTable (for ease-of-use).
3 Name the first TDataSource component CustDataSource, and set its Dataset
property to CustTable. Set the DataSource property of DBGrid1 to
CustDataSource. When you activate CustTable (by setting its Active property to
True), the grid displays the data in the CUSTOMER table.
4 Analogously, set the properties of the second TTable component as follows:
DatabaseName: DBDEMO.
TableName: ORDERS (the table containing order records).
Name: OrdTable (for ease-of-use).
5 Name the second TDataSource component OrdDataSource, and set its Dataset
property to OrdTable. Set the DataSource property of DBGrid2 to
OrdDataSource. When you activate OrdTable (by setting its Active property to
True), the grid displays the data in the ORDERS table.
93
6 Compile and run the application now. The form displays data from each table
independently and should look something like this:
Figure 3.8
Sample form
7 The next step is to link the ORDERS table (the master table) to the CUSTOMER table
(the detail table) so that the form displays only the orders placed by the current
customer. To do this, exit the application, return to design mode, and set the
MasterSource property of OrdTable to CustDataSource.
8 In the Object Inspector, click on the ellipsis button to the right of the MasterFields
property of OrdTable. The Field Link Designer dialog box will open.
In the Available Indexes field, choose ByCustNo to link the two tables by the
CustNo field.
Select CustNo in both the Detail Fields and Master Fields field lists.
Click on the Add button to add this join condition. In the Joined Fields list,
CustNo -> CustNo will appear.
Choose OK to commit your selections and exit the Field Link Designer.
If you run the application now, you will see that the tables are linked together, and that
when you move to a new record in the CUSTOMER table, you see only those records in
the ORDERS table that belong to the current customer.
The MasterSource property specifies the TDataSource from which OrdTable will take its
master column values. This limits the records it retrieves, based on the current record in
CustTable. To do this, you must specify for OrdTable:
The name of the column that links the two tables. The column must be present in
each table, and must be identically named.
The index of the column in the ORDERS table that will be linked to the CUSTOMER
table.
In addition, you must ensure that the ORDERS table has an index on the CustNo field.
Since it is a primary index, there is no need to specifically name it, and you can safely
leave the IndexName field blank in both tables. However, if the table were linked
through a secondary index, you must explicitly designate that index in the IndexName
property.
In this example, the CUSTOMER table has a primary index on the CustNo column, so
there is no need to specify the index name. However, the ORDERS table does not have a
94
primary index on CustNo, so you must explicitly declare it in the IndexName property, in
this case ByCustNo
Note
You can also set the IndexFieldNames property to CustNo, and the correct index will be
supplied for you.
Once the second TDataSource is assigned to a valid dataset, both forms will remain
synchronized.
The TWOFORMS.DPR example in \DELPHI\DEMOS\DB\TWOFORMS
demonstrates how to work with multiple forms and a single dataset. The program
opens the COUNTRY table and shows the Name, Capital, and Continent fields on one
form, and the Area and Population fields on a second form. A button on the first form
opens the second form. Both forms have TDBNavigator components, so you can
navigate through the table. The forms look like this:
Figure 3.9
Two forms
1 Place a TTable, a TDataSource, a TButton, three TDBEdit, and three TLabel components
on a form.
95
When you are creating the second form, you might find it helpful to temporarily create a
TTable component and link the data source to it. This enables you to design the form
using live data, and gives you access to a list of field names for each edit control. Once
you have the form set up properly, you can delete the TTable component and at run time
reconnect the data source to a table on a separate form.
Once you have built the second form, go back to the first form and add DETAILS to the
uses clause in the form units implementation part, and create the following event
handler for the OnClick event of the Detail button:
procedure TForm1.DetailClick(Sender: TObject);
begin
DetailView.DataSource1.DataSet := Table1;
DetailView.Visible := True;
end;
This code first assigns the data source on the second form to the table in the first form.
Once this connection is made, then the data source on the second form is live. That is,
it will act exactly like the data source on the first form. Then it makes the form visible.
Now, connect the navigators on each form to the appropriate data source.
When you run the program, open the second form by clicking on the Detail button.
Notice that whether you use the navigator in either form, the edit controls on the other
form remain synchronized with the current record.
Close the application and add two more lines of code to the second forms unit. This
code is called in response to a click on the OK button:
procedure TDetailView.BitBtn1Click(Sender: TObject);
begin
DataSource1.DataSet := nil;
Close;
end;
96
This code sets the dataset to nil whenever the second form is closed. While not
necessary, this ensures that the hidden detail view is not responding to events.
97
98
Chapter
Chapter 4
To display and edit data from a database, use the components on the Data Controls
page of the Component palette. Data controls include components such as TDBGrid for
displaying and editing all specified records and fields in a table, and TDBNavigator for
navigating among records, deleting records, and posting records when they change.
Figure 4.1
The following table summarizes the data controls in order from left to right as they
appear on the Component palette:
Table 4.1
Data controls
Data control
Description
TDBGrid
TDBNavigator
TDBText
TDBEdit
TDBMemo
TDBImage
TDBListBox
TDBComboBox
99
Table 4.1
Data control
Description
TDBCheckBox
Displays a check box. If the value in the indicated column of the current record
matches the text of the check boxs ValueChecked property, the box is checked.
Offers a mutually exclusive set of options to enter into a specific column in the
current data record in the form of radio buttons.
Displays a list of items from which a user can update a column in the current data
record. The list of items is looked up in a specific column in another dataset.
Combines a TDBEdit control with a dropdown version of TDBLookupList. The
application user can update a field in the current database by typing a value or by
choosing a value from the drop-down list that is looked up in a specific column in
another dataset.
TDBRadioGroup
TDBLookupList
TDBLookupCombo
Most data controls are data-aware versions of standard components. Some, such as
TDBGrid and TDBNavigator, are data-aware, but differ from standard components in
significant, useful ways. A data-aware control derives display data from a database
source outside the application, and can also optionally post (or return) data changes to a
data source. Data controls are data-aware at design time, meaning that when you connect
a component to an active data source while building an application, you can
immediately see live data in the controls. You can use the Fields Editor to scroll through
records at design time to verify that your application is making the right database
connections without requiring you to compile and run the application, but you cannot
modify data at design time.
This chapter describes basic features common to all Data Control components, then
describes how and when to use individual components.
100
2 Set the DataSource property to the name of a TTable or TQuery component already on
the form. You can type the name or choose it from the drop-down list.
3 Set the DataField property to the name of a TField component. You can type the field
name or choose it from the drop-down list.
Note
Two data controls, TDBGrid and TDBNavigator, access all available TField components
within a dataset, and therefore do not have DataField properties. For these controls, omit
step 3.
When a data control is associated with a dataset, its Enabled property determines if its
attached TDataSource component receives data from mouse, keyboard, or timer events.
Controls are also disabled if the Enabled property of TDataSource is False, or if the Active
property of the dataset is False.
Updating fields
Most data controls can update fields by default. Update privileges depend on the status
of the controls ReadOnly property and underlying TFields and datasets CanModify
property. ReadOnly is set to False by default, meaning that data modifications can be
made.
In addition, the data source must be in Edit state if updates are to be permitted. The data
source AutoEdit property, set to True by default, ensures that the dataset enters Edit
mode whenever an attached control starts to modify data in response to keyboard or
mouse events.
In all data controls except TDBGrid, when you modify a field, the modification is copied
to the underlying TField component when you Tab from the control. If you press Esc
before you Tab from a field, then Delphi abandons the modifications, and the value of
the field reverts to the value it held before any modifications were made. In TDBGrid,
modifications are copied only when you move to a different record; you can press Esc in
any record of a field before moving to another record to cancel all changes to the record.
When a record is posted, Delphi checks all data-aware components associated with the
dataset for a change in status. If there is a problem updating any fields that contain
modified data, Delphi raises an exception, and no modifications are made to the record.
101
Figure 4.2
TDBText component
A TDBText control is useful when you want to provide display-only data on a form that
allows user input in other controls. For example, suppose a form is created around the
fields in a customer list table, and that once the user enters a street address, city, and
state or province information in the form, you use a dynamic lookup to automatically
determine the zipcode field from a separate table. A TDBText component tied to the
zipcode table could be used to display the zipcode field that matches the address
entered by the user.
Note
When you create a TDBText component on a form, make sure its AutoSize property is
True (the default) to ensure that the control resizes itself as necessary to display data of
varying widths. If AutoSize is set to False, and the control is too small, data display is
truncated.
TDBEdit component
Editing a field
A user can modify a database field in a TDBEdit component if:
102
Edits made to a field must be posted to the database by using a navigation or Post button
on a TDBNavigator component.
TDBGrid component
Current field
Column titles
Record
indicator
103
properties that you can set individually. To view and set these properties, double-click
the Options property. The list of options that you can set appears in the Object Inspector
below the Options property. The + sign changes to a (minus) sign, indicating that you
can collapse the list of properties by double-clicking the Options property.
The following table lists the Options properties that can be set, and describes how they
affect the grid at run time:
Table 4.2
Option
Purpose
dgEditing
True: (Default). Enables editing, inserting, and deleting records in the grid.
False: Disables editing, inserting, and deleting records in the grid.
True: When a field is selected, it is in Edit state.
False: (Default). A field is not automatically in Edit state when selected.
True: (Default). Displays field names across the top of the grid.
False: Field name display is turned off.
True: (Default). The indicator column is displayed at the left of the grid, and
the current record indicator (an arrow at the left of the grid) is activated to
show the current record. On insert, the arrow becomes an asterisk. On edit, the
arrow becomes an I-beam.
False: The indicator column is turned off.
True: (Default). Columns can be resized by dragging the column rulers in the
title area. Resizing changes the corresponding width of the underlying TField
component.
False: Columns cannot be resized in the grid.
True: (Default). Displays vertical dividing lines between columns.
False: Does not display dividing lines between columns.
True: (Default). Displays horizontal dividing lines between records.
False: Does not display dividing lines between records.
True: (Default). Enables tabbing between fields in records.
False: Tabbing exits the grid control.
True: The selection bar spans the entire width of the grid.
False: (Default). Selecting a field in a record selects only that field.
True: (Default). The selection bar in the grid is always visible, even if another
control has focus.
False: The selection bar in the grid is only visible when the grid has focus.
True: (Default). Prompt for confirmation to delete records (Ctrl+Del).
False: Delete records without confirmation.
dgAlwaysShowEditor
dgTitles
dgIndicator
dgColumnResize
dgColLines
dgRowLines
dgTabs
dgRowSelect
dgAlwaysShowSelection
dgConfirmDelete
For more information about these options, see the online Help reference.
104
In most data controls, edits to a field are posted as soon as you Tab to another control. By
default in TDBGrid, edits and insertions within a field are posted only when you move
to a different record in the grid. Even if you use the mouse to change focus to another
control on a form, the grid does not post changes until you move off the current row.
When a record is posted, Delphi checks all data-aware components associated with the
dataset for a change in status. If there is a problem updating any fields that contain
modified data, Delphi raises an exception, and does not modify the record.
You can cancel all edits for a record by pressing Esc in any field before moving to
another record.
TDBGrid events
Event
Purpose
OnColEnter
OnColExit
OnDblClick
OnDragDrop
OnDragOver
Specify action to take when a user moves into a column on the grid.
Specify action to take when a user leaves a column on the grid.
Specify action to take when a user double clicks in the grid.
Specify action to take when a user drags and drops in the grid.
Specify action to take when a user drags over the grid.
105
Table 4.3
Event
Purpose
OnDrawDataCell
OnEndDrag
OnEnter
OnExit
OnKeyDown
OnKeyPress
OnKeyUp
There are many uses for these events. For example, you might write a handler for the
OnDblClick event that pops up a list from which a user can choose a value to enter in a
column. Such a handler would use the SelectedField property to determine to current row
and column. For more information about TDBGrid events and properties, see the online
Help reference.
TDBNavigator component
Insert record
Next record
First record
Refresh records
Prior record
106
TDBNavigator buttons
Button
Purpose
First
Prior
Next
Last
Insert
Calls the datasets First method to set the current record to the first record.
Calls the datasets Prior method to set the current record to the previous record.
Calls the datasets Next method to set the current record to the next record.
Calls the datasets Last method to set the current record to the last record.
Calls the datasets Insert method to insert a new record before the current record, and set the
dataset in Insert state.
Table 4.4
Button
Purpose
Delete
Deletes the current record. If the ConfirmDelete property is True it prompts for confirmation
before deleting.
Puts the dataset in Edit state so that the current record can be modified.
Writes changes in the current record to the database.
Cancels edits to the current record, and returns the dataset to Browse state.
Clears data control display buffers, then refreshes its buffers from the physical table or
query. Useful if the underlying data may have been changed by another application.
Edit
Post
Cancel
Refresh
As button values are set to False, they are removed from the TDBNavigator on the form,
and the remaining buttons are expanded in width to fill the control. You can drag the
controls handles to resize the buttons.
For more information about buttons and the methods they call, see the online Help
reference.
107
permits a user to enter multi-line text as well. For example, you can use TDBMemo
controls to display memo fields from dBASE and Paradox tables and text data contained
in BLOB fields.
Figure 4.6
TDBMemo component
By default, TDBMemo permits a user to edit memo text. To limit the number of
characters users can enter into the database memo, use the MaxLength property. To
make a TDBMemo component read-only, set its ReadOnly property to True.
Several properties affect how the database memo appears and how text is entered. You
can supply scroll bars in the memo with the ScrollBars property. To prevent word wrap,
set the WordWrap property to False. To permit tabs in a memo, set the WantTabs
property to True. The Alignment property determines how the text is aligned within the
control. Possible choices are taLeftJustify (the default), taCenter, and taRightJustify.
At run time, users can cut, copy, and paste text to and from a database memo control.
You can accomplish the same task programmatically by using the CutToClipboard,
CopyToClipboard, and PasteFromClipboard methods.
Because the TDBMemo can display large amounts of data, it can take time to populate
the display at run time. To reduce the time it takes scroll through data records,
TDBMemo has an AutoDisplay property that controls whether the accessed data should
automatically displayed. If you set AutoDisplay to False, TDBMemo displays the field
name rather than actual data. Double-click inside the control to view the actual data.
Note
DBImage component
By default, TDBImage permits a user to edit a graphics image by cutting and pasting to
and from the Clipboard, or if you supply an editing method. You can accomplish the
same task programmatically by using the CutToClipboard, CopyToClipboard, and
108
These components can be linked only to TTable components. They do not work with
TQuery components.
The following table describes these controls:
Table 4.5
Data control
Description
TDBListBox
Displays a list of items from which a user can update a specific column in the
current data record.
Combines a TDBEdit control with an attached list. The application user can update
a specific column in the current data record by typing a value or by choosing a
value from the drop-down list.
Displays a list of items from which a user can update a column in the current data
record. The list of items is looked up in a specific column in another dataset.
Combines a TDBEdit control with a dropdown version of TDBLookupList. The
application user can update a field in the current database by typing a value or by
choosing a value from the drop-down list that is looked up in a specific column in
another dataset.
TDBComboBox
TDBLookupList
TDBLookupCombo
TDBComboBox
The TDBComboBox component is similar to a TDBEdit component, except that at run
time it has a drop-down list that enables a user to pick from a predefined set of values.
Here is an example of what a TDBComboBox component looks like at run time:
Figure 4.8
DBComboBox component
The Items property of the component specifies the items contained in the drop-down list.
Use the String List Editor to specify the values for the drop-down list.
109
At run time, the user can choose an item from the list or (depending on the value of the
Style property) type in a different entry. When the component is linked to a column
through its DataField property, it displays the value in the current row, regardless of
whether it appears in the Items list.
The following properties determine how the Items list is displayed at run time:
Style determines the display style of the component:
csDropDown (default): Displays a drop-down list with an edit box in which the
user can enter text. All items are strings and have the same height.
csSimple: Displays the Items list at all times instead of in a drop-down list. All items
are strings and have the same height.
csDropDownList: Displays a drop-down list and edit box, but the user cannot enter
or change values that are not in the drop-down list at run time.
csOwnerDrawFixed and csOwnerDrawVariable: Allows the items list to display
values other than strings (for example, bitmaps). For more information, see the
online VCL reference.
DropDownCount: the maximum number of items displayed in the list. If the number
of Items is greater than DropDownCount, the user can scroll the list. If the number of
Items is less than DropDownCount, the list will be just large enough to display all the
Items.
ItemHeight: The height of each item when style is csOwnerDrawFixed.
Sorted: If True, then the Items list will be displayed in alphabetical order.
TDBListBox
TDBListBox is functionally the same as TDBComboBox, but instead of a drop-down list, it
displays a scrollable list of available choices. When the user selects a value at run time,
the component is assigned that value. Unlike TDBComboBox, the user cannot type in an
entry that is not in the list.
Here is an example of how a TDBListBox component appears at run time.
Figure 4.9
TDBListBox component
110
completely-displayed item in the list. If IntegralHeight is False, the bottom of the list box
is determined by the ItemHeight property, and the bottom item might not be completely
displayed.
TDBLookupCombo
The TDBLookupCombo component is similar to TDBComboBox, except that it derives its
list of values dynamically from a second dataset at run time, and it can display multiple
columns in its drop-down list. With this control, you can ensure that users enter valid
values into forms by providing an interface from which they can choose values. Here is
an example of how a TDBLookupCombo component appears at run time:
Figure 4.10 TDBLookupCombo component
The lookup list for TDBLookupCombo must be derived from a second dataset. To display
values from a column in the same table as the first dataset, drop a second data source
and dataset component on the form and point them at the same data as the first data
source and dataset.
Three properties establish the lookup list for TDBLookupCombo, and determine how it is
displayed:
LookupSource specifies a second data source from where the control populates its list.
LookupField specifies a field in the LookupSource dataset which links that dataset to the
primary dataset. This must be a column in the dataset pointed to by LookupSource,
and it must contain the same values as the column pointed to by the DataField
property (although the column names do not have to match).
LookupDisplay, if set, defines the columns that TDBLookupCombo displays. If you do
not specify values in LookupDisplay, TDBLookupCombo displays the values found in
the column specified by LookupField. Use this property to display a column other than
that specified by LookupField, or to display multiple columns in the drop-down list. To
specify multiple columns, separate the different column names with a semicolon.
A TDBLookupCombo component appears similar to a TDBComboBox at both design time
and run time, except when you want it to display multiple columns in its lookup list.
How the control displays multiple columns depends on the Options property settings:
loColLines: When True, uses lines to separate the columns displayed in the lookup list.
loRowLines: When True, uses lines to separate the rows displayed in the lookup list.
loTitles: When True, column names appear as titles above the columns displayed in
the lookup list.
111
TDBLookupList
TDBLookupList is functionally the same as TDBLookupCombo, but instead of a drop-down
list, it displays a scrollable list of the available choices. When the user selects one at run
time, the component is assigned that value. Like TDBLookupCombo, the user cannot type
in an entry that is not in the list. Here is an example of how a TDBLookupList component
appears at run time:
112
TDBCheckBox
TDBCheckBox is a data-aware version of the Standard TCheckBox component. It can be
used to set the values of fields in a dataset. For example, a customer invoice form might
have a check box control that when checked, specifies that the customer is entitled to a
special discount, or when unchecked means that the customer is not entitled to a
discount
Figure 4.12 TDBCheckBox component
Like the other data controls, TDBCheckBox is attached to a specific field in a dataset
through its DataSource and DataField properties. Use the Caption property to display a
label for the check box on your form.
Set the ValueChecked property to a value the control should post to the database if the
control is checked when the user moves to another record. By default, this value is set to
True, but you can make it any alphanumeric value appropriate to your needs. You can
also enter a semicolon-delimited list of items as the value of ValueChecked. If any of the
items matches the contents of that field in the current record, the check box is checked.
For example, you can specify a ValueChecked string like:
DBCheckBox1.ValueChecked := 'True;Yes;On';
If the field for the current record contains values of True, Yes, or On, then the
check box is checked. Comparison of the field to ValueChecked strings is case-insensitive.
If a user checks a box for which there are multiple ValueChecked strings, the first string is
the value that is posted to the database.
Set the ValueUnchecked property to a value the control should post to the database if the
control is not checked when the user moves to another record. By default, this value is
set to False, but you can make it any alphanumeric value appropriate to your needs. You
can also enter a semicolon-delimited list of items as the value of ValueUnchecked. If any
of the items matches the contents of that field in the current record, the check box is
unchecked.
If the DataField of the check box is a logical field, the check box is always checked if the
contents of the field is True, and it is unchecked if the contents of the field is False. In this
113
case, strings entered in the ValueChecked and ValueUnchecked properties have no effect
on logical fields.
A TDBCheckBox component is grayed out and disabled whenever the field for the
current record does not contain one of the values listed in the ValueChecked or
ValueUnchecked properties.
TDBRadioGroup
TDBRadioGroup is a data-aware version of the standard TRadioGroup component. It lets
you set the value of a data field with a radio button control where there is a limited
number of possible values for the field. The radio group consists of one button for each
value a field can accept.
TDBRadioGroup is attached to a specific field in a dataset through its DataSource and
DataField properties. A radio button for each string value entered in the Items property is
displayed on the form, and the string itself is displayed as a label to the right of the
button.
Figure 4.13 A TDBRadioGroup component
For the current record, if the field associated with a radio group matches one of the
strings in the Items or property, that radio button is selected. For example, if three
strings, Red, Yellow, and Blue, are listed for Items, and the field for the current
record contains the value Blue, then the third button in the group is selected.
Note
If the field does not match any strings in Items, a radio button may still be selected if the
field matches a string in the Values property. If the field for the current record does not
match any strings in Items or Values, no radio button is selected.
The Values property can contain an optional list of strings that can be returned to the
dataset when a user selects a radio button and posts a record. Strings are associated with
buttons in numeric sequence. The first string is associated with the first button , the
second string with the second button, and so on. For example, to continue the example
for the three buttons labeled Red, Yellow, and Blue, if three strings, Magenta,
Yellow, and Cyan, are listed for Values, and the user selects the first button (labeled
Red), then Delphi posts Magenta to the database.
If strings for Values are not provided, the label from a selected radio button (from Items)
is returned to the database when a record is posted. Users can modify the value of a data
field by clicking the appropriate radio button. When the user scrolls off the current row,
Delphi posts the value indicated by the radio button string to the database.
114
Chapter
Chapter 5
Using TQuery
TQuery is a dataset component, and shares many characteristics with TTable, as
described in Chapter 3, Using data access components and tools. In addition, TQuery
enables Delphi applications to issue SQL statements to a database engine (either the
BDE or a server SQL engine).
The SQL statements can be either static or dynamic, that is, they can be set at design time
or include parameters that vary at run time.
115
116
The following diagram illustrates the lifetime of a TQuery component and the methods
used to work with it:
Figure 5.1
Close
Open
ExecSQL
Fetch Data
Note
Prepare applies only to dynamic queries. It is not required, but is recommended in most
cases. For more information, see Dynamic SQL statements on page 121.
A dynamic SQL statement, also called a parameterized statement, includes parameters for
column or table names. For example, this is a dynamic SQL statement:
SELECT * FROM CUSTOMER WHERE CUST_NO = :Number
The variable Number, indicated by the leading colon, is a parameter which must be
provided at run time and may vary each time the statement is executed.
117
Figure 5.2
Choose OK to assign the text you enter to the SQL property of the query. Choose Load
to include text from a file or Save to save the text to a file.
To specify SQL text at run time, an application should first close the query with Close
and clear the SQL property with Clear. For example,
Query1.Close; {This closes the query}
Query1.SQL.Clear; {This clears the contents of the SQL property}
It is always safe to call Closeif the query is already closed, the call will have no effect.
Use the SQL propertys Add method to add the SQL statements to it. For example,
Query1.SQL.Add('SELECT * FROM COUNTRY');
Query1.SQL.Add('WHERE NAME = ''ARGENTINA''');
An application should always call Clear before specifying an SQL statement. Otherwise,
Add will simply append the statements to the existing one.
Note
The SQL property may contain only one complete SQL statement at a time. In general,
multiple statements are not allowed. Some servers support multiple statement batch
syntax; if the server supports this, then such statements are allowed.
You can also use the LoadFromFile method to assign the text in an SQL script file to the
SQL property. For example,
Query1.SQL.LoadFromFile('C:\MYQUERY.TXT');
118
Figure 5.3
For information on how to use the Visual Query Builder, refer to its online Help. After
you have you constructed a query and exited the Visual Query Builder, the SQL
statement you constructed will be entered in the SQL property of the selected TQuery
component.
Executing a query
At design time, you can execute a query by changing its Active property in the Object
Inspector to True. The results of the query will be displayed in any data controls
connected to the Query component (through a data source).
At run time, an application can execute a query with either the Open or the ExecSQL
methods. Use Open for SQL statements that return a result set (SELECT statements). Use
ExecSQL for all other SQL statements (INSERT, UPDATE, DELETE, and so on). For
example,
Query1.Open; {Returns a result set}
If the SQL statement does not return a cursor and a result set from the database, use
ExecSQL instead of Open. For example,
Query1.ExecSQL; {Does not return a result set}
If you dont know at design time whether a query will return a result set, use a
try...except block with Open in the try part and ExecSQL in the except part.
119
RequestLive
CanModify
False
TrueSELECT syntax meets requirements
TrueSELECT syntax does not meet requirements
False
True
False
If an application needs to update the data in a read-only result set, it must use a separate
TQuery to construct an UPDATE statement. By setting the parameters of the update
query based on the data retrieved in the first query, the application can perform the
desired update operation.
120
Parameters Editor
Select the desired data type for the parameter in the Data Type combo box. Enter a value
in the Value text field or select Null Value to set the parameters value to null. When you
click OK, the query will be prepared and values will be bound to the parameters. Then,
when you set the querys Active property to True, the results of the SQL query with the
specified parameter values will be shown in any data controls connected to the query.
At run time, an application can supply values to parameters with the following TQuery
properties:
The Params property, using the order that the parameters appear in the SQL
statement.
The ParamByName method, using the parameter names specified in the SQL
statement.
The DataSource property to set values from another dataset for columns that match
the names of parameters that have no values.
Preparing a query
The Prepare method sends a parameterized query to the database engine for parsing and
optimization. A call to Prepare is not required to use a parameterized query. However, it
is strongly recommended, since it will improve performance for dynamic queries that
121
will be executed more than once. If a query is not explicitly prepared, each time it is
executed, Delphi automatically prepares it.
Prepare is a Boolean property of TQuery that indicates if a query has been prepared. The
Parameters Editor automatically prepares a query when you use it to set parameter
values at design time.
If a query has been executed, an application must call Close before calling Prepare again.
Generally, an application should call Prepare oncefor example, in the OnCreate event
of the formthen set parameters using the Params property, and finally call Open or
ExecSQL to execute the query. Each time the query is to be executed with different
parameter values, an application must call Close, set the parameter values, and then
execute the query with Open or ExecSQL.
Preparing a query consumes some database resources, so it is good practice for an
application to unprepare a query once it is done using it. The UnPrepare method
unprepares a query. When you change the text of a query at run time, Delphi
automatically closes and unprepares the query.
An application could use Params to specify the values of the parameters as follows:
Query2.Params[0].AsString := 'Lichtenstein';
Query2.Params[1].AsString := 'Vaduz';
Query2.Params[2].AsInteger := 420000;
These statements would bind the value Lichtenstein to the :Name parameter,
Vaduz to the :Capital parameter, and 420000 to the :Population parameter.
122
Query2.ParamByName('Population').AsInteger := 420000;
These statements would have the same effect as the three previous statements that used
the Params array directly.
Orders DataSource property is set to CustSource. Because the parameter :CustNo does
not have any value assigned to it, at run time Delphi will try to match it with a column
name in CustSource, which gets its data from the Customer table through Cust. Because
there is a CustNo column in Cust, the current value of CustNo in the Cust table is
assigned to the parameter, and the two data grids are linked in a master-detail
relationship. Each time the Cust table moves to a different row, the Orders query
automatically re-executes to retrieve all the orders for the current customer.
123
124
You can define BDE aliases with the BDE Configuration Utility, described in
Appendix B, Using the BDE configuration utility. For example, suppose you define an
alias called Oracle1 for an Oracle database that has a CUSTOMER table, and Sybase1 for a
Sybase database that has an ORDERS table. A simple query against these two tables
would be
SELECT CUSTOMER.CUSTNO, ORDERS. ORDERNO
FROM :Oracle1:CUSTOMER, :Sybase1:ORDERS
125
126
Chapter
Chapter 6
Delphi Client/Server enables you to develop applications that can access remote SQL
servers such as Oracle, Sybase, Informix, and InterBase, as well as local Paradox and
dBASE databases. A remote server is one that is physically removed from the client
machine on which the Delphi application runs. The server and client must be connected
by a network. Delphi also includes the Local InterBase Server, a full-featured SQL server
that runs on Microsoft Windows.
There are a number of issues that are particularly important when developing a client/
server application:
Portability versus optimization: Will the application use any server-specific SQL
syntax? To what degree will the database be optimized for a particular server?
Transactions: What kind of transaction control will the application require?
Server features: Will the application require the use of server features such as stored
procedures? How will these be surfaced?
Connectivity: What communication protocol will the application use? Does the
application need to be deployed to support multiple communication protocols?
Deployment: What executables, libraries, and other files does the application require
and how are these delivered to the end user?
127
Portability refers to the ease with which an database/application can run on different
servers. Optimization refers to the extent to which an application takes advantage of the
special features of a particular system.
Client portability is not an issue with Delphi, because Delphi applications will run on
any 16-bit or 32-bit Windows platform. However, server portability and
communications portability can be considerations.
Because Delphi applications use the Borland Database Engine, they can be easily
integrated with dBASE and Paradox applications (for desktop data sources) and other
clients for server data sources.
Server portability
It may be desirable to design an application so that it can be easily ported to different
types of servers, either because the end-users require multiple heterogeneous server
support, or because the application will be used by different groups of end-users with
different types of servers. In designing a client-server application, there is an inherent
trade-off between portability and optimization, because making use of server-specific
features results in increased application performance but decreased portability.
A Delphi application that uses only TTable components for data access will be fully
portable among different server types. An application may benefit from improved
performance by using TQuery components and passthrough SQL, and as long as the
SQL syntax is ANSI standard, there will be little loss of portability.
As soon as SQL syntax departs from the ANSI standard, the application will no longer
be fully portable. If server portability is a consideration, you must carefully weigh
whether the gain in using server-specific syntax is worth the cost in portability.
Maintainability of an application may be reduced by optimization for a specific server
type, because each server-specific implementation may require separate maintenance.
An application can be further optimized by using server-specific features such as stored
procedures. However, this will usually require server-specific implementation in the
database, and perhaps the application, depending on how the features are surfaced.
It is also important to consider that servers transaction processing may differ in subtle
yet important ways. This and other distinctions among SQL servers may complicate
portability. Before attempting to create a portable database/application, you should
build an application that runs reliably against one type of server database. In some
cases, it may be necessary to build the application separately against each of the target
server types.
128
phase to ensure that the initial test deployment packages include the proper client
communication software.
129
define a congruent database on the target server. Finally, you can redirect the
application to access the database on the target server.
130
information on the BDE Configuration Utility, see Appendix B, Using the BDE
configuration utility.
Connectivity
Delphi client applications can use any network protocol (such as TCP/IP or Novell
SPX/IPX) supported by the server, as long as both the server and the client machines
have the proper communication software installed. You must configure the SQL Link
driver for the desired protocol. For more information, see the SQL Links for Windows
Users Guide.
Establishing an initial connection between client and server can often be problematic,
especially when using TCP/IP, because there are a number of critical factors that must
all be in place before a connection can be established.
Using TCP/IP
TCP/IP is a widely-used communication protocol that enables applications to connect
to many different database servers. When using TCP/IP, you must ensure:
The TCP/IP communication software and the proper Winsock driver are installed on
the client.
The servers IP address is registered in the clients HOSTS file or that Directory
Network Services (DNS) is properly configured.
The servers port number is entered in the clients SERVICES file.
The application is searching the proper directory paths for the DLLs it needs. Check
the PATH statement in AUTOEXEC.BAT.
For more information, see the SQL Links for Windows Users Guide and your server
documentation.
Connection parameters
The Params property of a connected TDatabase object contains a TString list of all the SQL
Link parameters required to connect to a server of the specified type. You can edit these
parameters by clicking on the ellipsis button to the right of the Params property in the
Object Inspector. The String List Editor opens with the parameters For example, here are
the parameters for connection to an InterBase server:
131
Figure 6.1
You can modify these parameters and add others as needed to customize the connection
performed by the application. For more information, see the SQL Links for Windows
Users Guide.
Using ODBC
A Delphi application can access ODBC data sources such as DB2, Btrieve, or Microsoft
Access through the Borland Database Engine (BDE). To do this, you must set up an
ODBC driver connection using the BDE Configuration Utility. An ODBC driver
connection requires:
A vendor-supplied ODBC driver.
The Microsoft ODBC Driver Manager.
A BDE alias, established with the BDE Configuration Utility or with Delphi.
The BDE configuration setting AUTO ODBC (on the System page) enables an alias to
automatically configure for use of ODBC. When AUTO ODBC is True, datasource and
driver information will automatically be imported from the ODBC.INI file.
For more information, see the online help for the BDE Configuration Utility.
132
Figure 6.2
When control returns from your DatabaseLogin event handler, these parameters will
be used to establish a connection.
The DataSets property of TDatabase is an array of pointers to the active datasets in the
TDatabase. The DatasetsCount property is an integer that specifies the number of active
datasets.
133
This tool enables you to customize application-specific aliases local based on existing
aliases.
The three text fields at the top of the dialog box correspond to the DatabaseName,
AliasName, and DriverName properties.
134
DatabaseName is the name of the database connection that can be used by dataset
components instead of a BDE alias, directory path, or database name. In other words,
this is the name of the local alias defined by the component that will show up in the
DatabaseName drop-down list of dataset components.
AliasName is the name of an existing BDE alias configured with the BDE
Configuration Utility. This is where the component gets its default parameter
settings. This property will be cleared if DriverName is set.
DriverName is the name of a BDE driver, such as STANDARD (for dBASE and
Paradox), ORACLE, SYBASE, INFORMIX or INTERBASE. This property will be
cleared if AliasName is set, because an AliasName specifies a driver type.
Choose the Defaults button to retrieve the default parameters for the selected alias. The
values will be displayed in the Parameters list box. Any changes you make to the
defaults are used instead of the default values for any database connection in the
application that uses that DatabaseName.
The check boxes labeled Loginprompt and Keep inactive connection correspond to
the LoginPrompt and KeepConnections properties of the TDatabase component.
135
Explicitly: depending on the level of control the application requires, either with
The StartTransaction, Commit, and Rollback methods of TDatabase. This is the
recommended approach.
Passthrough SQL in a TQuery component. The application must use serverspecific SQL transaction control statements. You must understand how your
server performs transaction handling.
Transaction control statements are only meaningful when the database is on an SQL
server. The StartTrans, Commit, and Rollback methods will raise an exception if the
underlying database is Paradox or dBASE.
136
To control transactions with passthrough SQL, you must set SQLPASSTHRU MODE to
NOT SHARED. Otherwise, passthrough SQL and Delphis methods may interfere with
each other, leading to unpredictable results.
137
Table 6.1, Server transaction isolation levels. For a detailed description of how each
isolation level is implemented, see your server documentation.
Table 6.1
TransIsolation
setting
Dirty read
Read committed
(Default)
Repeatable read
Oracle
Sybase and
Microsoft SQL
servers
Informix
InterBase
Read committed
Read committed
Read committed
Read committed
Dirty Read
Read committed
Read committed
Read committed
Repeatable read
(READ ONLY)
Read committed
Repeatable Read
Repeatable Read
If an application is using ODBC to interface with a server, the ODBC driver must also
support the isolation level. For more information, see your ODBC driver
documentation.
InterBase select procedures are called with the SELECT statement as if querying a
table. To get output from such procedures, use a TQuery component with the
appropriate SELECT syntax.
138
Figure 6.4
The Parameters Editor displays the input and output parameters for the procedure. To
prepare the stored procedure with the default parameter types and field types, simply
choose OK. You can set values of input parameters at design time by choosing the
parameter in the Parameters list and entering a value in the Value field. To specify null
input parameter values, select the Null value check box. The Parameters Editor is
explained in more detail in Chapter 5, Using SQL in applications.
Note
Delphi will attempt to get information on input and output parameters from the server.
For some servers (such as Sybase), this information may not be accessible. In such cases,
you must enter the names and data types of the input and output parameters in the
Parameters Editor at design time.
To execute a prepared stored procedure, use the ExecProc method. Values can be
assigned to and from a TStoredProc component just as for TQuery components, by using
the Params array. For example, the following code could be in a buttons OnClick event:
StoredProc1.Params[0].AsString := Edit1.Text;
StoredProc1.ExecProc;
Edit2.Text := StoredProc1.Params[1].AsString;
The first parameter, Params[0], is an input parameter of type String. It is assigned the
text entered by the user in Edit1. Then, assuming StoredProc1 has been prepared at
design time with the Parameters Editor, the stored procedure is run with ExecProc.
Finally, the output parameter, Params[1], is displayed by Edit2.
On some servers, stored procedures can return a result set similar to a query.
Applications can use data aware controls to display the output of such stored
procedures. You do this in the same way as you display output from TQuery
139
components: create a TDataSource component and assign its name to a data grids
DataSource property.
Upsizing
Migrating a desktop application to a client/server application is called upsizing.
Upsizing is a complex topic and a full treatment of it is beyond the scope of this book.
However, this section will address some of the most important aspects of upsizing a
Delphi application.
Upsizing has two major facets:
Upsizing the database from the desktop to the server
Upsizing the application to address client/server considerations
Upsizing requires a shift in perspective from the desktop world to the client/server
world. Desktop databases and SQL server databases are different in many respects.
Desktop databases are designed for one user at a time, while servers are designed for
multiuser access. Desktop databases are conceptually record-oriented, while server
databases are conceptually set-oriented. Desktop databases typically store each table in
a separate file, while servers store all the tables in a database together.
Client/server applications must also address some entirely new issues, the most
complex of which are connectivity, network usage, and transaction handling.
140
Use the Database Desktop utility and choose Tools|Utilities|Copy to copy a table
from desktop table to SQL format. For more information, see Appendix A, Using
Database Desktop.
Build a Delphi application that uses a TBatchMove component. For more information
on TBatchMove, see Chapter 3, Using data access components and tools.
Both of these options will copy table structures and migrate data from the desktop
source to the server destination. Depending on the database, it may be necessary to
make changes to the tables created by these methods. For example, the datatype
mappings may not be exactly as desired.
Additionally, you must add to the database any of the following features if required:
Depending on the database, it may be most efficient to define the metadata first by using
an SQL script and the servers data definition tools and then migrate the data using one
of the two methods previously mentioned. If you define the table structure manually,
then Database Desktop and TBatchMove will copy only the data.
141
be performed on the server, so the application would only retrieve the answer from the
server.
For more information on deploying Delphi applications, refer to the file DEPLOY.TXT,
installed to the DELPHI\DOC directory by default.
Each server type has a set of files for the SQL Link. In addition, a file used by all the SQL
Links is BLROM800.LD, the Roman8 language driver using binary collation sequence.
Oracle
The following files provide the SQL Links interface with Oracle servers. In addition,
applications will require Oracle client files for interface to low-level communication
protocols such as TCP/IP. Refer to your server documentation.
Table 6.2
File name
Description
SQLD_ORA.DLL
SQLD_ORA.HLP
SQL_ORA.CNF
ORA6WIN.DLL
ORA7WIN.DLL
SQL13WIN.DLL
SQLWIN.DLL
COREWIN.DLL
ORAWE850.LD
142
File name
Description
SQLD_SS.DLL
SQLD_SS.HLP
SQL_SS.CNF
Table 6.3
File name
Description
W3DBLIB.DLL
DBNMP3.DLL
SYDC437.LD
SYDC850.LD
Informix
The following files provide the SQL Links interface with Informix servers. In addition,
applications will require Informix client files for interface to low-level communication
protocols such as TCP/IP. Refer to your server documentation.
Table 6.4
File name
Description
SQLD_INF.DLL
SQLD_INF.HLP
SQL_INF.CNF
LDLLSQLW.DLL
ISAM.IEM
OS.IEM
RDS.IEM
SECURITY.IEM
SQL.IEM
InterBase
The following files provide the SQL Links interface to remote InterBase servers. These
files are distinct from those required to access the Local InterBase Server..
Table 6.5
File name
Description
SQLD_IB.DLL
SQLD_IB.HLP
SQL_IB.CNF
CONNECT.EXE
CONNECT.HLP
GDS.DLL
REMOTE.DLL
INTERBAS.MSG
143
TCP/IP Interface
The following files provide InterBase client applications their interface to Winsock 1.1
compliant TCP/IP products.
Table 6.6
File name
Description
MVWASYNC.EXE
VSL.INI
WINSOCK.DLL
MSOCKLIB.DLL
For TCP/IP products that are not Winsock 1.1 compliant, InterBase client applications
will require one of the following files. During installation, Delphi will prompt you to
select the TCP/IP stack for which to install support. If the deployed application needs to
support a different TCP/IP stack, you must copy the corresponding file from the
installation disks.
Table 6.7
File name
TCP/IP Product
M3OPEN.EXE
M3OPEN.DLL
MBW.EXE
MFTP.EXE
MHPARPA.DLL
MNETONE.EXE
MNOVLWP.DLL
MPATHWAY.DLL
MPCNFS.EXE
MPCNFS2.EXE
MPCNFS4.DLL
MWINTCP.EXE
144
For more information on deploying ReportSmith reports, refer to the file DEPLOY.TXT,
installed to the DELPHI\DOC directory by default.
145
146
Appendix
A
Using Database Desktop
Appendix A
147
Status line
Files you open in Database Desktop appear in their own type of windows. Tables
appear in Table windows, queries appear in Query windows, and SQL statements
appear in the SQL Editor.
Below the menu is a tool bar. The tool bar changes when the active window changes.
The following figure shows the application window tool bar.
Figure A.2
Open
Table
Open QBE
Query
Managing files
In Database Desktop you work with three types of files: QBE queries, .SQL files, and
tables. Other files are created automatically by Database Desktop.
For a list of file extensions used by Database Desktop, search for file-name extensions
in the keyword list in Database Desktop Help, and choose the topic Types of Files.
Opening files
To open a QBE query, SQL statement, or table, follow these steps:
1 Choose File|Open.
2 Choose the type of file to openQBE query, SQL statement, or table.
148
To access tables stored on a network, you must specify the location of the network
control file. You do this by running the BDE Configuration Utility; double-click the BDE
Configuration Utility icon in the Delphi program group. See online Help in the BDE
Configuration Utility for more details.
Aliases
You can assign an alias as a shorthand for a directory using the Alias Manager dialog
box. For example, if you have a collection of tables and queries in one directory (called
C:\DBD\PROJECTS\CUSTLIST), you can specify the alias :MYWORK: rather than
type the entire path.
Using aliases, you can avoid typing long path names, and you can use the Path list in
File|Open and File|Save dialog boxes to list files in any directory for which you have
defined an alias.
To create an alias, choose File|Aliases. For information on creating, changing, or
removing an alias, search for aliases in the keyword list in Database Desktop Help.
Creating tables
This section describes tables and discusses how to create and restructure Paradox,
dBASE, and SQL tables in Database Desktop.
149
Understanding tables
A database is an organized collection of information or data. An address book is an
example of a database. It organizes data about people into specific categories: names,
phone numbers, and addresses.
In a relational database, the data is organized into tables. Each row of a table contains
information about a particular item; this is called a record. Each column contains one
piece of the information that makes up a record; this is called a field.
Figure A.3
A table
Relational tables
Relational database applications such as dBASE and Paradox give you a way to link
tables by comparing values stored in comparable fields in separate tables. The
advantage of a relational database is that you can easily extract or combine data from
several tables to get exactly the information you need, without changing the structure of
the database. Also, a few small and discrete tables are more convenient to use and
maintain than one large table.
The sample database files CUSTOMER.DB and BOOKORD.DB are examples of
relational tables. These tables can be linked through the fields containing customers ID
numbers (Cust ID in the Customer table, Cust in Bookord). When the tables are linked, you
can extract information from both tables into one table. For example, you can search for
and extract a list of quantities ordered (from the Bookord table) and the respective last
names (from Customer). The results are returned in an Answer table (see page 170).
Planning tables
Planning is the first step in creating a table. Decide what you want the table to contain
and how you want to lay it out. For tips on planning tables, search for planning in the
keyword list in Database Desktop Help, and choose the topic Planning Tables.
150
1 Choose File|New|Table. Or right-click the Open Table tool bar button, and choose
New.
The Table Type dialog box appears.
Figure A.4
2 If you want a table type other than Paradox for Windows, click the arrow next to the
list box and select from the drop-down list.
3 Choose OK. The Create Table dialog box appears. This dialog box may have a
slightly different appearance for different table types, but it will function the same.
Figure A.5
For a step-by-step description of creating a table, search for creating tables in the
keyword list in Database Desktop Help, and choose the topic Creating a New Table.
151
Defining fields
Use the Field Roster in the Create Table dialog box (page 151) to define the fields of the
new table. You can use the mouse, arrow keys, Enter, Tab, or Shift+Tab to move among the
columns. (Shift+Tab moves backwards.)
Field names
Type field names in the Field Name column of the Field Roster.
For information on rules governing field names, search for field names in the
keyword list in Database Desktop Help, and choose the topic for the type of table you
are using (Paradox, dBASE, or SQL).
Using indexes
The BDE uses indexes to keep track of the location of records in tables. This makes it
easy to maintain a sorted order of a table and view like values together.
When you create an index for a Paradox or dBASE table, Database Desktop creates a file
that contains the indexed fields values and their locations. Database Desktop uses the
index file to locate and sort the records in a table.
Indexes work differently for Paradox, dBASE, and SQL tables.
152
values (taken as an ordered group) must be unique. This guards against duplication of
data within the table. Keys are required for linking tables and for using the data
integrity features of Paradox tables.
To create a key, display the Create Table (page 151) or the Restructure Table (page 160)
dialog box. Then move to the Key column in the Field Roster and double-click (or press
any key). The key field indicator (*) appears. Database Desktop keys the table on the
selected field.
Follow these rules when defining keys:
A table can have only one primary key. This key can be made up of one or more
fields.
If a key is defined as a single field, that field must be the first field in the Field Roster.
If you identify more than one field as keyed, you create a composite key. These fields,
taken as a group, must be unique for each record of the table. The composite key
must be the first fields in the Field Roster.
Delphi does not support all dBASE index types. For more information, see Chapter 3,
Using data access components and tools.
153
insert, depending on the server. To add a unique index to an existing table, choose
Utilities|Restructure.
For more information on SQL indexes, see Creating indexes on SQL tables on
page 155.
Validity checks work only on Paradox tables, not on dBASE tables. For SQL tables, the
only validity check you can specify in Database Desktop is whether a field is required
(not Null).
Table A.1
Validity check
Meaning
Required field
Every record in the table must have a value in this field. SQL tables can also use
this validity check (equivalent to NOT NULL).
The values entered in this field must be equal to or greater than the minimum you
specify here.
The values entered in this field must be less than or equal to the maximum you
specify here.
The value you specify here is automatically entered in this field. You can replace it
with another value.
You specify a character string that acts as a template for the values that can be
entered in this field. The values entered in this field are automatically formatted
according to this picture.
For information on pictures, search for picture strings in the keyword list in
Database Desktop Help, and choose the topic Picture String Characters.
Minimum
Maximum
Default
Picture
For detailed information on validity checks, search for validity checks in the keyword
list in Database Desktop Help.
Note
154
A Required field validity check will set a Delphi TFields Required property to True
when the table is accessed from a Delphi application.
For information on valid field types for your SQL server, search for field types in the
keyword list in Database Desktop Help, and choose the topic for your server.
155
Figure A.7
Lists all
fields in
your table
When you use an SQL table in Database Desktop, the table should have a unique index.
If it does not have a unique index, you may not be able to view new records you insert.
For detailed information on using the Define Index dialog box, search for Define Index
Dialog Box in the keyword list in Database Desktop Help, and choose the topic Define
Index Dialog Box (SQL Tables).
Sybase index names need only be unique within a table, not within the entire database,
so Database Desktop does not prefix Sybase index names with table names.
When you create an SQL index and choose OK from the Define Index dialog box,
Database Desktop supplies the prefix <table>_ for the index name as follows:
Figure A.8
You can include the table name with the index name or omit it:
If you type the index name following <table>_, Database Desktop prefixes the
index name with the table name and an underscore.
If you delete <table>_, Database Desktop omits the table name from the index
name. If the index name is not unique, an error will occur when Database Desktop
saves the table.
156
Referential integrity
ORDERS
OrderNo CustomerNo
City
Database Desktop prohibits you
from entering a value in the Orders
Customer No field that doesnt
match an existing value in the
Customer Customer No field.
Name
Database Desktop accepts only those values that exist in the parent tables key as valid
values for the specified field(s) of the child table. You can establish referential integrity
only between like fields that contain matching values. For example, you can establish
referential integrity between Customer and Orders on their CustomerNo fields. In both
cases, the values contained in the specified fields are the same. The field names dont
matter as long as the field types and sizes are identical.
Note
You can establish referential integrity only between tables in the same directory.
Using referential integrity, Database Desktop checks the validity of a value before
accepting it in the table. If you establish referential integrity between Customer and
Orders on their CustomerNo fields, then enter a value in the CustomerNo field of Orders,
Database Desktop searches the CustomerNo field of Customer and
Accepts the value in Orders if it exists in Customer
Rejects the value in Orders if it doesnt exist in Customer
Procedure
To define a referential integrity relationship,
1 In the Create Table (page 151) or Restructure Table (page 160) dialog box, choose
Referential Integrity from the Table Properties list. The Define button becomes
available.
157
The referential
integrity diagram
3 Choose the parent table from the Table list. The tables key field appears in the
Parents Key area of the referential integrity diagram.
4 Double-click the child tables field in the Fields list (or Tab to it and click the Add
Field arrow or press Alt+A). The field name appears in the Child Fields area of the
referential integrity diagram.
5 Choose the update rule you want.
6 Choose whether you want to enforce strict referential integrity.
7 Choose OK to name and save the referential integrity relationship.
For detailed information on defining referential integrity, search for Referential
Integrity or Referential Integrity Dialog Box in the keyword list in Database Desktop
Help.
158
For detailed information on table lookup, search for table lookup in the keyword list
in Database Desktop Help, and choose the topic Looking up Table Values.
Note
Restructuring tables
Database Desktop enables you to restructure Paradox and dBASE tables to:
Restructuring a table is very much like creating it for the first time. You will not be able
to restructure a table if Delphi or any other application has the table open. For detailed
information on restructuring tables, see the Database Desktop Help; choose Help|
Contents|Tasks|Creating and Restructuring|Restructuring a Table.
Note
159
Figure A.11 The Restructure Table dialog box for Paradox tables
Work in the Restructure
Table dialog box the same
way you work in the Create
Table dialog box.
Pack a table to reuse disk space left over from deleting records. Some restructure operations automatically pack
your table. You can check Pack Table and choose OK when you want to be sure Paradox packs the table.
160
If you create a new index during a restructure, Database Desktop prompts you to
prefix the index name with the table name.
If you modify an index during a restructure, Database Desktop does not modify the
index name, unless you rename the index as part of your modification.
If you choose Save As during a restructure, Database Desktop prefixes all index
names with the new table name, if you have not explicitly entered an index name. For
example, suppose the EMPLOYEE table contains the following indexes:
EMPLOYEE_DEPT_NO
EMPLOYEE_EMP_NO
FULL_NAME
JOB
If you restructure the table and save it as MY_DEPT, Database Desktop renames the
indexes as follows:
MY_DEPT_DEPT_NO
MY_DEPT_EMP_NO
MY_DEPT_FULL_NAME
MY_DEPT_JOB
Viewing tables
To open a table, choose File|Open|Table. Or, if the application window is empty, click
the Open Table button in the tool bar. In the Open Table dialog box, choose the table to
open. The table you chose opens in a Table window, and the tool bar appears as shown
in the following figure:
Figure A.13 The Table window tool bar
Copy
Cut
Restructure
Paste
Previous
Set
First
Record
Next
Record
Previous
Record
Last
Record
Next
Set
Edit
Data
Field
View
When you first open a table, its data appears in a Table window in View mode. Each
Table window contains an independent view of a table, so different views of a single
table can be open at the same time. Up to 24 tables can be open at one time.
To be able to simultaneously access tables stored on a network, you must provide
Database Desktop the location of the network control file. You do this by running the BDE
Configuration Utility; double-click the BDE Configuration Utility icon in the Delphi
program group. See online Help in the BDE Configuration Utility for more details.
A Delphi application can specify the network control file in the NetFileDir property of
TSession. This enables a Delphi application access to tables stored on a network.
161
162
Resizing rows
To resize the height of all of the rows in a table, drag the line under the first record
number. Move the line up to decrease the row height, or down to increase the row
height.
163
For detailed information on the Properties menu commands, search for Properties
menu in the keyword list in Database Desktop Help.
Editing data
This section introduces Database Desktops editing features. For detailed information
on editing data, search for editing data or Edit mode in the keyword list in Database
Desktop Help.
Press F9.
In Edit mode, you can select any field and begin typing to replace its existing entry.
When you enter Edit mode, the Edit Data button remains pressed in and the status line
tells you Edit mode is active.
Note
In Database Desktop you cannot edit data in the following field types:
Paradox: Memo, Formatted Memo, Graphic, OLE, Autoincrement, Binary, or Bytes
dBASE: Memo, OLE, or Binary
SQL: any BLOB (binary large object) field or a text field that allows more than 255
characters
Figure A.16 The Customer table in Edit mode
164
Field view
In Edit mode, you can change a fields entry in one of two ways:
Select the field and type a new value. When you begin typing, the new value replaces
the old entry.
Select the field and edit the existing entry using field view.
For information on field view, search for Field View in the keyword list in Database
Desktop Help.
165
Sorting tables
When you sort a table, you tell Database Desktop to rearrange the order of the records in
the table and display them in the order you specify.
If a table is keyed, Database Desktop creates a new, unkeyed table containing the
sorted data. The original table remains unchanged.
If a table is not keyed, the sort changes the actual location of the records in the table.
SQL
Copying objects
You can copy Paradox and dBASE tables, queries, SQL tables, and .SQL files from
within Database Desktop. To copy an object, choose Utilities|Copy. Database Desktop
opens the Copy dialog box.
When you copy a table, Database Desktop copies both the structure of the table and the
data contained in it. You can copy tables from one table type to another. For example,
you can copy a Paradox table to a dBASE or SQL table. To copy to an SQL table type,
you must have an SQL database server and the appropriate SQL Link.
For detailed information on copying objects, see Database Desktop Help; choose Help|
Contents|Tasks|Using Table Utilities|Copying Tables.
Renaming objects
You can rename tables, queries, and .SQL files from within Database Desktop. You
cannot rename SQL tables.
To rename an object, choose Utilities|Rename. Database Desktop opens the Rename
dialog box. For detailed information on renaming objects, see Database Desktop Help;
choose Help|Contents|Tasks|Using Table Utilities|Renaming Tables.
Deleting objects
You can delete tables, queries, SQL tables, and .SQL files from within Database Desktop.
166
To delete an object, choose Utilities|Delete. Database Desktop opens the Delete dialog
box. For detailed information on deleting objects, see Database Desktop Help; choose
Help|Contents|Tasks|Using Table Utilities|Deleting Tables.
If you execute a SELECT statement in the SQL Editor, Database Desktop displays the
resulting data in an Answer table, as shown in Figure A.18.
167
The SQL Editor has the tool bar shown in Figure A.19.
Figure A.19 SQL Editor Toolbar
Copy
Cut
Run SQL
Paste
Search
Next
Search
Answer
Table Options
Select Alias
Do this
Specifying an alias
Before running an SQL statement, you must specify the alias that the statement will run
against. To specify an alias, do one of the following:
Choose SQL|Select Alias.
Click the Select Alias tool bar button.
Database Desktop opens the Select Alias dialog box, where you can choose one of the
aliases you created in the Alias Manager dialog box. You cannot include an alias in the
text of the SQL statement.
168
If your SQL statement is a query, the query results are displayed in an Answer table, as
shown in Figure A.18 on page 168.
169
The result of a query is a temporary table called Answer. The Answer table is overwritten
each time a query is run.
SQL
If you have Borland SQL Links, you can use QBE to view and query tables on SQL
servers. For more information, see the Database Desktop Help Contents.
For details on using QBE, see Database Desktop Help; choose Help|Contents|Tasks|
Using Query-By-Example.
170
Appendix
B
Using the BDE configuration utility
Appendix B
171
1 Select the Alias Manager (Aliases page) and choose the New Alias button. The Add
New Alias dialog box appears. The type can be STANDARD or SQL-specific.
Figure B.2
2 Enter the new alias name and select the SQL-specific alias type. Then choose OK to
begin the setup process. The Alias Manager displays all the configuration parameters
you can change to customize the new alias.
Figure B.3
3 If desired, edit the settings for the category you selected. If you leave any categories
blank, the Alias Manager assumes you want to use the default for driver type.
4 When you are finished, select File|Save to save the new alias in the default
configuration file; select File|Save as to save the new alias in a configuration file with
a different name.
172
Note
The other pages contain settings that can also be customized. See online help for
specifics.
Page
Settings modified
Driver Manager
System Manager
Date Manager
Time Manager
Number Manager
Those BDE uses to determine how an application creates, sorts, and handles tables.
Those BDE uses to start an application.
Those used to convert string values into date values.
Those used to convert string values into time values.
Those used to convert string values to number values.
If you save the new alias in a configuration file with a different name, the BDE
Configuration Utility displays:
Figure B.4
Choose Yes if you want to activate this configuration file next time you start your
application. Choose No if you want to keep using the current default configuration file.
Your changes take effect the next time you start your application.
1 Scan the list of Alias Names available through the current configuration file. If the
alias you want to modify was stored in a different configuration file, use File|Open
to load that configuration file.
2 Highlight the name of the alias you want to modify. The configuration for that alias
appears in the Parameters section of the Alias Manager page.
3 Highlight the configuration parameter you want to change, and enter the desired
value. If you leave any categories blank, the Alias Manager assumes you want to use
the drivers default value.
4 When you are finished, select File|Save to save the new alias in the default
configuration file; select File|Save As to save the new alias in a configuration file
with a different name.
When you modify a driver parameter, all aliases that use the default setting for that
parameter inherit the new setting.
Your changes take effect the next time you start your application.
173
Deleting an alias
To delete an alias,
1 Scan the list of Alias Names available through the current configuration file. If the
alias you want to delete was stored in a different configuration file, use File|Open to
load that configuration file.
2 Highlight the name of the alias you want to modify, and select the Delete Alias
button.
3 Select File|Save to save your changes in the default configuration file; select File|
Save As to save your changes in a different configuration file.
Note
174
If an application attempts to use an alias that has been deleted, Delphi will raise an
exception. If a Delphi form was saved with a table or query open, Delphi will attempt to
open the dataset when the form is loaded and the exception will occur at that time. In
many cases, modifying an alias can also cause an exception in Delphi forms if the
changes to the alias require changes to the Delphi application.
Appendix
C
Using local SQL
Appendix C
The BDE enables limited access to database tables through local SQL (also called clientbased SQL). Local SQL is a subset of ANSI-standard SQL enhanced to support Paradox
and dBASE naming conventions for tables and fields (called columns in SQL). Two
categories of SQL statements are supported:
Data Manipulation Language (DML) for selecting, inserting, updating, and deleting
table data.
Data Definition Language (DDL) for creating, altering, and dropping tables, and for
creating and dropping indexes.
This appendix describes naming conventions, syntax enhancements, and syntax
limitations for local SQL. For a complete introduction to ANSI-standard SQL, see one of
the many third-party books available at your local computer book store.
Local SQL also supports BDE aliases for table names. For example,
SELECT * FROM :PDOX:TABLE1
Finally, local SQL permits table names to duplicate SQL keywords as long as those table
names are enclosed in single or double quotes. For example,
SELECT PASSID FROM "PASSWORD"
175
In the next example, the column name duplicates the SQL DATE keyword:
SELECT DATELOG."DATE" FROM DATELOG
Data manipulation
With some restrictions, local SQL supports the following statements for data
manipulation:
SELECT, for retrieving existing data
INSERT, for adding new data to a table
UPDATE, for modifying existing data
DELETE, for removing existing data from a table
The following sections describe parameter substitution, aggregate, string, and date
functions, and operators available to DML statements in local SQL.
176
For example, the following statement extracts the year value from a DATE field:
SELECT EXTRACT(YEAR FROM HIRE_DATE)
FROM EMPLOYEE
You can also extract MONTH, DAY, HOUR, MINUTE, and SECOND using this
function.
Note
Supported operators
Local SQL supports the following arithmetic operators:
+, , *, /
177
Using SELECT
The SELECT statement is used to retrieve data from one or more tables. A SELECT that
retrieves data from multiple tables is called a join. Local SQL supports the following
form of the SELECT statement:
SELECT [DISTINCT] column_list
FROM table_reference
[WHERE search_condition]
[ORDER BY order_list]
[GROUP BY group_list]
[HAVING having_condition]
Except as noted below, all clauses are handled as in ANSI-standard SQL. Clauses in
square brackets are optional.
The column_list indicates the columns from which to retrieve data. For example, the
following statement retrieves data from two columns:
SELECT PART_NO, PART_NAME
FROM PARTS
The WHERE clause can now include the IN predicate, followed by a parenthesized list
of values. For example, the next statement retrieves only those rows where a part
number matches an item in the IN predicate list:
SELECT * FROM PARTS
WHERE PART_NO IN (543, 544, 546, 547)
Important
178
The next query retrieves all part information ordered in descending numeric order by
part number:
SELECT * FROM PARTS
ORDER BY PART_NO DESC
Calculated fields can be ordered by correlation name or ordinal position. For example,
the following query orders rows by FULL_NAME, a calculated field:
SELECT LAST_NAME || ', ' || FIRST_NAME AS FULL_NAME, PHONE
FROM CUSTOMERS
ORDER BY FULL_NAME
Heterogeneous joins
Local SQL supports joins of tables in different database formats; such a join is called a
heterogeneous join. For example, it is possible to retrieve data from a Paradox table
and a dBASE table as follows:
SELECT DISTINCT C.CUST_NO, C.STATE, O.ORDER_NO
FROM "CUSTOMER.DB" C, "ORDER.DBF" O
WHERE C.CUST_NO = O.CUST_NO
Using INSERT
In local SQL, INSERT is restricted to a list of values:
INSERT INTO CUSTOMER (FIRST_NAME, LAST_NAME, PHONE)
VALUES(:fname, :lname, :phone_no)
Using UPDATE
There are no restrictions on or extensions to the ANSI-standard UPDATE statement.
Using DELETE
There are no restrictions on or extensions to the ANSI-standard DELETE statement.
179
Data definition
Local SQL supports data definition language (DDL) for creating, altering, and dropping
tables, and for creating and dropping indexes. All other ANSI-standard SQL DDL
statements are not supported. In particular, views are not supported.
Local SQL does not permit the substitution of variables for values in DDL statements.
The same statement for a dBASE table should omit the PRIMARY KEY definition:
CREATE TABLE "employee.db"
(
LAST_NAME CHAR(20),
FIRST_NAME CHAR(15),
SALARY NUMERIC(10,2)
DEPT_NO SMALLINT
)
The following table lists SQL syntax for data types used with CREATE TABLE, and
describes how those types are mapped to Paradox and dBASE types by the BDE:
Table C.1
SQL Syntax
BDE Logical
Paradox
dBASE
SMALLINT
INTEGER
DECIMAL(x,y)
NUMERIC(x,y)
FLOAT(x,y)
CHARACTER(n)
fldINT16
fldINT32
fldBCD
fldFLOAT
fldFLOAT
fldZSTRING
fldPDXSHORT
fldPDXLONG
fldPDXBCD
fldPDXNUM
fldPDXNUM
fldPDXALPHA
fldDBNUM
fldDBNUM
N/A
fldDBNUM(x,y)
fldDBFLOAT(x,y)
fldDBCHAR
180
Table C.1
SQL Syntax
BDE Logical
Paradox
dBASE
VARCHAR(n)
DATE
BOOLEAN
BLOB(n,s)
TIME
TIMESTAMP
MONEY
fldZSTRING
fldDATE
fldBOOL
See Subtypes below
fldTIME
fldTIMESTAMP
fldFLOAT,
fldstMONEY
fldINT32,
fldstAUTOINC
fldBYTES(n)
fldPDXALPHA
fldPDXDATE
fldPDXBOOL
See Subtypes below
fldPDXTIME
fldPDXTIMESTAMP
fldPDXMONEY
fldDBCHAR
fldDBDATE
fldDBBOOL
See subtypes below
N/A
N/A
fldDBFLOAT(20,4)
fldPDXAUTOINC
N/A
fldPDXBYTES
fldDBBYTES
(in-memory tables only)
AUTOINC
BYTES(n)
The following table specifies how BLOB subtypes translate from SQL to Paradox and
dBASE through the BDE:
Table C.2
SQL Subtype
1
2
3
4
5
BDE Logical
Paradox
dBASE
fldstMEMO
fldstBINARY
fldstFMTMEMO
fldstOLEOBJ
fldstGRAPHIC
fldPDXMEMO
fldPDXBINARY
fldPDXFMTMEMO
fldPDXOLEBLOB
fldPDXGRAPHIC
fldDBMEMO
fldDBBINARY
N/A
fldDBOLEBLOB
N/A
You can delete existing columns from a table using the following ALTER TABLE syntax:
ALTER TABLE table DROP column_name [, DROP column_name . . .]
For example, the next statement drops two columns from a Paradox table:
ALTER TABLE "employee.db" DROP LAST_NAME, DROP FIRST_NAME
ADD and DROP operations can be combined in a single statement. For example, the
following statement drops two columns and adds one:
181
ALTER TABLE "employee.dbf" DROP LAST_NAME, DROP FIRST_NAME, ADD FULL_NAME CHAR[30]
Using CREATE INDEX is the only way to create indexes for dBASE tables. For example,
the following statement creates an index on a dBASE table:
CREATE INDEX NAMEX ON "employee.dbf" (LAST_NAME)
Paradox users can only create secondary indexes with CREATE INDEX. Primary
Paradox indexes can only be created by specifying a PRIMARY KEY constraint when
creating a new table with CREATE TABLE.
The PRIMARY keyword is used to delete a primary Paradox index. For example, the
following statement drops the primary index on EMPLOYEE.DB:
DROP INDEX "employee.db".PRIMARY
To drop any dBASE index, or to drop secondary Paradox indexes, provide the index
name. For example, the next statement drops a secondary index on a Paradox table:
DROP INDEX "employee.db".NAMEX
182
Appendix
D
The MAST database
Appendix D
This appendix describes the MAST sample database provided with Delphi and used for
the MASTAPP sample application. The basic MAST database is in Paradox format. A
SQL version that uses the Local InterBase Server is also provided. See README.TXT for
a complete list of sample databases and applications.
MAST is the fictional Marine Adventures and Sunken Treasures company. MASTs
customers are dive shops around the world. They sell products and supplies to these
shops; the shops place orders for equipment. The following tables are used to track
MASTs sales:
Table D.1
MAST tables
Table name
Information in table
CUSTOMER.DB
EMPLOYEE.DB
ITEMS.DB
NEXTORD.DB
ORDERS.DB
PARTS.DB
VENDOR.DB
Each table contains a primary key. To link tables, some fields and data must be
duplicated among tables. A table must have a primary key or secondary index assigned
to the duplicate field before it can be linked to another table. Fields that are duplicated
between tables use referential integrity to make sure their values match in all tables.
The following tables describe each of the MAST database tables by showing the fields
contained in the table, the type of each field, the size of the alphanumeric fields, and the
fields that are key fields.
183
Type
CustNo
Company
Addr1
Addr2
City
State
Zip
Country
Phone
FAX
TaxRate
Contact
LastInvoiceDate
Numeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Numeric
Alphanumeric
Timestamp
Size
Key
*
30
30
30
15
20
10
20
15
15
20
In CUSTOMER, the CustNo field is a primary key because orders in the ORDERS table
must be linked to customers. The secondary index on Company is named
"ByCompany". ORDERS itself contains only information about each order placed by a
customer.
The structure of the EMPLOYEE table is as follows:
Field
Type
EmpNo
LastName
FirstName
PhoneExt
HireDate
Salary
Long integer
Alphanumeric
Alphanumeric
Alphanumeric
Timestamp
Numeric
Size
Key
*
20
15
4
Type
ItemNo
OrderNo
PartNo
Qty
Discount
Numeric
Numeric
Numeric
Long integer
Numeric
Size
Key
*
OrderNo is a secondary index and is used in the master-detail link in the Orders form.
The NEXTORD tables is a single-column table used to generate unique, sequential order
numbers. In a multi-user environment using Paradox tables, the only way to guarantee
184
that an order number is unique is to store the last-used number in a table, and increment
it each time a new number is fetched. The table is structured as follows:
Field
Type
NewKey
Numeric
Size
Key
Size
Key
Type
OrderNo
CustNo
SaleDate
ShipDate
EmpNo
ShipToContact
ShipToAddr1
ShipToAddr2
ShipToCity
ShipToState
ShipToZip
ShipToCountry
ShipToPhone
ShipVIA
PO
Terms
PaymentMethod
ItemsTotal
TaxRate
Freight
AmountPaid
Numeric
Numeric
Timestamp
Timestamp
Long integer
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Money
Numeric
Money
Money
20
30
30
15
20
10
20
15
7
15
6
7
In ORDERS, the link to CUSTOMER is through the CustNo field. A secondary index is
defined on CustNo to ensure that ORDERS and CUSTOMERS can be sorted and linked
in the same order. To be sure that values entered as CustNo in ORDERS match exactly
one record in CUSTOMER, referential integrity is used to constrain values entered in the
CustNo field to valid customer numbers already in the CUSTOMER table.
The primary key in ITEMS is a composite of the OrderNo and ItemNo fields; these fields
also have secondary indexes. This enables ITEMS to link to ORDERS (using OrderNo)
in the MASTAPP Orders form. Referential integrity is used to validate the information
in PARTS.
185
The PARTS table tracks the inventory of products. PARTS is structured as follows so
that it can be linked to VENDORS:
Field
Type
PartNo
VendorNo
Description
OnHand
OnOrder
Cost
ListPrice
Numeric
Numeric
Alphanumeric
Numeric
Numeric
Money
Money
Size
Key
*
30
20
PartNo is the primary key for this table. Because PartNo is a secondary index, the two
tables can be linked. VendorNo is the primary key of VENDORS, so it is a secondary
index in PARTS and is defined to use referential integrity to make sure values entered in
VendorNo match a single VendorNo entry in the VENDORS table.
The VENDORS table has the following structure:
Field
Type
Size
VendorNo
VendorName
Address1
Address2
City
State
Zip
Country
Phone
FAX
Preferred
Numeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Alphanumeric
Logical
30
30
30
20
20
10
15
15
15
Key
*
Using these tables, a customers information is entered only once, and then referred to in
other tables. Likewise, order, item, inventory, and vendor information is entered only
once, reducing storage requirements, and the chance for data entry error.
186
Index
Symbols
" (quotation mark), naming
conventions 175, 176
* operator 177
+ (plus) sign in property lists 103
+ operator 177
/ operator 177
: (colon) in SQL statements 117,
176
< operator 177
<> operator 177
= operator 177
> operator 177
? (question mark) in SQL
statements 176
|| operator 177
(minus) sign in property
lists 104
operator 177
(apostrophe), naming
conventions 175, 176
A
abandoning changes 64, 101, 107
Abort procedure 68
AbortOnKeyViol property 92
AbortOnProblem property 92
accessing
data 79, 89, 100, 115, 116
at run time 8788
field values 30, 32
optimizing access 119
remote servers 127, 141
data sources 5, 99
networks and 5
property values 40, 86
Active property
datasets 59, 101
queries 50, 119
Add command (Database
Desktop) 165
Add Fields window 81
Add method 118
Add New Alias dialog box 172
ADD operations 181
adding See creating
AfterCancel event 68
AfterClose event 68
AfterDelete event 68
AfterEdit event 68
AfterInsert event 68
AfterOpen event 68
AfterPost event 68
aggregate functions 141,
176177, 179
Alias Manager 172
Alias Manager dialog box
(Database Desktop) 149
aliases 5, 149, 171174
changing 173
defined 149
deleting 174
local SQL and 175
predefined 20
queries 168
heterogenous 124
retrieving defaults 135
retrieving information 57
saving 172, 173
specifying 134, 172
Aliases command (Files) 149
Aliases page (BDE Configuration
Utility) 172
AliasName property 135
alignment, text 108
Alignment property 33, 83, 108
ALTER TABLE keyword 181
altering See changing
ancestor objects 55
AND operator 177
ANSI/OEM conversion 93
ANSI-standard SQL naming
conventions 175176
Answer tables 170
apostrophe (), naming
conventions 175, 176
Append method 64
AppendRecord method 65
applications 79, 93
building 19
client/server 14, 118
deploying 1618
remote servers 142145
developing 1216
client/server 127129
fundamentals 13
displaying multiple
views 9597
multiuser 5, 135, 147
updating data 65
optimizing 128
sample
LINKQRY 123
MASTAPP 20, 183
TWOFORMS 95
starting 173
upsizing 140142
ApplyRange method 51, 73
arithmetic operators 177
arrays 65, 72, 73
indexes 74
queries 122
stored procedures 139
AsBoolean property 35
ASCII files 6, 70
AsDateTime property 35
AsFloat property 35
AsInteger property 35
assigning values 37, 154
at run time 87, 88
calculated fields 6869, 8283
default 109, 154
names as 122
required 154
run-time 35
to buttons 114
to combo boxes 109
assignment statements 86
AsString property 35
asynchronous communication
module 144
attaching to servers 5, 8, 56
remote databases 130133
Connected property
and 134
connection
parameters 131132
login parameters 133
attributes See display attributes;
properties
AUTO ODBC setting 132
AutoCalcFields property
OnCalcFields event and 68
AutoDisplay property 108, 109
AutoEdit property 22, 77, 101
automatically translating data 12
AutoSize property 102
AutoUnload property 88
averages 176
AVG function 176
Index
187
B
batAppend constant 89
batAppendUpdate constant 89
batch move operations 8, 75,
8992
error handling 92
BatchMove method 75
batCopy constant 89
batDelete constant 89
batUpdate constant 89
BDE (Borland Database
Engine) 2, 1618, 92
retrieving information 57
BDE Configuration Utility 5,
171174
starting 171
BDE Configuration Utility
Window 171
BeforeCancel event 68
BeforeClose event 63, 68
BeforeDelete event 68
BeforeEdit event 68
BeforeInsert event 68
BeforeOpen event 68
BeforePost event 68
binary collation sequence 142
binary large objects See BLOBs
bitmaps 99, 108, 110
BLOB data 107
type compatibility 181
BLOBs 99, 108
BLROM800.LD 142
BOF property 61
bookmarks 6667
Boolean properties 84
Boolean types 86
Borland Database Engine See
DBE
Borland SQL Links 142, 170
borrowing table structures 155
Browse mode (datasets) 58
BRPARTS.DFM 22
Btrieve databases 132
buffers 60
clearing 107
flushing 67
building applications 19
building databases 1216, 147
building forms 1930
multi-table 2430
single-table 2124
buttons 78
See also specific type
adding 99, 100
assigning values to 114
188
C
CalcFields mode (datasets) 58,
69
calculated fields 9, 3739, 58
assigning values 6869, 8283
defining 81, 82, 83
ordering 179
updating 38
Calculated property 33, 83
Cancel method 64
Cancel navigator button 107
canceling current operation 64,
101, 107
canceling method calls 68
CancelRange method 51, 73
CanModify property 63, 75, 120
Caption property
check boxes 113
case
conversions 177
sensitivity 75
centering data 83
ChangedTableName
property 92
changing
See also editing
aliases 173
component names 23
data 6366, 100, 101
abandoning changes 64,
101, 107
committing changes 135,
136, 137
edit boxes and 36
rolling back changes 136
single-table queries 48
datasets 78
events 82, 83, 85
property values 82, 8384
table structures 159161
tables 181
values See updating values
character sets 89
character strings See string lists;
strings
check boxes 100, 113
checking for null values 73
child tables 157
Clear method 118
clearing data buffers 107
client platforms 16
client/server applications 14,
118, 127145
deploying 142145
developing 127129
handling security 132133
transaction control 135138
client-based SQL 175
Clipboard 108
Close method
datasets 60
queries 118, 122
code 23, 87
changing data 36
optimizing 61
collation sequence 142
colon (:) in SQL statements 117,
176
column headings See field names
columns
See also field names; fields
combo boxes and
multiple 111
outlining 104
combo boxes 99, 109112
assigning values 109
multiple columns 111
sorting items 110
user input and 4446
Commit method 136
COMMIT statements 135
commiting changes 135, 136, 137
communication protocols 128,
131
comparison operators 177
Component palette 6
components 2
data-aware 10, 87, 100
disabling/enabling 67
database 6, 8, 11, 5556, 133
dataset 100
field 3032
referencing 34
renaming 23
composite keys 153
concatenation operator 177
configuration files 171
configuration options 173
configuring drivers 131
confirming deletions 68, 104
Connect method 89
CONNECT.EXE 143
CONNECT.HLP 143
Connected property 134
connections (server) 5, 56
inactive 56
remote databases 8, 130133
Connected property
and 134
connection
parameters 131132
login parameters 133
controls
See also components
data 99114
read-only 101, 108
graphics 109
conversions
batch move operations
and 91
case 177
numbers to strings 35
strings to date/time 173
strings to numbers 36, 173
Copy command (Database
Desktop) 166
Copy dialog box (Database
Desktop) 166
copying
data 75, 166
table structures 8, 75
text 108
CopyToClipboard method 108
COREWIN.DLL 142
COUNT function 177
counting function 177
CREATE INDEX keyword 182
Create Table dialog box
(Database Desktop) 151152
SQL tables 155
CREATE TABLE keyword 180
creating
forms 1930
multi-table 2430, 9395
single-table 2124
indexes 182
new tables 89, 151, 155
Paradox tables 151, 158
SQL tables 155
csDropDown constant 110
csDropDownList constant 110
csOwnerDrawFixed
constant 110
csOwnerDrawVariable
constant 110
csSimple constant 110
Currency property 83
current date and time 46
current field 4, 165
current operation,
canceling 101, 107
D
data
accessing 79, 89, 100, 115, 116
at run time 8788
field values 30, 32
optimizing access 119
remote servers 127, 141
adding 100101, 154
automatically 158
predefined values 109
to grids 103
automatically translating 12
changing 6366, 100, 101
abandoning changes 64,
101, 107
committing changes 135,
136, 137
edit boxes and 36
rolling back changes 136
single-table queries 48
confirming deletions 68, 104
copying 75, 166
defined 5
deleting See deleting
displaying 9, 83, 161164
at run time 87
current values 34, 102
in grids 83, 103, 105
multiple views 9597
display-only 82, 84, 102, 107
truncated 102
editing 6364, 83, 99, 102
canceling current
operation 64, 101, 107
Database Desktop
and 164165
in grids 104
restrictions 164
filtering 5051
formatting 3942, 83, 85
at run time 4042
invalid, restricting 43
porting 127129
retrieving 8, 7274
from multiple tables 178,
179
specific values 179
specifying conditions 178
searching for 4243, 7072
in unkeyed fields 47
nearest match 71, 72
sorting 74, 152, 166, 173
typing to replace 164
updating 63, 6566, 101, 107
batch move operations 89
calculated fields 38
handing events 78
multiuser applications 65
read-only results 120
Refresh method and 67
validating 4347
Data Access page (Component
palette) 710
data buffers 60
clearing 107
flushing 67
data controls 99114
inactive 51, 77
linking to datasets 67, 100,
101
Data Controls page (Component
palette) 1011, 99100
data definition 13
Data Definition Language
180182
data entry forms 102, 158, 183
data grids 99, 103106
adding 103
displaying data 83
editing data 104
inserting records 104
linking to datasets 103
options 103104
Data Manipulation Language
(DML) 176179
data masks 84
data sources 2, 7778
accessing 5, 99
networks and 5
adding 100
changing datasets 78
handling events 78
lists 111
supported 6
data templates 83, 84, 154
data types See types
data-aware components 10, 87,
100
disabling/enabling 67
Index
189
190
retrieving information 57
sample 183186
Databases property 56
DataField property 45, 100
check boxes 113
combo boxes 110
dataset components 100
DataSet property 23, 77
datasets 5769, 113
changing 78
closing 59
current state 59
data sources and 77
defining 32
handling events 6869
linking to data controls 67,
100, 101
linking to data grids 103
modes 5859
moving through 6062
opening 59
rights and privileges 75
DataSource property 100, 123
date functions 177
Date Manager page (BDE
Configuration Utility) 173
dates 40, 85, 173
conversion functions 86
getting current 46
returning 177
DAY constant 177
.DB files 6, 70
DB2 databases 132
dBASE tables 5, 6, 70, 175
batch move operations
and 90
deleting 182
indexes 74, 153, 182
memo fields 108
naming 175
retrieving data 73
searching for data 70, 72
setting ranges 50
specifying directories 69, 149
type compatibility 180181
DBD.EXE 147
DBDEMOS alias 20
.DBF files 6, 70
DBHandle function 93
DBIPROCS.PAS 93
DBITYPES.PAS 93
DBLocale function 93
DBMS 1
DBNMP3.DLL 143
DDL See Data Definition
Language
default settings 85, 173
dynamic queries 48
dynamic SQL statements
121124
defined 117
E
edit boxes 99, 102
See also combo boxes
changing data 36
Edit Data command (Database
Desktop) 164
Edit method 63
Edit mode 107
Database Desktop 164, 165
datasets 58, 63, 77
CanModify property
and 63
Edit navigator button 107
EditFormat property 83, 103
editing
See also changing
data 6364, 83, 99, 102
canceling current
operation 64, 101, 107
Database Desktop
and 164165
in grids 104
restrictions 164
graphics 108
text 108
editing methods 108
EditMask property 33, 41, 83, 84
editors
Database Properties 134
Fields See Fields Editor
Input Mask 84
Parameters 121, 122, 138
SQL 167169
String List 109, 117
EditRangeEnd method 73
EditRangeStart method 73
EDORDERS.DFM 38
EMPLOYEE.DB 183
Empty command (Database
Desktop) 165
EmptyTable method 75
EnableControls method 50, 51,
61, 67
Enabled property 77, 101
entering SQL statements
117119, 120
at run time 118, 122
EOF property 61
errors 92
Esc key 101
F
fetching data See retrieving data
field components 3032
Field Link Designer 7677
Field Link Designer dialog
box 76
field names 83
ANSI-standards 176
assigning as values 122
disabling 104
resizing columns 163
field properties 3234
changing 83
field types See types
field values See values
field view 165
FieldByName method 8788
FieldName property 33, 83
fields 4, 3043
adding 31, 79, 181
Fields Editor 81
calculated 9, 3739, 58
assigning values 6869,
8283
defining 81, 82, 83
ordering 179
updating 38
current 4, 165
default settings 85
defining 152
deleting 81, 181
display-only 82, 84
Index
191
192
flickering screens 67
floating-point numbers 86
flushing data buffers 67
focus, setting 85
FocusControl method 85
Form Expert See Database Form
Expert
FormatDateTime routine 85
FormatFloat routine 85
FormatInteger routine 85
formatting data 3942, 83, 85
at run time 4042
formatting text 40
forms 1930
data entry 102, 158, 183
designing 100
multi-table 2430, 76
creating 9395
order entry 93, 112
printing 53
running 21
single-table 2124
FreeBookmark method 67
freeing memory 67
functions
See also methods; routines
aggregate 141, 176177, 179
date 177
mathematical 141
search 70
string manipulation 177
G
.GDB files 6
GDS.DLL 143
GetAliasNames method 57
GetAliasParams method 57
GetBookmark method 67
GetDatabaseNames method 57
GetDriverNames method 57
GetDriverParams method 57
GetIndexNames method 74
GetTableNames method 57
GoToBookmark method 67
GoToCurrent method 76
GoToKey method 70
GoToNearest method 70, 71, 72
graphics 108
displaying large 109
editing 108
grids See data grids
H
Handle function 93
handles 93
I
icons
Data Access page 7
Data Controls page 10
IDAPI.CFG 171
IDAPI.CNF 17
IDAPI01.DLL 17
IDAPICFG.EXE 17, 171
IDAPICFG.HLP 17
IDASCI01.DLL 17
IDBAT01.DLL 17
IDDBAS01.DLL 17
IDODBC01.DLL 17
IDPDX01.DLL 17
IDQRY01.DLL 17
IDR10009.DLL 17
ILD01.DLL 17
image boxes 99
images 108
scrolling through 109
inactive data controls 51, 77
inactive database connections 56
Inactive mode (datasets) 58
Index property 33, 83
indexes 7475, 152154, 180
See also key fields
creating 182
deleting 182
naming 156
primary 74
secondary 71, 72, 74, 154, 182
SQL tables 153154, 155157,
160
IndexFieldCount property 74
IndexFieldNames property 50,
71
IndexFields property 74
IndexName property 71, 74
Informix servers 143
Informix tables 6, 90, 91
transactions 138
inheritance 55
InitialValues property 88
inner joins 178
input focus 85
J
joins 178
heterogeneous 179
K
KeepConnections property 56,
134
key fields 83, 152
See also indexes
partial keys and 73
specifying 50
key violations 92
M3OPEN.DLL 144
M3OPEN.EXE 144
maintaining database
connections 134
Mappings property 91
masks 84
MAST sample database 183186
MASTAPP sample
application 20, 183
master tables 24, 7677, 9395
MasterFields property 76
MasterSource property 76, 94
mathematical functions 141
MAX function 177
maximum values 51, 83, 154, 177
MaxLength property 108
MaxValue property 83
MBW.EXE 144
memo boxes 99
memo fields 108
memory, freeing 67
memos 107108
scrolling through 108
menu items 78
messages 71
metadata 138, 141
methods
See also functions; procedures
bookmarks 67
canceling calls 68
editing 108
MFTP.EXE 144
MHPARPA.DLL 144
Microsoft Access databases 132
Microsoft Named Pipes
protocol 144
Microsoft SQL servers 6, 142
transactions 138
MIN function 176
minimum values 51, 83, 154, 176
minus () sign in property
lists 104
MINUTE constant 177
MinValue property 84
MNETONE.EXE 144
MNOVLWP.DLL 144
labels 101102
language drivers 142, 143
large images 109
Last method 60
Last navigator button 106
LDLLSQLW.DLL 143
left justifying data 83
LIBS See InterBase Server
linking data controls to
datasets 67, 100, 101
linking data grids to datasets 103
linking queries 123
linking tables 94, 150
one-many-many links 27
one-to-many links 24, 76
LINKQRY sample
application 123
list boxes 99, 100, 109, 110
See also combo boxes
lists 111
scrolling through 110, 112
sorting items 110
string See string lists
user input and 4445
live results 48, 120
See also SQL queries
LoadFromFile method 118
local buffers 60
clearing 107
flushing 67
Local Interbase Server (LIBS) See
InterBase Server
Locale function 93
locating field values 42, 7072
nearest match 71, 72
locking tables 75
loColLines constant 111
logical operators 177
Login dialog box 132
login parameters 133
LoginPrompt property 133
lookup lists 111
lookup tables 4546, 158
LookupDisplay property 45, 111
Index
193
Mode property 89
modifying See changing
monetary values 83, 85
MONTH constant 177
mouse events 101, 105
MoveBy method 62
MoveCount property 92
moving
cursors 6062, 72, 78
fields 163
at run time 105
text 108
moving among fields 104, 165
Tab key and 101, 104
moving through images 109
moving through lists 110, 112
moving through memos 108
moving through tables 6062,
104
Database Desktop and 162,
165
MPATHWAY.DLL 144
MPCNFS.EXE 144
MPCNFS2.EXE 144
MPCNFS4.DLL 144
MSOCKLIB.DLL 144
multi-line text 107
multiple query statements 118
multi-table forms 2430, 76
creating 9395
Paradox tables 157, 158
multi-table queries 124, 178
heterogeneous joins 179
multiuser applications 5, 135,
147
See also client/server
applications; networks
updating data 65
MVWASYNC.EXE 144
MWINTCP.EXE 144
N
Name property 32, 33, 84
naming
directories 149
fields 176
indexes 156
tables 175
navigator See database navigator
nbDelete constant 23
nbNext constant 23
NetFileDir property 57
networks 127, 144, 149
accessing 5
temporary files and 149
194
Next method 60
Next navigator button 106
Next Record buttons 23
NEXTORD.DB 183
nil values 65
NOT operator 177
NOT SHARED setting 137
Novell SPX/IPX interface 131,
144
Now function 46
null values 65, 121
checking for 73
stored procedures 139
Number Manager page (BDE
Configuration Utility) 173
numbers
conversion functions 86
converting
strings to 36, 173
to strings 35
numeric fields 83, 154, 176
displaying values 83
in edit boxes 35, 36
NWCALLS.DLL 144
NWIPXSPX.DLL 144
O
object hierarchy 7, 55
Object Inspector
displaying property
values 32, 33, 103
ODBC data sources 6
ODBC driver 132, 138
ODBC.NEW 17
ODBCINST.NEW 17
OEM conversion 93
OnCalcFields event 38, 58,
6869, 82
OnColEnter event 105
OnColExit event 105
OnDataChange event 78
OnDblClick event 105
OnDragDrop event 105
OnDragOver event 105
OnDrawDataCell event 105, 106
one-many-many links 27
OnEndDrag event 106
OnEnter event 106
one-to-many links 24, 76
OnExit event 106
OnGetText event 85
OnKeyDown event 106
OnKeyPress event 106
OnKeyUp event 106
OnLogin event 133
OnNewRecord event 68
OnSetText event 85
OnStateChange event 59, 78
OnUpdateData event 78
OnValidate event 43, 46
Open command (Database
Desktop) 148, 161
Open method
datasets 59
queries 119
Open Table dialog box (Database
Desktop) 161
opening
datasets 59
files 148
queries 168
tables 161
at run time 23
operators (local SQL
statements) 177
optimizing applications 128
optimizing code 61
optimizing queries 121
Options property
combo boxes 111
data grids 103
OR operator 177
ORA6WIN.DLL 142
ORA7WIN.DLL 142
Oracle servers 142
Oracle tables 6, 90, 91
stored procedures 140
transactions 138
ORAWE850.LD 142
order entry forms 93, 112
ORDERS.DB 24, 183
OS.IEM 143
outer joins 178
outlining records and fields 104
output 53
Overload property 140
overloading stored
procedures 140
P
Paradox tables 5, 6, 70, 175
batch move operations
and 90
creating 151, 158
deleting 182
indexes 74, 152, 154, 182
key fields 152
memo fields 108
multi-table forms 157
lookup tables and 158
naming 175
Q
QBE (defined) 169
queries 9, 4750, 169170
See also SQL queries
deleting 166
dynamic 48
multi-table 124, 178
heterogeneous joins 179
opening 168
renaming 166
single-table 48
specifying table names 9
static 47
query by example (defined) 169
Query component 115, 117
question mark (?) in SQL
statements 176
quotation mark ("), naming
conventions 175, 176
R
radio buttons 100, 114
ranges 5051, 73
canceling 51
maximum values 51
minimum values 51
RDS.IEM 143
read-only controls 101, 108
graphics 109
read-only privileges 75
ReadOnly property 33, 75, 84
CanModify property and 63
read-only results 48, 120
See also SQL queries
ReCalcReport method 89
records
adding 64, 65, 106, 165
batch move operations 89
data grids and 104
current 4, 60, 104, 165
indicator, setting 104
setting 106
data grids and 103, 105
deleting 64, 75, 104, 165
batch move operations 89
moving through 6062
ordering 152, 179
outlining 104
posting 63, 64, 102, 105
automatically 107
resizing 163
selecting 104, 106, 165
specific sets 47, 50
updating See updating data
Redistributable BDE 16
redrawing screens 105, 108, 109
referencing components 34
referential integrity 157158
Referential Integrity dialog box
(Database Desktop) 158
Refresh method 67
Refresh navigator button 107
relational databases 150
See also databases
releasing memory 67
remote servers 5, 127
aliases and 149
connecting to 8, 130133, 134
deploying applications
142145
developing applications 12,
15
REMOTE.DLL 143
removing See deleting
Rename command (Database
Desktop) 166
Index
195
196
S
sample applications
LINKQRY 123
MASTAPP 20, 183
TWOFORMS 95
sample database 183186
saving
aliases 172, 173
SQL statements 118, 169
screens
flickering 67
redrawing 105, 108, 109
script files 118
scroll bars 108
scroll locks 162
ScrollBars property 108
scrolling through images 109
scrolling through lists 110, 112
scrolling through text 108
search conditions (SQL
queries) 178
search functions 70
search mode 70
searching for data 4243, 7072
in unkeyed fields 47
nearest match 71, 72
SECOND constant 177
secondary indexes 154
deleting 182
searching on 71, 72, 74
security 132133
SECURITY.IEM 143
Select Alias command (Database
Desktop) 168
Select Alias dialog box
(Database Desktop) 168
SELECT keyword 178
SELECT statements 118, 120,
178179
selecting
See also searching for data
fields 104, 165
Tab key and 101, 104
records 104, 106, 165
specific sets 47, 50
selection bars (grids) 104
servers 5, 6, 127
aliases and 149
connecting to See connections
developing applications See
client/server applications
Session component 56
set functions 176177, 179
SetFields method 65
SetKey method 70, 71
SetKey mode (datasets) 58, 70
SetRange method 73
SetRangeEnd method 51, 73
SetRangeStart method 51, 73
setting locks 75
setting property values 32
SetVariable method 89
SHARED AUTOCOMMIT
setting 137
SHARED NOAUTOCOMMIT
setting 137
Show SQL command (Database
Desktop) 168
ShowHint property 107
ShowMessage function 71
single quote (), naming
conventions 175, 176
single-table forms 2124
single-table queries 48
Size property 84
Sort command (Database
Desktop) 166
sort order 74
Sort Table dialog box (Database
Desktop) 166
Sorted constant 110
sorting data 74, 152, 166
configuration options 173
sorting items in lists 110
source tables 8992
specifying aliases 134, 172
spreadsheets 99
SQL database servers 6
SQL Editor (Database
Desktop) 167169
saving statements 169
starting 168
SQL Editor window (Database
Desktop) 167
SQL keywords
ALTER TABLE 181
COMMIT 135
CREATE INDEX 182
CREATE TABLE 180
DELETE 179
DROP INDEX 182
DROP TABLE 182
INSERT 179
naming conventions 175, 176
ROLLBACK 135
SELECT 178
UPDATE 179
SQL13WIN.DLL 142
SQLD_IB.DLL 143
SQLD_IB.HLP 143
SQLD_INF.DLL 143
SQLD_INF.HLP 143
SQLD_ORA.DLL 142
SQLD_ORA.HLP 142
SQLD_SS.DLL 142
SQLD_SS.HLP 142
SQLPASSTHRUMODE
setting 136, 136137
SQLWIN.DLL 142
starting
applications 173
BDE Configuration
Utility 171
Database Form Expert 21
Fields Editor 80
Input Mask Editor 84
Parameters Editor 138
StartTrans method 136
StartTransaction method 136
State property 59
static queries 47
static SQL statement
(defined) 117
stored procedures 8, 57, 138140
executing 139
overloading 140
parameters 138139
StoredProcName property 138
String List Editor 109
entering SQL statements 117
string lists 117
associating with buttons 114
sorting items 110
string manipulation
functions 177
strings 73
concatenating 177
conversion functions 86
converting
case 177
to date/time 173
to numbers 36, 173
picture 83, 84, 154
removing repeating
characters 177
returning parts of 177
Structured Query Language See
SQL
Style property
combo boxes 110
subqueries 178, 179
SUBSTRING function 177
T
Tab key 101
tabbing through fields 101, 104
Table Type dialog box (Database
Desktop) 151
Table window (Database
Desktop) 161
TableName property 22, 69
tables 4, 180
adding 8
Database Desktop
149161
Answer 170
changing 181
child 157
configuration options 173
creating new 89, 151, 155
Paradox 151, 158
SQL 155
customizing views 162164
deleting 75, 166, 182
destination 8992
detail 24, 7677, 9395
linking 94, 150
one-many-many links 27
one-to-many links 24, 76
locking 75
locking columns 162
lookup 4546, 158
master 24, 7677, 9395
moving through 6062, 104
Database Desktop
and 162, 165
multiple views 9597, 180
naming, ANSI standards 175
opening 161
at run time 23
parent 157
placing bookmarks 6667
renaming 166
retrieving information 57
source 8992
Index
197
.TXT files 6
text 108
See also data
adding 107
aligning 108
editing 108
formatting 40
scrolling through 108
wordwrapping 108
text files 6, 70
text strings See string lists; strings
TField component 30, 33, 40,
7987, 100
disabling 103
instantiating 103
overview 8
referencing 34
TFloatField type 84, 85, 86
TGraphicField type 86
tiDirtyRead constant 137
time 85, 173
conversion functions 86
returning 177
Time Manager page (BDE
Configuration Utility) 173
timer events 101
timestamps 46
TIMEZONE_HOUR clause 177
TIMEZONE_MINUTE
clause 177
TIntegerField type 85, 86
tiReadCommitted constant 137
tiRepeatableRead constant 137
TMemoField type 86
tool bars 22
Database Desktop
windows 148, 161, 168
totaling numeric values 176
TQuery component 57, 100,
115117
overview 6, 8, 910
TDataSource and 10
TTable vs. 116, 120
transactions 100, 128, 135138
implicit vs. explicit
control 136
isolation levels 137138
TransIsolation property 137
translating data 12
Transliterate property 89
TReport component 8, 52, 8889
TRIM function 177
truncated data 102
try...except blocks 119
try...finally blocks 51, 61, 67
TSession component 5657, 134
U
UniDirectional property 119
unique indexes 153, 156
UnPrepare method 122
UPDATE keyword 179
UPDATE statements 120
UpdateMode property 6566
updating data 63, 6566, 101,
107
batch move operations 89
calculated fields 38
handling events 78
multiuser applications 65
read-only results 120
Refresh method and 67
updating queries 50
UPPER function 177
uppercase conversions 177
upsizing desktop databases 130,
140142
Utilities menu (Database
Desktop) 165
V
validity checks 4347, 154
types 43
Value property 86
ValueChecked property 113
values
accessing 30, 32
assigning 37, 154
at run time 87, 88
calculated fields 6869,
8283
default 109, 154
names as 122
required 154
run-time 35
to buttons 114
to combo boxes 109
averaging 176
changing
edit boxes and 36
changing See updating data
converting
numbers to strings 35
string to date/time 173
string to numbers 36, 173
counting 177
currency 83, 85
display formats 85
displaying current 34, 102
finding 42, 7072
nearest match 71, 72
minimum/maximum 83, 154
aggregate functions
176177
specifying 51
nil 65
null 65, 121
checking for 73
stored procedures 139
predefined 109
property
accessing 40, 86
changing 82, 8384
displaying 32, 103
setting 32
restoring previous 64, 101,
107
retrieving specific 179
rounding 86
totaling 176
typing to replace entries 164
updating See updating data
Values property 114
ValueUnchecked property 113
variables
local SQL statements 176, 180
VBX controls 16
VENDOR.DB 183
vertical dividing lines, enabling/
disabling 104
viewing See displaying
W
W3DBLIB.DLL 143
WhereAll constant 66
WhereChanged constant 66
WhereKeyOnly constant 66
Windows for Workgroups 144
Windows ISQL 129
Winsock 1.1 compliant TCP/IP
products 144
WINSOCK.DLL 144
WordWrap property 108
wordwrapping text 108
working directories
(:WORK:) 149
Working Directory command
(Database Desktop) 149
write privileges 75
Index
199
Database Application
Developers Guide
Delphi
Borland may have patents and/or pending patent applications covering subject matter in this document. The
furnishing of this document does not give you any license to these patents.
COPYRIGHT 1995 Borland International. All rights reserved. All Borland products are trademarks or registered
trademarks of Borland International, Inc. Other brand and product names are trademarks or registered trademarks of
their respective holders.
9596979899-987654321
W1
Contents
Chapter 1
Introduction
What is data? . . . . . . . . . . . . . . . . . . . . .5
What is data access? . . . . . . . . . . . . . . . . .5
Data sources . . . . . . . . . . . . . . . . . . . . . .6
Chapter 3
Using datasets . . . . . . . . . . . . . . . . . . . . 57
Dataset states . . . . . . . . . . . . . . . . . .
Opening and closing datasets . . . . . . . .
Navigating datasets . . . . . . . . . . . . . .
The Next and Prior methods . . . . . . . .
The First and Last methods . . . . . . . . .
The BOF and EOF properties . . . . . . . .
The MoveBy function . . . . . . . . . . . .
Modifying data in datasets . . . . . . . . . .
The CanModify property . . . . . . . . . .
Posting data to the database . . . . . . . .
Editing records . . . . . . . . . . . . . . . .
Adding new records . . . . . . . . . . . . .
Deleting records . . . . . . . . . . . . . . .
Canceling changes . . . . . . . . . . . . . .
Working with entire records . . . . . . . .
Setting the update mode. . . . . . . . . . .
Bookmarking data . . . . . . . . . . . . . . .
Disabling, enabling, and refreshing
data-aware controls . . . . . . . . . . . . .
Using dataset events. . . . . . . . . . . . . .
Abort a method . . . . . . . . . . . . . . . .
Using OnCalcFields . . . . . . . . . . . . .
Deploying an application . . . . . . . . . . . . . 16
Deploying BDE support . . . . . . . . . . . . . . 16
Language drivers. . . . . . . . . . . . . . . . . 17
ODBC Socket . . . . . . . . . . . . . . . . . . . 18
Chapter 2
19
Building forms . . . . . . . . . . . . . . . . . . . 19
MASTAPP aliases . . . . . . . . .
Building a single-table form. . . .
Building a master-detail form. . .
Building a one-many-many form
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 20
. 21
. 24
. 27
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
58
59
60
60
60
61
62
63
63
63
63
64
64
64
64
65
66
.
.
.
.
.
.
.
.
67
68
68
68
Using TTable. . . . . . . . . . . . . . . . . . . . . 69
Specifying the database table . . . . . . . .
The TableType property . . . . . . . . . . .
Searching a table . . . . . . . . . . . . . . . .
Using Goto functions . . . . . . . . . . . .
Using Find functions. . . . . . . . . . . . .
The KeyExclusive property . . . . . . . . .
Limiting records retrieved by an
application . . . . . . . . . . . . . . . . . .
Using partial keys . . . . . . . . . . . . . .
The KeyExclusive property . . . . . . . . .
55
. 30
. 32
. 34
. 35
. 37
. 39
. 40
i
.
.
.
.
.
.
.
.
.
.
.
.
69
69
70
70
72
72
. . 72
. . 73
. . 74
Indexes . . . . . . . . . . . . . . . . . . . . . . . . 74
The Exclusive property . . . . . . . . . . . . . . 75
Other properties and methods . . . . . . . . . . 75
The ReadOnly and CanModify
properties . . . . . . . . . . . . . . . . . . . . 75
The GoToCurrent method . . . . . . . . . . . 76
Creating master-detail forms . . . . . . . . . . . 76
The Field Link Designer. . . . . . . . . . . . . 76
Using TDataSource . . . . . . . . . . . . . . . . . 77
Using TDataSource properties .
The DataSet property . . . . .
The Enabled property . . . . .
The AutoEdit property . . . .
Using TDataSource events . . .
The OnDataChange event . .
The OnUpdateData event. . .
The OnStateChange event . .
.
.
.
.
.
.
.
.
. . . . . . . . 77
. . . . . . . . 77
. . . . . . . . 77
. . . . . . . . 77
. . . . . . . . 78
. . . . . . . . 78
. . . . . . . . 78
. . . . . . . . 78
TDBComboBox. . .
TDBListBox . . . . .
TDBLookupCombo
TDBLookupList . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.109
.110
.111
.112
115
. 89
. 90
. 92
. 92
.
.
.
.
.
.
.
.
.
.116
.116
.117
.117
.118
.119
.119
.120
.120
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.121
.121
.122
.122
.123
.124
Chapter 4
.
.
.
.
Chapter 5
.
.
.
.
TDBCheckBox . . . . . . . . . . . . . . . . . . . 113
TDBRadioGroup . . . . . . . . . . . . . . . . . 114
.
.
.
.
.103
.104
.105
.105
.105
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Chapter 6
99
127
ii
Client/server communication
portability . . . . . . . . . . . . . . . . . . . . 128
Relational tables . . . . . . . . . . . . . . .
Planning tables . . . . . . . . . . . . . . . .
Creating a new table. . . . . . . . . . . . . .
Defining fields . . . . . . . . . . . . . . . . .
Field names . . . . . . . . . . . . . . . . . .
Adding, deleting, and rearranging
fields . . . . . . . . . . . . . . . . . . . . .
Specifying field type . . . . . . . . . . . . .
Using indexes. . . . . . . . . . . . . . . . . .
Keys in Paradox tables. . . . . . . . . . . .
A dBASE tables index . . . . . . . . . . . .
An SQL tables index. . . . . . . . . . . . .
Defining secondary indexes . . . . . . . . .
Specifying validity checks . . . . . . . . . .
Borrowing a table structure . . . . . . . . .
Creating an SQL table . . . . . . . . . . . . .
Creating indexes on SQL tables . . . . . .
Naming SQL indexes . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. . . . . . . 131
. . . . . . . . 131
. . . . . . . 131
. . . . . . . 132
. . . . . . . 132
.150
.150
.151
.152
.152
.
.
.
.
.
.
.
.
.
.
.
.
.152
.152
.152
.152
.153
.153
.154
.154
.155
.155
.155
.156
Procedure . . . . . . . . . . . . . . . . . . . . . .157
Creating table lookup . . . . . . . . . . . . . . .158
Upsizing . . . . . . . . . . . . . . . . . . . . . . 140
.
.
.
.
.
.
.162
.162
.163
.163
.163
.163
Appendix A
.
.
.
.
.
147
. . . . . .164
. . . . . .165
. . . . . .165
. . . . . .165
Sorting tables . . .
Copying objects .
Renaming objects
Deleting objects .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.166
.166
.166
.166
iii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.167
.168
.168
.169
.169
Using SELECT . . . . . . . . . . . . . . . .
Using the FROM clause . . . . . . . . . .
Using the WHERE clause . . . . . . . . .
Using the ORDER BY clause . . . . . . .
Using the GROUP BY clause . . . . . . .
Heterogeneous joins . . . . . . . . . . . .
Using INSERT . . . . . . . . . . . . . . . .
Using UPDATE . . . . . . . . . . . . . . .
Using DELETE . . . . . . . . . . . . . . . .
Appendix B
.
.
.
.
.
.
.
.
.
.178
.178
.178
.179
.179
.179
.179
.179
.179
Appendix C
175
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.180
.181
.182
.182
.182
Appendix D
176
176
177
177
177
iv
183
Index
187
Tables
1.1
1.2
. .2
.
.
.
.
3.8
3.9
3.10
3.11
3.12
3.13
.4
.6
.8
11
. 17
3.14
. 22
. 22
3.15
. 23
4.1
4.2
4.3
4.4
4.5
. 23
. 26
. 26
.
.
.
.
.
.
.
.
.
.
.
.
.
29
33
40
44
45
52
57
58
60
5.1
6.1
6.2
6.3
6.4
6.5
6.6
6.7
A.1
C.1
C.2
D.1
63
64
68
83
.
.
.
.
.
.
.
.
.
.
.85
.85
.86
.88
.89
. . .90
. . .90
.
.
.
.
.
. .91
. .99
. 104
. 105
. 106
.
.
.
.
.
.
.
.
. 109
. 120
. 138
. 142
. 142
. 143
. 143
. 144
.
.
.
.
.
. 144
. 154
. 180
. 181
. 183
Figures
1.1
1.2
1.3
1.4
1.5
1.6
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11
2.12
2.13
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
4.9
4.10
4.11
4.12
vi