Declarative Part
It is an optional part. However, the declarative part for a
subprogram does not start with the DECLARE keyword. It
contains declarations of types, cursors, constants,
variables, exceptions, and nested subprograms. These
items are local to the subprogram and cease to exist
when the subprogram completes execution.
Executable Part
This is a mandatory part and contains statements that
perform the designated action.
Exception-handling
This is again an optional part. It contains the code that
handles run-time errors.
Creating a Procedure
A procedure is created with the CREATE OR REPLACE PROCEDURE
statement. The simplified syntax for the CREATE OR REPLACE
PROCEDURE statement is as follows:
CREATE [OR REPLACE] PROCEDURE procedure_name
[(parameter_name [IN | OUT | IN OUT] type [, ...])]
{IS | AS}
BEGIN
< procedure_body >
END procedure_name;
Where,
procedure-name specifies the name of the procedure.
[OR REPLACE] option allows modifying an existing procedure.
The optional parameter list contains name, mode and types
of the parameters. IN represents that value will be passed
from outside and OUT represents that this parameter will be
used to return a value outside of the procedure.
procedure-body contains the executable part.
The AS keyword is used instead of the IS keyword for
creating a standalone procedure.
Example:
The following example creates a simple procedure that displays
the string 'Hello World!' on the screen when executed.
CREATE OR REPLACE PROCEDURE greetings
AS
BEGIN
dbms_output.put_line('Hello World!');
END;
/
When above code is executed using SQL prompt, it will produce
the following result:
Procedure created.
Executing a Standalone Procedure
A standalone procedure can be called in two ways:
Using the EXECUTE keyword
N.
1
IN
An IN parameter lets you pass a value to the
subprogram. It is a read-only parameter. Inside the
subprogram, an IN parameter acts like a constant. It
cannot be assigned a value. You can pass a constant,
literal, initialized variable, or expression as an IN
parameter. You can also initialize it to a default value;
however, in that case, it is omitted from the subprogram
call. It is the default mode of parameter passing.
Parameters are passed by reference.
OUT
An OUT parameter returns a value to the calling
program. Inside the subprogram, an OUT parameter acts
like a variable. You can change its value and reference
the value after assigning it. The actual parameter
must be variable and it is passed by value.
IN OUT
An IN OUT parameter passes an initial value to a
subprogram and returns an updated value to the caller. It
can be assigned a value and its value can be read.
The actual parameter corresponding to an IN OUT formal
parameter must be a variable, not a constant or an
expression. Formal parameter must be assigned a
value. Actual parameter is passed by value.
DECLARE
a number;
b number;
c number;
PROCEDURE findMin(x IN number, y IN number, z OUT number) IS
BEGIN
IF x < y THEN
z:= x;
ELSE
z:= y;
END IF;
END;
BEGIN
a:= 23;
b:= 45;
findMin(a, b, c);
dbms_output.put_line(' Minimum of (23, 45) : ' || c);
END;
/
When the above code is executed at SQL prompt, it produces the
following result:
Minimum of (23, 45) : 23
Mixed notation
POSITIONAL NOTATION
In positional notation, you can call the procedure as:
findMin(a, b, c, d);
In positional notation, the first actual parameter is substituted for
the first formal parameter; the second actual parameter is
substituted for the second formal parameter, and so on. So, a is
substituted for x, b is substituted for y, c is substituted for z and d
is substituted for m.
NAMED NOTATION
In named notation, the actual parameter is associated with the
formal parameter using the arrow symbol ( => ). So the
procedure call would look like:
findMin(x=>a, y=>b, z=>c, m=>d);
MIXED NOTATION
In mixed notation, you can mix both notations in procedure call;
however, the positional notation should precede the named
notation.
The following call is legal:
findMin(a, b, c, m=>d);
But this is not legal:
findMin(x=>a, b, c, d);
.FUNCTION
..
A PL/SQL function is same as a procedure except that it returns a
value. Therefore, all the discussions of the previous chapter are
true for functions too.
Creating a Function
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi
| 3 | kaushik | 23 | Kota
| 4 | Chaitali | 25 | Mumbai
| 5 | Hardik | 27 | Bhopal
| 6 | Komal
| 22 | MP
| 1500.00 |
| 2000.00 |
| 6500.00 |
| 8500.00 |
| 4500.00 |
+----+----------+-----+-----------+----------+
CREATE OR REPLACE FUNCTION totalCustomers
RETURN number IS
total number(2) := 0;
BEGIN
SELECT count(*) into total
FROM customers;
RETURN total;
END;
/
When above code is executed using SQL prompt, it will produce
the following result:
Function created.
Calling a Function
While creating a function, you give a definition of what the
function has to do. To use a function, you will have to call that
function to perform the defined task. When a program calls a
function, program control is transferred to the called function.
A called function performs defined task and when its return
statement is executed or when it last end statement is reached, it
returns program control back to the main program.
To call a function you simply need to pass the required
parameters along with function name and if function returns a
value then you can store returned value. Following program calls
the function totalCustomers from an anonymous block:
DECLARE
c number(2);
BEGIN
c := totalCustomers();
dbms_output.put_line('Total no. of Customers: ' || c);
END;
/
When the above code is executed at SQL prompt, it produces the
following result:
Total no. of Customers: 6
PL/SQL procedure successfully completed.
Example:
The following is one more example which demonstrates Declaring,
Defining, and Invoking a Simple PL/SQL Function that computes
and returns the maximum of two values.
DECLARE
a number;
b number;
c number;
FUNCTION findMax(x IN number, y IN number)
RETURN number
IS
z number;
BEGIN
IF x > y THEN
z:= x;
ELSE
Z:= y;
END IF;
RETURN z;
END;
BEGIN
a:= 23;
b:= 45;
c := findMax(a, b);
dbms_output.put_line(' Maximum of (23,45): ' || c);
END;
/
When the above code is executed at SQL prompt, it produces the
following result:
Maximum of (23,45): 45
PL/SQL procedure successfully completed.
PL/SQL Recursive Functions
We have seen that a program or subprogram may call another
subprogram. When a subprogram calls itself, it is referred to as a
recursive call and the process is known as recursion.
BEGIN
num:= 6;
factorial := fact(num);
dbms_output.put_line(' Factorial '|| num || ' is ' || factorial);
END;
/
When the above code is executed at SQL prompt, it produces the
following result:
Factorial 6 is 720 (PL/SQL procedure successfully completed.)
Packages
PL/SQL packages are schema objects that groups logically related PL/SQL
types, variables and subprograms.
A package will have two mandatory parts:
Package specification
Package Specification
The specification is the interface to the package. It just DECLARES the types,
variables, constants, exceptions, cursors, and subprograms that can be
referenced from outside the package. In other words, it contains all
information about the content of the package, but excludes the code for the
subprograms.
All objects placed in the specification are called public objects. Any
subprogram not in the package specification but coded in the package body
is called aprivate object.
The following code snippet shows a package specification having a single
procedure. You can have many global variables defined and multiple
procedures or functions inside a package.
CREATE PACKAGE cust_sal AS
+----+----------+-----+-----------+----------+
| ID | NAME
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 3000.00 |
| 2 | Khilan | 25 | Delhi
| 3 | kaushik | 23 | Kota
| 4 | Chaitali | 25 | Mumbai
| 3000.00 |
| 3000.00 |
| 7500.00 |
| 5 | Hardik | 27 | Bhopal
| 6 | Komal
| 22 | MP
| 9500.00 |
| 5500.00 |
+----+----------+-----+-----------+----------+
THE PACKAGE SPECIFICATION:
CREATE OR REPLACE PACKAGE c_package AS
-- Adds a customer
PROCEDURE addCustomer(c_id customers.id%type,
c_name customers.name%type,
c_age customers.age%type,
c_addr customers.address%type,
c_sal customers.salary%type);
-- Removes a customer
PROCEDURE delCustomer(c_id customers.id%TYPE);
--Lists all customers
PROCEDURE listCustomer;
END c_package;
/
When the above code is executed at SQL prompt, it creates the above
package and displays the following result:
Package created.
CREATING THE PACKAGE BODY:
CREATE OR REPLACE PACKAGE BODY c_package AS
PROCEDURE addCustomer(c_id customers.id%type,
c_name customers.name%type,
c_age customers.age%type,
c_addr customers.address%type,
c_sal customers.salary%type)
IS
BEGIN
INSERT INTO customers (id,name,age,address,salary)
VALUES(c_id, c_name, c_age, c_addr, c_sal);
END addCustomer;
PROCEDURE listCustomer IS
CURSOR c_customers is
SELECT name FROM customers;
TYPE c_list is TABLE OF customers.name%type;
name_list c_list := c_list();
counter integer :=0;
BEGIN
FOR n IN c_customers LOOP
counter := counter +1;
name_list.extend;
name_list(counter) := n.name;
dbms_output.put_line('Customer(' ||counter|| ')'||name_list(counter));
END LOOP;
END listCustomer;
END c_package;
/
Above example makes use of nested table which we will discuss in the next
chapter. When the above code is executed at SQL prompt, it produces the
following result:
Package body created.
USING THE PACKAGE:
The following program uses the methods declared and defined in the
packagec_package.
DECLARE
code customers.id%type:= 8;
BEGIN
c_package.addcustomer(7, 'Rajnish', 25, 'Chennai', 3500);
c_package.addcustomer(8, 'Subham', 32, 'Delhi', 7500);
c_package.listcustomer;
c_package.delcustomer(code);
c_package.listcustomer;
END;
/
When the above code is executed at SQL prompt, it produces the following
result:
Customer(1): Ramesh
Customer(2): Khilan
Customer(3): kaushik
Customer(4): Chaitali
Customer(5): Hardik
Customer(6): Komal
Customer(7): Rajnish
Customer(8): Subham
Customer(1): Ramesh
Customer(2): Khilan
Customer(3): kaushik
Customer(4): Chaitali
Customer(5): Hardik
Customer(6): Komal
Customer(7): Rajnish
TRIGGER
Triggers are stored programs, which are automatically executed or fired when
some events occur. Triggers are, in fact, written to be executed in response
to any of the following events:
Triggers could be defined on the table, view, schema, or database with which
the event is associated.
Benefits of Triggers
Triggers can be written for the following purposes:
Auditing
Creating Triggers
The syntax for creating a trigger is:
[OF col_name]: This specifies the column name that would be updated.
[ON table_name]: This specifies the name of the table associated with
the trigger.
[REFERENCING OLD AS o NEW AS n]: This allows you to refer new and
old values for various DML statements, like INSERT, UPDATE, and
DELETE.
[FOR EACH ROW]: This specifies a row level trigger, i.e., the trigger
would be executed for each row being affected. Otherwise the trigger
will execute just once when the SQL statement is executed, which is
called a table level trigger.
WHEN (condition): This provides a condition for rows for which the
trigger would fire. This clause is valid only for row level triggers.
Example:
To start with, we will be using the CUSTOMERS table we had created and
used in the previous chapters:
Select * from customers;
+----+----------+-----+-----------+----------+
| ID | NAME
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi
| 3 | kaushik | 23 | Kota
| 4 | Chaitali | 25 | Mumbai
| 5 | Hardik | 27 | Bhopal
| 6 | Komal
| 22 | MP
| 1500.00 |
| 2000.00 |
| 6500.00 |
| 8500.00 |
| 4500.00 |
+----+----------+-----+-----------+----------+
The following program creates a row level trigger for the customers table
that would fire for INSERT or UPDATE or DELETE operations performed on the
CUSTOMERS table. This trigger will display the salary difference between the
old values and new values:
CREATE OR REPLACE TRIGGER display_salary_changes
BEFORE DELETE OR INSERT OR UPDATE ON customers
FOR EACH ROW
WHEN (NEW.ID > 0)
DECLARE
sal_diff number;
BEGIN
sal_diff := :NEW.salary - :OLD.salary;
dbms_output.put_line('Old salary: ' || :OLD.salary);
dbms_output.put_line('New salary: ' || :NEW.salary);
dbms_output.put_line('Salary difference: ' || sal_diff);
END;
/
When the above code is executed at SQL prompt, it produces the following
result:
Trigger created.
Here following two points are important and should be noted carefully:
OLD and NEW references are not available for table level triggers,
rather you can use them for record level triggers.
If you want to query the table in the same trigger, then you should use
the AFTER keyword, because triggers can query the table or change it
again only after the initial changes are applied and the table is back in
a consistent state.
Above trigger has been written in such a way that it will fire before any
DELETE or INSERT or UPDATE operation on the table, but you can write
your trigger on a single or multiple operations, for example BEFORE
DELETE, which will fire whenever a record will be deleted using DELETE
operation on the table.
Triggering a Trigger
Let us perform some DML operations on the CUSTOMERS table. Here is one
INSERT statement, which will create a new record in the table:
INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (7, 'Kriti', 22, 'HP', 7500.00 );
When a record is created in CUSTOMERS table, above create
triggerdisplay_salary_changes will be fired and it will display the following
result:
Old salary:
New salary: 7500
Salary difference:
Because this is a new record so old salary is not available and above result is
coming as null. Now, let us perform one more DML operation on the
CUSTOMERS table. Here is one UPDATE statement, which will update an
existing record in the table:
UPDATE customers
SET salary = salary + 500
WHERE id = 2;
When a record is updated in CUSTOMERS table, above create
triggerdisplay_salary_changes will be fired and it will display the following
result:
Old salary: 1500
New salary: 2000
Salary difference: 500
.PL/SQL DATABASE
OBJECT
The Role of Abstraction
An abstraction is a high-level description or model of a real-world entity.
Abstractions keep our daily lives manageable by suppressing irrelevant
detail. For example, to drive a car, you need not know how its engine works.
A simple interface consisting of a gearshift, steering wheel, accelerator, and
brake, lets you use the car effectively. The details of what happens under the
hood are not important for day-to-day driving.
Abstractions are central to the discipline of programming. For example, you
use procedural abstraction when you hide the details of a complex
algorithm by writing a procedure and passing it parameters. To try a different
implementation, you simply replace the body of the procedure. Thanks to
abstraction, programs that call the procedure need not be modified.
You use data abstraction when you specify the datatype of a variable. The
datatype represents a set of values and a set of operations appropriate for
those values. For instance, a variable of type POSITIVE can hold only positive
integers, and can only be added, subtracted, multiplied, and so on. To use
the variable, you do not need to know how PL/SQL stores integers or
implements arithmetic operations.
Suppose you must write a program to allocate employee bonuses. Not all
employee attributes are needed to solve this problem. So, you design an
abstract employee who has the following problem-specific attributes: name,
ID number, department, job title, salary, and rank. Then, you identify the
operations needed to handle an abstract employee. For example, you need
an operation that lets Management change the rank of an employee.
Next, you define a set of variables (attributes) to represent the data, and a
set of subprograms (methods) to perform the operations. Finally, you
encapsulate the attributes and methods in an object type.
The data structure formed by the set of attributes is public (visible to client
programs). However, well-behaved programs do not manipulate it directly.
Instead, they use the set of methods provided. That way, the employee data
is kept in a proper state.
At run time, when the data structure is filled with values, you have created
an instance of an abstract employee. You can create as many instances
(usually called objects) as you need. Each object has the name, number, job
title, and so on of an actual employee (see Figure 10-2). This data is
accessed or changed only by the methods associated with it. Thus, object
types let you create objects with well-defined attributes and behavior.
Figure 10-2 Object Type and Objects (Instances) of that Type
the operations (methods) needed to manipulate the data. The body fully
defines the methods, and so implements the spec.
Figure 10-3 Object Type Structure
All the information a client program needs to use the methods is in the spec.
Think of the spec as an operational interface and of the body as a black box.
You can debug, enhance, or replace the body without changing the spec--and
without affecting client programs.
In an object type spec, all attributes must be declared before any methods.
Only subprograms have an underlying implementation. So, if an object type
spec declares only attributes, the object type body is unnecessary. You
cannot declare attributes in the body. All declarations in the object type spec
are public (visible outside the object type).
To understand the structure better, study the example below, in which an
object type for complex numbers is defined. For now, it is enough to know
that a complex number has two parts, a real part and an imaginary part, and
that several arithmetic operations are defined for complex numbers.
CREATE TYPE Complex AS OBJECT (
rpart REAL, -- attribute
ipart REAL,
MEMBER FUNCTION plus (x Complex) RETURN Complex, -- method
MEMBER FUNCTION less (x Complex) RETURN Complex,
MEMBER FUNCTION times (x Complex) RETURN Complex,
MEMBER FUNCTION divby (x Complex) RETURN Complex
);
Attributes
Like a variable, an attribute is declared with a name and datatype. The name
must be unique within the object type (but can be reused in other object
types). The datatype can be any Oracle type except:
However, STATIC methods are invoked on the object type, not its instances,
as in
object_type_name.method()
g := gcd(SELF.num, SELF.den);
g := gcd(num, den); -- equivalent to previous statement
num := num / g;
den := den / g;
END normalize;
...
END;
From a SQL statement, if you call a MEMBER method on a null instance (that
is, SELF is null), the method is not invoked and a null is returned. From a
procedural statement, if you call a MEMBER method on a null instance,
PL/SQL raises the predefined exception SELF_IS_NULL before the method is
invoked.
Overloading
Like packaged subprograms, methods of the same kind (functions or
procedures) can be overloaded. That is, you can use the same name for
different methods if their formal parameters differ in number, order, or
datatype family. When you call one of the methods, PL/SQL finds it by
comparing the list of actual parameters with each list of formal parameters.
A subtype can also overload methods it inherits from its supertype. In this
case, the methods can have exactly the same formal parameters.
You cannot overload two methods if their formal parameters differ only in
parameter mode. Also, you cannot overload two member functions that differ
only in return type. For more information, see "Overloading Subprogram
Names".
MAP and ORDER Methods
The values of a scalar datatype such as CHAR or REAL have a predefined
order, which allows them to be compared. But instances of an object type
have no predefined order. To put them in order for comparison or sorting
purposes, PL/SQL calls aMAP method supplied by you. In the following
example, the keyword MAP indicates that
method convert() orders Rational objects by mapping them to REAL values:
CREATE TYPE Rational AS OBJECT (
num INTEGER,
den INTEGER,
MAP MEMBER FUNCTION convert RETURN REAL,
...
);
PL/SQL uses the ordering to evaluate Boolean expressions such as x > y, and
to do comparisons implied by the DISTINCT, GROUP BY,
and ORDER BY clauses. MAP method convert() returns the relative position of
an object in the ordering of allRational objects.
An object type can contain only one MAP method. It accepts the built-in
parameter SELF and returns one of the following scalar
types: DATE, NUMBER, VARCHAR2, or an ANSI SQL type such
as CHARACTER or REAL.
Alternatively, you can supply PL/SQL with an ORDER method. An object
type can contain only one ORDER method, which must be a function that
returns a numeric result. In the following example, the
keyword ORDER indicates that methodmatch() compares two objects:
CREATE TYPE Customer AS OBJECT (
id NUMBER,
name VARCHAR2(20),
addr VARCHAR2(30),
ORDER MEMBER FUNCTION match (c Customer) RETURN INTEGER
);
Drop the method in the subtype, then add it back later using ALTER
TYPE without the OVERRIDING keyword.
For more information about the ALTER TYPE statement, see Oracle9i SQL
Reference. For guidelines about using type evolution in your applications,
and options for changing other types and data that rely on see Oracle9i
Application Developer's Guide - Object-Relational Features.
Defining Object Types
An object type can represent any real-world entity. For example, an object
type can represent a student, bank account, computer screen, rational
number, or data structure such as a queue, stack, or list. This section gives
several complete examples, which teach you a lot about the design of object
types and prepare you to start writing your own.
and generates more manageable code. The best-known API is the Open Database
Connectivity (ODBC) standard. DS4_Web1.qxd 23/04/2004 18:39 Page 1 .. 2 |
Appendix E z Programmatic SQL .. E.1 Most DBMSs provide some form of embedded
SQL, including Oracle, INGRES, Informix, and DB2; Oracle also provides an API;
Access provides only an API (called ADO ActiveX Data Objects a layer on top of
ODBC). Structure of this Appendix There are two types of embedded SQL: static
embedded SQL, where the entire SQL statement is known when the program is
written, and dynamic embedded SQL, which allows all or part of the SQL statement
to be specified at runtime. Dynamic SQL provides increased flexibility and helps
produce more general-purpose software. We examine static embedded SQL in
Section E.1 and dynamic embedded SQL in Section E.2. In Section E.3 we discuss
the Open Database Connectivity (ODBC) standard,
Embedded SQL is a method of inserting inline SQL statements or queries into the
code of a programming language, which is known as a host language. Because the
host language cannot parse SQL, the inserted SQL is parsed by an embedded SQL
preprocessor.
In this example, the SQL statement calculates and returns 20 percent of the sale
amount from a TOTAL_SALES table, while the user is expected to input the
SALE_DATE and AGENT_NO values. This SQL query is then inserted inline into the C
code of the front-end module. The C code and SQL query work together to deliver
seamless user results.
.
What Is ODBC?
Open Database Connectivity (ODBC) is a standard that allows programs to read
from almost all of the databases currently available.
This means that Batch can read database formats like Microsoft Access, Paradox,
dBase and FoxPro; spreadsheets like Microsoft Excel; and connect to external
database servers such as Oracle, Informix or Microsoft SQL Server.
Or For A Technical Definition
Open Database Connectivity (ODBC) technology provides a common interface for
accessing heterogeneous SQL databases. ODBC is based on Structured Query
Language (SQL) as a standard for accessing data. This interface provides maximum
interoperability: a single application can access different SQL Database
Management Systems (DBMS) through a common set of code. This enables a
developer to build and distribute a client/server application without targeting a
specific DBMS. Database drivers are then added to link the application to the user's
choice of DBMS.
How Does It Work?
Rather than having to know about each type of database, an application just talks to
an ODBC driver that understands that format.
This means that, once the ODBC driver for a particular type of database is provided,
any program can read databases in that format. If a new database format needs to
be worked with, then all that is required is to install the relevant driver.
The figure above shows how ODBC fits in between an application and the database
it is accessing.
Who Provides ODBC Drivers?
When installing Batch, if the Database Connectivity option is left checked, then
ODBC drivers will be installed for the following database formats: Microsoft Access,
dBase, Excel, FoxPro, Oracle, SQL Server and Paradox.
If you need drivers that are not included then they should be available from the
supplier or manufacturer of the database: check on their web site, as they are often
available free-of-charge.
Tech Note: Batch will not display the new database types unless it has additional
information about the driver, stored in qaworld.ini. However, it is still possible to use
the new driver by using it to establish a Registered ODBC Source.
Batch does not need ODBC to operate, but does require DAO. The System
Components installation option installs all the basics Batch needs; it must be run
on every machine you want to run Batch from.
What Is A Registered ODBC Source?
A Registered ODBC Source is a way of storing all the information needed to make an
ODBC connection: it can then be referred to by a single name the data source
name (DSN).
The application can then establish a connection without needing to know where or
what type of database it is connecting to, making it easy for administrators to move
or update the source.
You would use a Registered ODBC Source when you need to connect to an external
database server it is the only way of doing so or if you frequently connect to a
particular database.
To examine ODBC settings on your machine, go to the Control Panel and open the
ODBC icon. The figure above shows what it looks like on various platforms.
The ODBC Data Source Administrator that starts up displays all the drivers installed
on your machine (under the Drivers tab) along with their version, connections for all
who use your machine (under the System DSN tab) and connections set up solely
for you (under the User DSN tab).
To create a new DSN click on the Add button and use the wizard that appears to set
up all the settings required. Click on Configure to modify an existing DSN.
Can We Batch Data That Is On A Unix/AS400/Mainframe Box?
Yes. All you need is the appropriate ODBC driver (such as the SQL Server driver
provided with QAS Batch) and to set up your server as a Registered ODBC Source.
You might need to provide a username and password in order to make the
connection.
What Happens When You Clean A Database?
The following section explains what database reading and writing goes on during a
Batch run, and what affect this has on Batch cleaning.
The figure above shows a simplified picture of how the cleaning process work.
The location of a session's IDB and all future IDB's can be changed when configuring
a session: it is shown at the bottom of the "Enter Filename" page of the wizard:
modify it by clicking on the Change button.
How Big Is The Intermediate Database?
As the IDB holds original and cleaned address fields as well as the reference fields,
it can be as large as twice the size of the source database. However, it will
frequently be smaller as it does not include any fields or tables that are not part of
the Batch run.
How Can We Delete It?
The IDB is automatically deleted when a session is deleted. It is also deleted when a
fresh Batch run is started on an existing session, or when a fully cleaned session is
Reconfigured and then saved.
The last one is a useful way of reusing a session file say, if the same file is cleaned
periodically without the intermediate database hanging around.
Why Do We Use An Intermediate Database Instead Of Updating As We Go?
Writing data back to the user's database it is a one-way process: it cannot be
undone or rolled back. As Batch frequently deals with customer and contact
databases of immense value to the user, integrity and security are very important.
We wish to support the following functionality:
a. Allow the user to view the cleaned records before they are written.
b. Inform the user of what has been done to the record (match codes).
c. Provide the ability to Interactively clean the addresses.
d. Allow cleaned records to be selectively written back to the original database.
In order to provide all this, it is therefore necessary to hold the original and cleaned
addresses in an intermediate database.
What Is DAO And Why Do We Use It?
It was decided to store the IDB as an Access database rather than plain text as it
allows random access reads, updates, writes, record filtering and multi-user access.
Data Access Objects (DAO) is way of connecting to databases, designed primarily
for Microsoft Access files. It was chosen because it offers superior performance to
ODBC for our purposes.
What Happens During Interactive Cleaning?
Interactive displays the original and cleaned address fields to the user, along with
the match code (what Batch has done and how much confidence it has in the
cleaned record), all of which is read from the intermediate database.
If the user corrects the address or updates it's status then changes will be written
back to the IDB.
Note, therefore, that every Interactive user must have full write access to the
intermediate database, as well as the session file, in order to work successfully.
What Happens When You Commit?
The act of writing the cleaned address records back to the source database is called
a Commit (taken from database terminology). It is a one-way updating procedure.
As mentioned in paragraph 0, Resuming An Automatic Run, the source database can
only be updated in place if it has a unique field identifier. If it does not then the
cleaned address records can be written out to a text file instead.
Once a Commit filter has been chosen, the cleaned records that match it will be
written back to the source database. When Batch writes data back, it simply
overwrites the contents of each output field, then marks the record as committed in
the IDB.
As time has passed between when the source was originally read and the commit,
the following situations can arise:
a. Modification: if changes are made to fields in the source database after the
record is read by Batch, then they will be lost if Batch writes to that field as it
commits.
b. Deletion: if a record has been deleted then Batch will be unable to write the
address back: it will keep track of write failures, which will be displayed in the
commit summary.
c. Write failure: if the record cannot be updated for any other reason then this is
classed as a serious error, which will be reported individually in the summary along
with the reason. Fifty of these errors can occur before the Commit process
terminates.
Write failure could occur because the record is locked if somebody is editing it in
the source database or if the field is read-only to the user running Batch, or if the
database is offline or down.
Note that once a record successfully commits, it no longer appears in any of the
filters. This also means that problem records can easily be traced by running the
Viewer with the filter that was just used to Commit.
Why Did Commit Say "There Are No Records Matching The Specified
Filter"?
As mentioned above, when you Commit, each record that is successfully updated is
then marked as committed and is excluded from all the filters. This means that if
you immediately reapply the same Commit filter then there should no longer be any
record that matches it.