Documente Academic
Documente Profesional
Documente Cultură
1.2.6 Indexes
1.2.7 Keys
A unique key is a key that is constrained so that no two of its values are
equal. The constraint is enforced by DB2 during the execution of the LOAD
utility and the SQL INSERT and UPDATE statements. The mechanism used to
enforce the constraint is a unique index. Thus, every unique key is a key
of a unique index. Such an index is also said to have the UNIQUE
attribute.
Subtopics
1.2.7.1 Primary Keys
1.2.7.2 Foreign Keys
In DB2, a storage structure is a set of one or more VSAM data sets that
hold DB2 tables or indexes. A storage structure is also called a page
set. A storage structure can be one of the following:
table space A table space can hold one or more base tables. All tables
are kept in table spaces. A table space can be defined
using the CREATE TABLESPACE statement.
Defining and deleting the data sets of a storage structure can be left to
DB2. If it is left to DB2, the storage structure has an associated
storage group. The storage group is a list of DASD volumes on which DB2
can allocate data sets for associated storage structures.
1.2.10 Databases
In DB2, a database is a set of table spaces and index spaces. These index
spaces contain indexes on the tables in the table spaces of the same
database. Databases are defined using the CREATE DATABASE statement and
are primarily used for administration. Whenever a table space is created,
it is explicitly or implicitly assigned to an existing database.
1.2.11 Catalog
Each DB2 maintains a set of tables containing information about the data
under its control. These tables are collectively known as the catalog.
The catalog tables contain information about DB2 objects such as tables,
views, and indexes. In contrast, the catalogs maintained by
access method services are known as "integrated catalog facility
catalogs."
Tables in the catalog are like any other database tables with respect to
retrieval. If you have authorization, you can use SQL statements to look
at data in the catalog tables in the same way that you retrieve data from
any other table in the system. Each DB2 ensures that the catalog contains
accurate descriptions of the objects that the DB2 controls.
1.2.12 Views
Views can be used to control access to a table and make data easier to
use. Access to a view can be granted without granting access to the
table. The view can be defined to show only portions of data in the
table. A view can show summary data for a given table, combine two or
more tables in meaningful ways, or show only the selected rows that are
pertinent to the process using the view.
Example: The following SQL statement defines a view named XYZ. The view
represents a table whose columns are named EMPLOYEE and WHEN_HIRED. The
data in the table comes from the columns EMPNO and HIREDATE of the sample
table DSN8310.EMP. The rows from which the data is taken are for
employees in departments A00 and D11.
Read-only views cannot be used for insert, update, and delete operations.
Read-only views are discussed under the CREATE VIEW statement in Chapter 6
of SQL Reference.
Like all result tables, the table represented by a view is not persistent.
On the other hand, the definition of a view persists in the DB2 catalog.
An SQL DROP VIEW statement can drop a view, and the definition of the view
is removed from the catalog. The definition of a view is also removed
from the catalog when any view or base table on which the view depends is
dropped.
The data retrieved through SQL is always in the form of a table. In the
DB2 library, this table is called a result table. Like the tables from
which the data is retrieved, a result table has rows and columns. A
program fetches this data one row at a time.
You do not need to know the column names to select DB2 data. Use an
asterisk (*) in the SELECT clause to indicate "all columns" from each
selected row of the named table.
SELECT *
FROM DSN8310.DEPT;
The SELECT statement example retrieves data from each column (SELECT *) of
each retrieved row of the DSN8310.DEPT table. Because no WHERE clause is
specified, data from all rows are retrieved.
The dashes for MGRNO in the fourth row of the result table indicate that
this value is null. It is null because a manager is not identified for
this department. Null values are described under "Selecting Rows with
Null Values" in topic 2.1.5.1.
Select the column or columns you want by naming each column. All columns
appear in the order you specify, not in their order in the table.
MGRNO DEPTNO
====== ======
000010 A00
000020 B01
000030 C01
------ D01
000050 E01
000060 D11
000070 D21
000090 E11
000100 E21
------ F22
------ G22
------ H22
------ I22
------ J22
The example SELECT statement retrieves data contained in the two named
columns of each row in the DSN8310.DEPT table. You can retrieve one
column or up to as many as 750 columns.
Use a WHERE clause to select data from only the rows that meet certain
conditions. A WHERE clause specifies a search condition. A search
condition consists of one or more predicates. A predicate specifies a
test you want DB2 to apply to each table row.
When a predicate is evaluated for a row, it yields one of the following:
+------------------------------------------------------------------------+
¦ Table 2. Comparison Operators Used in Conditions ¦
+------------------------------------------------------------------------¦
¦ Type of ¦ Specified ¦ Example ¦
¦ comparison ¦ with... ¦ ¦
+--------------------------------+--------------+------------------------¦
¦ Equal to null ¦ IS NULL ¦ PHONENO IS NULL ¦
+--------------------------------+--------------+------------------------¦
¦ Equal to ¦ = ¦ DEPTNO = 'X01' ¦
+--------------------------------+--------------+------------------------¦
¦ Not equal to ¦ <> ¦ DEPTNO <> 'X01' ¦
+--------------------------------+--------------+------------------------¦
¦ Less than ¦ < ¦ AVG(SALARY) < 30000 ¦
+--------------------------------+--------------+------------------------¦
¦ Less than or equal to ¦ <= ¦ AGE <= 25 ¦
+--------------------------------+--------------+------------------------¦
¦ Not less than ¦ >= ¦ AGE >= 21 ¦
+--------------------------------+--------------+------------------------¦
¦ Greater than ¦ > ¦ SALARY > 2000 ¦
+--------------------------------+--------------+------------------------¦
¦ Greater than or equal to ¦ >= ¦ SALARY >= 5000 ¦
+--------------------------------+--------------+------------------------¦
¦ Not greater than ¦ <= ¦ SALARY <= 5000 ¦
+--------------------------------+--------------+------------------------¦
¦ Similar to another value ¦ LIKE ¦ NAME LIKE '%SMITH%' or ¦
¦ ¦ ¦ STATUS LIKE 'N_' ¦
+--------------------------------+--------------+------------------------¦
¦ At least one of two conditions ¦ OR ¦ HIREDATE < ¦
¦ ¦ ¦ '1965-01-01' OR SALARY ¦
¦ ¦ ¦ < 16000 ¦
+--------------------------------+--------------+------------------------¦
¦ Both of two conditions ¦ AND ¦ HIREDATE < ¦
¦ ¦ ¦ '1965-01-01' AND ¦
¦ ¦ ¦ SALARY < 16000 ¦
+--------------------------------+--------------+------------------------¦
¦ Between two values ¦ BETWEEN ¦ SALARY BETWEEN 20000 ¦
¦ ¦ ¦ AND 40000 ¦
+--------------------------------+--------------+------------------------¦
¦ Equals a value in a set ¦ IN (X, Y, Z) ¦ DEPTNO IN ('B01', ¦
¦ ¦ ¦ 'C01', 'D01') ¦
+------------------------------------------------------------------------+
You can also search for rows that do not satisfy one of the above
conditions, by using the NOT keyword before the specified condition. See
"Selecting Rows Using the NOT Keyword or Comparison Operators" in
topic 2.1.5.4 for more information about using the NOT keyword.
Subtopics
2.1.5.1 Selecting Rows with Null Values
2.1.5.2 Selecting Rows by Character or Numeric Data Values
2.1.5.3 Selecting Rows Using Inequalities
2.1.5.4 Selecting Rows Using the NOT Keyword or Comparison Operators
2.1.5.5 Selecting Values Similar to a Character String
A null value indicates the absence of a column value from a row. A null
value is not the same as zero or all blanks.
A WHERE clause can specify a column that, for some rows, contains a null
value. Normally, values from such a row are not retrieved, because a null
value is neither less than, equal to, nor greater than the value specified
in the condition. To select values from rows that contain null values;
specify:
You can also use a predicate to screen out null values, specify:
Use the equal (=) comparison operator to select data only from the rows
that contain a data value in the specified column that is equivalent to
the value specified. To select only the rows where the department number
is A00, use WHERE WORKDEPT = 'A00' in your SQL statement:
The statement retrieves the department number and the first and last name
of each employee in department A00.
The example retrieves the date hired and the name for each employee hired
before 1960.
The NOT keyword cannot be used with the comparison operators. The
following WHERE clause results in an error:
You also can precede other SQL keywords with NOT: NOT LIKE, NOT IN, or
NOT BETWEEN are all acceptable. For example, the following two clauses
are equivalent:
(2) Although the not sign (¬) can be used with comparison
operators, it is not recommended. See Chapter 3 of SQL
Reference for more information on basic predicates.
Use LIKE to specify a character string that is similar to the column value
of rows you want to select:
Subtopics
2.1.5.5.1 Selecting Values Similar to a String of Unknown Characters
2.1.5.5.2 Selecting a Value Similar to a Single Unknown Character
2.1.5.5.3 Selecting a Value Similar to a String Containing a % or an _
The following SQL statement selects data from each row for employees with
the initials "E. H."
could be specified to select all department numbers that begin with E and
end with 1. If E1 is one of your department numbers, it is not selected
because the blank that follows 1 is not taken into account. If the DEPTNO
column had been defined as a three-character column of varying-length,
department E1 would have been selected because varying-length columns can
have any number of characters, up to and including the maximum number
specified when the column was created.
The following SQL statement selects data from each row of the department
table where the department number starts with an E and contains a 1.
The underscore (_) means "any single character." In the following SQL
statement,
'E_1' means "E, followed by any character, followed by 1." (Be careful:
'_' is an underscore character, not a hyphen.) If two-character
department numbers were also allowed, 'E_1' would select only
three-character department numbers that begin with E and end with 1.
The SQL statement below selects data from each row whose four-digit phone
number has the first three digits of 378.
searches for a string starting with AAAA%BBB. The escape character (+) in
front of the first % indicates that the % is a single character and that
it is part of the search string. The second %, which is not preceded by
an escape character, indicates that the string can be followed by any
number of (or no) characters. In this example, putting '++' in the string
would allow you to search for a single plus sign (+) as part of the
string.
The following sections explain ways to use more than one predicate. The
order in which the statement is processed does not depend on the order in
which you specify comparisons. Using parentheses with multiple search
conditions can help control the order of processing.
Subtopics
2.1.6.1 Using AND, OR, and Parentheses to Relate Predicates
2.1.6.2 Using BETWEEN to Specify Ranges to Select
2.1.6.3 Using IN to Specify Values in a List
This example retrieves the employee number, date hired, and salary for
each employee hired before 1965 and having a salary of less than $16,000
per year.
This example retrieves the employee number, date hired, and salary for
each employee who either was hired before 1965, or has a salary less than
$16,000 per year, or both.
If you use more than two conditions with AND or OR, you can use
parentheses to make sure the intended condition is interpreted correctly.
WHERE (HIREDATE < '1965-01-01' AND SALARY < 20000) OR (EDLEVEL < 13)
selects the row of each employee that satisfies at least one of the
following conditions:
_ The employee was hired before 1965 AND is paid less than $20,000.
_ The employee's education level is less than 13.
Based on this WHERE clause, the selected rows are for employees 000290,
000310, and 200310.
With the parentheses moved, however, the meaning of the WHERE clause
changes significantly:
WHERE HIREDATE < '1965-01-01' AND (SALARY < 20000 OR EDLEVEL < 13)
This clause selects the row of each employee that satisfies both of the
following conditions:
Based on this WHERE clause, two rows are selected: one for employee
000310 and one for employee 200310.
The following SQL statement selects the employee number of each employee
that satisfies one of the following conditions:
SELECT EMPNO
FROM DSN8310.EMP
WHERE (HIREDATE < '1965-01-01' AND SALARY < 20000)
OR (HIREDATE > '1965-01-01' AND SALARY > 20000);
When using the NOT condition with AND and OR, the placement of the
parentheses is important.
In this SQL statement, only the first predicate (SALARY >= 50000) is
negated.
This SQL statement retrieves the employee number, education level, and job
title of each employee who satisfies both of the following conditions:
This SQL statement retrieves the employee number, education level, and job
title of each employee who satisfies at least one of the following
conditions:
You can retrieve data from each row whose column has a value within two
limits; use BETWEEN.
Specify the lower boundary of the BETWEEN condition first, then the upper
boundary. The limits are inclusive. If you specify WHERE column-name
BETWEEN 6 AND 8 (and if the value of the column-name column is an
integer), DB2 selects all rows whose column-name value is 6, 7, or 8. If
you specify a range from a larger number to a smaller number (for example,
BETWEEN 8 AND 6), the predicate is always false.
Example
The example retrieves the department number and manager number of each
department whose number is between C00 and D31.
Example
The example retrieves the employee numbers and the salaries for all
employees who either earn less than $40,000 or more than $50,000.
You can use the BETWEEN predicate when comparing floating point data in
your program with decimal data in the database to define a tolerance
around the two numbers being compared. Assume the following:
Possibly wrong:
SELECT *
FROM MYTABLE
WHERE :HOSTVAR = COL1;
The following embedded SQL statement uses a host variable, FUZZ, that
contains a tolerance factor.
Better:
SELECT *
FROM MYTABLE
WHERE :HOSTVAR BETWEEN (COL1 - :FUZZ) AND (COL1 + :FUZZ);
You can use the IN predicate to retrieve data from each row that has a
column value equal to one of several listed values.
In the values list after IN, the order of the items is not important and
does not affect the ordering of the result. Enclose the entire list in
parentheses, and separate items by commas; the blanks are optional.
The example retrieves the department number and manager number for
departments B01, C01, and D01.
Using the IN predicate gives the same results as a much longer set of
conditions separated by the OR keyword. For example, the WHERE clause in
the SELECT statement above could be coded:
The SQL statement below finds any sex code not properly entered.
You can concatenate strings by using the CONCAT keyword. You can use
CONCAT in any string expression. For example,
concatenates the last name, comma, and first name of each result row.
CONCAT is the preferred keyword. See Chapter 3 of SQL Reference for more
information on expressions using the concatenation operator.
Subtopics
2.1.8.1 Using Numeric Data
2.1.8.2 A Warning about 31-Digit Precision for Decimal Numbers
2.1.8.3 Using Datetime Data
You can retrieve calculated values, just as you display column values, for
selected rows.
For example, if you write the following SQL statement:
Here a name is given to each unnamed column to help you follow the
example, although the name shown (for example, SALARY/12) does not appear
when the example is executed through SPUFI. If a column in a result comes
directly from a column in a table, SPUFI uses the column name as a
heading; if the column is the result of a calculation made by DB2, SPUFI
does not give it a heading.
The SELECT statement example displays the monthly and weekly salaries of
employees in department A00.
If you will be using dates, you should assign datetime data types to all
columns containing dates. This not only allows you to do more with your
table but it can save you from problems like the following:
Suppose that in creating the table YEMP (described in "How To Create a New
Department Table" in topic 2.2.1.1.1), you assign data type DECIMAL(8,0)
to the BIRTHDATE column and then fill it with dates of the form yyyymmdd.
You then execute the following query to determine who is 27 years old or
older:
Suppose now that at the time the query is executed, one person represented
in YEMP is 27 years, 0 months, and 29 days old but is not shown in the
results. What happens is this:
If you have existing date data that is not stored in datetime columns, you
can use conversions to avoid errors. The following examples illustrate a
few conversion techniques, given the existing type of data:
_ For DECIMAL(8,0) values of the form yyyymmdd in column C1, use SUBSTR
to isolate the pieces and then use CONCAT to reassemble them in ISO
format (with hyphens):
DATE(SUBSTR(DIGITS(C2),1,4)CONCAT'-'
CONCAT SUBSTR(DIGITS(C2),5,2)
CONCAT'-'CONCAT
SUBSTR(DIGITS(C2),7,2))
Two types of built-in functions are available for use with a SELECT
statement: column and scalar.
Subtopics
2.1.9.1 Using Column Functions
2.1.9.2 Using Scalar Functions
Two types of built-in functions are available for use with a SELECT
statement: column and scalar.
Subtopics
2.1.9.1 Using Column Functions
2.1.9.2 Using Scalar Functions
A column function produces a single value for a group of rows. You can
use the SQL column functions to calculate values based on entire columns
of data which can then be retrieved. The calculated values are based on
selected rows only (all rows that satisfy the WHERE clause).
The following SQL statement calculates for department D11, the sum of
employee salaries, the minimum, average, and maximum salary, and the count
of employees in the department:
DISTINCT can be used with the SUM, AVG, and COUNT functions. DISTINCT
means that the selected function will be performed on only the unique
values in a column. The specification of DISTINCT with the MAX and MIN
functions has no effect on the result and is not advised.
In this case SUM and AVG can only be applied to numbers. MIN, MAX, and
COUNT can be applied to values of any type.
SELECT COUNT(*)
FROM DSN8310.EMP;
SELECT AVG(EDLEVEL)
FROM DSN8310.EMP
WHERE WORKDEPT LIKE '_0_';
The SQL statement below counts the different jobs in the DSN8310.EMP
table.
SELECT YEAR(HIREDATE)
FROM DSN8310.EMP
WHERE WORKDEPT = 'A00';
The scalar function YEAR produces a single scalar value for each row of
DSN8310.EMP that satisfies the search condition. In this example, there
are three rows that satisfy the search condition, so YEAR is applied three
times resulting in three scalar values.
Table 3 shows the scalar functions that can be used. For complete details
on using these functions see Chapter 4 of SQL Reference.
+------------------------------------------------------------------------+
¦ Table 3. Scalar Functions ¦
+------------------------------------------------------------------------¦
¦ Scalar ¦ Returns... ¦ Example ¦
¦ Function ¦ ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ CHAR ¦ a string representation of ¦ CHAR(HIREDATE) ¦
¦ ¦ its first argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ DATE ¦ a date derived from its ¦ DATE('1989-03-02') ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ DAY ¦ the day part of its ¦ DAY(DATE1 - DATE2) ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ DAYS ¦ an integer representation ¦ DAYS('1990-01-08') - ¦
¦ ¦ of its argument. ¦ DAYS(HIREDATE) + 1 ¦
+-------------+-----------------------------+----------------------------¦
¦ DECIMAL ¦ a decimal representation of ¦ DECIMAL(AVG(SALARY), 8,2) ¦
¦ ¦ a numeric value. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ DIGITS ¦ a character string ¦ DIGITS(COLUMNX) ¦
¦ ¦ representation of its ¦ ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ FLOAT ¦ floating-point ¦ FLOAT(SALARY)/COMM ¦
¦ ¦ representation of its ¦ ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ HEX ¦ a hexadecimal ¦ HEX(BCHARCOL) ¦
¦ ¦ representation of its ¦ ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ HOUR ¦ the hour part of its ¦ HOUR(TIMECOL) > 12 ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ INTEGER ¦ an integer representation ¦ INTEGER(AVG(SALARY)+.5) ¦
¦ ¦ of its argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ LENGTH ¦ the length of its argument. ¦ LENGTH(ADDRESS) ¦
+-------------+-----------------------------+----------------------------¦
¦ MICROSECOND ¦ the microsecond part of its ¦ MICROSECOND(TSTMPCOL) <> 0 ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ MINUTE ¦ the minute part of its ¦ MINUTE(TIMECOL) = 0 ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ MONTH ¦ the month part of its ¦ MONTH(BIRTHDATE) = 5 ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ SECOND ¦ the seconds part of its ¦ SECOND(RECEIVED) ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ SUBSTR ¦ a substring of a string. ¦ SUBSTR(FIRSTNME,2,3) ¦
+-------------+-----------------------------+----------------------------¦
¦ TIME ¦ a time derived from its ¦ TIME(TSTMPCOL) < ¦
¦ ¦ argument. ¦ '13:00:00' ¦
+-------------+-----------------------------+----------------------------¦
¦ TIMESTAMP ¦ a timestamp derived from ¦ TIMESTAMP(DATECOL, ¦
¦ ¦ its argument or arguments. ¦ TIMECOL) ¦
+-------------+-----------------------------+----------------------------¦
¦ VALUE ¦ the first argument that is ¦ VALUE(SMLLINT1,100) + ¦
¦ ¦ not null. ¦ SMLLINT2 > 1000 ¦
+-------------+-----------------------------+----------------------------¦
¦ VARGRAPHIC ¦ a graphic string from its ¦ VARGRAPHIC (:MIXEDSTRING) ¦
¦ ¦ argument. ¦ ¦
+-------------+-----------------------------+----------------------------¦
¦ YEAR ¦ the year part of its ¦ YEAR(BIRTHDATE) = 1956 ¦
¦ ¦ argument. ¦ ¦
+------------------------------------------------------------------------+
Subtopics
2.1.9.2.1 Examples
2.1.9.2.2 Nesting Column and Scalar Functions
Subtopics
2.1.10.1 Specifying the Column Names
2.1.10.2 Specifying the Column Numbers
The order of the selected rows is based on the column identified in the
ORDER BY clause; this column is the ordering column.
Rows are sorted in the EBCDIC collating sequence. To order the rows by
more than one column's value, use more than one column name in the ORDER
BY clause.
When several rows have the same first ordering column value, those rows
are in an order based on the second column identified in the ORDER BY
clause, and then on the third ordering column, and so on. For example,
there is a difference between the results of the following two SELECT
statements. The first one orders selected rows by job and next by
education level. The second SELECT statement orders selected rows by
education level and next by job.
You can use the column number even if the ordering column has a name.
The following SQL statement lists names and phone numbers of all employees
in ascending order by LASTNAME.
The DISTINCT keyword removes duplicate rows from your result. Each row
contains unique data.
ADMRDEPT
========
A00
D01
E01
SELECT ADMRDEPT
FROM DSN8310.DEPT;
ADMRDEPT
========
A00
A00
A00
A00
A00
D01
D01
E01
E01
E01
E01
E01
E01
E01
When the DISTINCT keyword is omitted, the ADMRDEPT column value of each
selected row is returned, even though the result includes several
duplicate rows.
Except for the grouping columns (the columns named in the GROUP BY
clause), any other column value that is selected must be specified as an
operand of one of the column functions.
The following SQL statement lists, for each department, the lowest and
highest education level within that department.
You can use ORDER BY to specify the order in which rows are retrieved.
GROUP BY accumulates column values from the selected rows by group, but
does not order the groups.
The following SQL statement calculates the average salary for each
department:
WORKDEPT AVG(SALARY)
======== ===============
A00 40850.00000000
B01 41250.00000000
C01 29722.50000000
D11 25147.27272727
D21 25668.57142857
E01 40175.00000000
E11 21020.00000000
E21 24086.66666666
The average salary for each department is calculated. The GROUP BY clause
in this example specifies that you want DB2 to apply a function (AVG) to
each group of column values (SALARY) and return one row for each group of
department numbers (WORKDEPT). WORKDEPT can be selected without a column
function because its value determines the group (that is, every member of
each group has the same WORKDEPT value).
You can also specify that you want the rows grouped by more than one
column. For example, you can find the average salary for men and women in
departments A00 and C01. The following SQL statement:
The rows are grouped first by department number and next (within each
department) by sex before DB2 derives the average SALARY value for each
group.
If there are null values in the column you specify in the GROUP BY clause,
DB2 considers those values equal and returns a single-row result
summarizing the data in those rows with null values.
When it is used, the GROUP BY clause follows the FROM clause and any WHERE
clause, and precedes the ORDER BY clause.
The SQL statement below lists, for each job, the number of employees with
that job and their average salary.
For static SQL, GROUP BY can be used only in cursor declarations. Using
GROUP BY in any other way (SELECT INTO statement, for example) results in
an error. See "Chapter 3-2. Using a Cursor to Retrieve a Set of Rows" in
topic 3.2 for more information on cursors.
WORKDEPT AVG(SALARY)
======== ===============
A00 40850.00000000
C01 29722.50000000
D11 25147.27272727
D21 25668.57142857
E11 21020.00000000
E21 24086.66666666
The HAVING clause tests a property of the group. To specify that you want
the average salary and minimum education level of women in each department
in which all female employees have an education level greater than or
equal to 16, you can use the HAVING clause. Assuming you are only
interested in departments A00 and D11, the following SQL statement tests
the group property, MIN(EDLEVEL):
When GROUP BY and HAVING are both specified, the HAVING clause must follow
the GROUP BY clause. A function in a HAVING clause can include DISTINCT
if you have not used DISTINCT anywhere else in the same SELECT statement.
You can also use multiple predicates in a HAVING clause by connecting them
with AND and OR, and you can use HAVING NOT for any predicate of a search
condition.
Data from two or more tables can be combined or joined. To join data, you
need to do the following:
The search condition for the join is the link between the tables that
restricts the selection of rows. For example, the search condition could
identify two columns that must be equal (one from each of the tables being
joined) in order for the rows to be joined and included in the result.
Each row of the result table contains data that has been joined from both
tables (for rows that satisfy the search condition). Each column of the
result table contains data from one, but not both, of the tables.
If you do not specify a search condition in the WHERE clause, the result
table contains all possible combinations of rows for the tables identified
in the FROM clause. If this happens, the number of rows in the result
table is equal to the product of the number of rows in each table
specified.
Subtopics
2.1.14.1 Example: Joining Two Tables
2.1.14.2 Example: Joining a Table to Itself
2.1.14.3 Example: An Outer Join Using UNION
2.1.14.1 Example: Joining Two Tables
The SELECT statement example displays data retrieved from two tables:
The WHERE clause makes the connection between the two tables. Column
values are selected only from those rows where MGRNO (in DSN8310.DEPT)
equals EMPNO (in DSN8310.EMP).
The following SQL statement lists (in descending order by education level)
education level, first name, last name, and department name for each
employee whose education level is greater than 18.
The following example joins table DSN8310.PROJ to itself and returns the
number and name of each "major" project followed by the number and name of
the project that is part of it. In this example, A indicates the first
instance of table DSN8310.PROJ and B indicates a second instance of this
table. The join condition is such that the value in column PROJNO in
table DSN8310.PROJ A must be equal to a value in column MAJPROJ in table
DSN8310.PROJ B.
The query in the following example is often called an outer join. This
query returns rows for the following:
Using the UNION keyword, you can combine two or more SELECT statements to
form a single result table. When DB2 encounters the UNION keyword, it
processes each SELECT statement to form an interim result table, and then
combines the interim result table of each statement. You use UNION to
merge lists of values from two or more tables. You can use any of the
clauses and techniques you have learned so far when coding SELECT
statements, including ORDER BY.
SELECT EMPNO
FROM DSN8310.EMP
WHERE WORKDEPT = 'D11'
UNION
SELECT EMPNO
FROM DSN8310.EMPPROJACT
WHERE PROJNO = 'MA2112' OR
PROJNO = 'MA2113' OR
PROJNO = 'AD3111'
ORDER BY 1;
======
000060
000150
000160
000170
000180
000190
000200
000210
000220
000230
000240
200170
200220
Any ORDER BY clause must appear after the last SELECT statement that is
part of the union. In this example, the sequence of the results is based
on the first column of the result table. ORDER BY specifies the order of
the final result table.
To specify the columns by which DB2 is to order the results, use numbers
(in a union, you cannot use column names for this). The number refers to
the position of the column in the result table.
SELECT EMPNO
FROM DSN8310.EMP
WHERE WORKDEPT = 'D11'
UNION ALL
SELECT EMPNO
FROM DSN8310.EMPPROJACT
WHERE PROJNO = 'MA2112' OR
PROJNO = 'MA2113' OR
PROJNO = 'AD3111'
ORDER BY 1;
======
000060
000150
000150
000150
000160
000160
000170
000170
000170
000170
000180
000180
000190
000190
000190
000200
000210
000210
000210
000220
000230
000230
000230
000230
000230
000240
000240
200170
200220
Subtopics
2.1.17.1 Using Three-Part Table and View Names
2.1.17.2 Using Aliases
2.1.17.3 Creating Aliases
Suppose that you want the name, employee number, and department ID of
every employee whose last name ends in "son" in table DSN8310.EMP at
location DALLAS. If you have the appropriate authority, you could run the
following query:
Assume now that the alias SMITH.DALEMP has been defined at your local
subsystem for the table DALLAS.DSN8310.EMP. You could then substitute the
alias for this table name in the previous query.
For more on aliases and their creation, see the description of CREATE
ALIAS in SQL Reference.
Subtopics
2.2.1 Creating Your Own Tables: CREATE TABLE
2.2.2 Modifying DB2 Data: INSERT, UPDATE, and DELETE
2.2.3 Dropping Tables: DROP
Use the CREATE TABLE statement to create a table. The following SQL
statement creates a table named PRODUCT:
_ A list of the columns that make up the table. For each column,
specify:
- The data type and length attribute (for example, CHAR(8)). For
further information about data types, see "Data Types" in
topic 2.1.2.
- NOT NULL, when the column cannot contain null values and does not
have a default value.
- NOT NULL WITH DEFAULT, when the column cannot contain null values
but does have a default value, as follows:
You must separate each column description from the next with a comma
and enclose the entire list of column descriptions in parentheses.
Subtopics
2.2.1.1 Creating Work Tables
2.2.1.2 Creating Tables with Referential Constraints
2.2.1.3 Defining a View
2.2.1.4 Changing Data through a View
Before executing sample SQL statements that insert, update, and delete
rows, you probably want to create work tables (duplicates of the
DSN8310.EMP and DSN8310.DEPT tables) that you can practice with so the
original sample tables remain intact. This section shows how to create
two work tables and how to fill a work table with the contents of another
table.
Each example shown in this chapter assumes you are logged on using your
own authorization ID. The authorization ID qualifies the name of each
object you create. For example, if your authorization ID is SMITH, and
you create table YDEPT, the name of the table is SMITH.YDEPT. If you want
to access table DSN8310.DEPT, you must refer to it by its complete name.
If you want to access your own table YDEPT, you need only to refer to it
as "YDEPT".
Subtopics
2.2.1.1.1 How To Create a New Department Table
2.2.1.1.2 How to Create a New Employee Table
You must use two statements to create YDEPT and its index as shown above.
If you want DEPTNO to be a primary key as in the sample table, you must
explicitly define the key. Use an ALTER TABLE statement:
An INSERT statement is used with a SELECT clause to copy rows from one
table to another. The following statement fills the table:
You can use the following statements to create and fill a new employee
table called YEMP.
The CREATE TABLE statement can create tables with primary keys or foreign
keys in order to establish referential constraints.
You can define a single primary key composed of specific columns. (These
columns cannot allow nulls.) However, the definition of the table is
incomplete until its primary index is created. The primary index is a
unique index that matches the primary key and enforces the uniqueness of
the primary key.
For an example of a CREATE TABLE statement that defines both a primary key
and a foreign key, see "How to Create a New Employee Table" in
topic 2.2.1.1.2.
Use the CREATE VIEW statement to define a view and give the view a name,
just as you do for a table.
This view adds each department manager's name to the department data in
the DSN8310.DEPT table.
When a program accesses the data defined by a view, DB2 uses the view
definition to return a set of rows the program can access with SQL
statements. Now that the view VDEPTM exists, you can manipulate data by
means of it. To see the departments administered by department D01 and
the managers of those departments, execute the following statement:
When a view is created, the USER and CURRENT SQLID special registers may
be referenced in the CREATE VIEW statement. When the view is referenced,
the value used for USER or CURRENT SQLID is related to the person
executing the SQL statement (SELECT, UPDATE, INSERT, or DELETE) rather
than the person who created the view. In other words, a reference to a
special register in the definition of a view refers to its runtime value.
You can use views to limit access to certain kinds of data, such as salary
information. Views can also be used to do the following:
_ Combine data from two or more tables and make the combined data
available to an application. By using a SELECT statement that matches
values in one table with those in another table, you can create a view
that presents data from both tables. However, data defined by this
type of view can only be selected. You cannot update, delete, or
insert data into a view that joins two tables.
Some views are considered to be read-only, while others are subject update
or insert restrictions. (See Chapter 6 of SQL Reference for more
information about read-only views.) If a view does not have update
restrictions, there are some additional things to consider:
_ The owner of the plan or package that contains the program must be
authorized to update, delete, or insert rows into the view. You are
so authorized if you have created that view or have privileges for the
table on which the view is based. Otherwise, to bind the program you
have to obtain authorization through a GRANT statement.
_ When inserting a row into a table (via a view), the row must have a
value for each column of the table that does not have a default value.
If a column in the table on which the view is based is not specified
in the view's definition, and if the column does not have a default
value, you cannot insert rows into the table via the view.
Tables can be modified using the INSERT, UPDATE, and DELETE statements.
Subtopics
2.2.2.1 Inserting a Row: INSERT
2.2.2.2 Updating Current Values: UPDATE
2.2.2.3 Updating Tables with Referential Constraints
2.2.2.4 Deleting Rows: DELETE2.2.2.1 Inserting a Row: INSERT
In either case, for every row you insert, you must provide a value for any
column that does not have a default value.
You can name all columns for which you are providing values.
Alternatively, you can omit the column name list; when the program is
bound, DB2 inserts the name of each column of the table or view into the
column name list.
By naming the columns, you need not list the values based on their
position in the table. When you list the column names, supply their
corresponding values in the same order as the listed column names.
It is a good idea to name all columns into which you are inserting values
because:
For example,
After inserting a new department row into your YDEPT table, you can use a
SELECT statement to see what you have loaded into the table. This SQL
statement:
SELECT *
FROM YDEPT
WHERE DEPTNO LIKE 'E%'
ORDER BY DEPTNO;
shows you all the new department rows that you have inserted:
_ You can copy one table into another, as explained in "Filling a Table
from Another Table: Mass INSERT" in topic 2.2.2.1.3.
_ You can use the DB2 LOAD utility to enter data from other sources.
See Command and Utility Reference for more information about the LOAD
utility.
Subtopics
2.2.2.1.1 Inserting into Tables with Referential Constraints
2.2.2.1.2 Using an INSERT Statement in an Application Program
2.2.2.1.3 Filling a Table from Another Table: Mass INSERT
_ If the primary index does not currently exist, then define a unique
index on the primary key.
_ Do not insert a null value for any column of the primary key.
_ Each non-null value you insert into a foreign key column must be equal
to some value in the primary key (the primary key is in the parent
table).
_ If any field in the foreign key is null, the entire foreign key is
considered null.
_ If the index enforcing the primary key of the parent table has been
dropped, the INSERT into either the parent table or dependent table
fails.
For example, the sample application project table (PROJ) has foreign keys
on the department number (DEPTNO), referencing the department table, and
the employee number (RESPEMP), referencing the employee table. Every row
inserted into the project table must have a value of RESPEMP that is
either equal to some value of EMPNO in the employee table or is null. The
row must also have a value of DEPTNO that is equal to some value of DEPTNO
in the department table. (The null value is not allowed because DEPTNO in
the project table is defined as NOT NULL.)
The following statement also inserts a row into the YEMP table. However,
several column values are not specified. Because the unspecified columns
allow it, null values are inserted into columns not named: PHONENO,
EDLEVEL, SEX, BIRTHDATE, SALARY, BONUS, COMM, and HIREDATE. Since YEMP has
a foreign key WORKDEPT referencing the primary key DEPTNO in YDEPT, the
value being inserted for WORKDEPT (D11) must be a value of DEPTNO in
YDEPT.
Use a SELECT statement within an INSERT statement to select rows from one
table to be inserted into another table.
This statement copies data from DSN8310.EMP into the newly created table:
The INSERT statement fills the newly created table with data selected from
the DSN8310.EMP table: the names and phone numbers of employees in
Department D21. (The SELECT statement within the INSERT statement
specifies the data you want selected from one table to be inserted into
another table.)
To change the data in a table, use the UPDATE statement. You can also use
the UPDATE statement to delete a value from a row's column (without
removing the row) by changing the column's value to NULL.
UPDATE YEMP
SET JOB = 'MANAGER ',
PHONENO ='5678'
WHERE EMPNO = '000400';
The SET clause names the columns you want updated and provides the values
you want them changed to. The value you specify can be:
A column name. Replace the column's current value with the contents
of another column in the same row.
A null value. Replace the column's current value with a null value.
The column must have been defined as capable of containing a null
value when the table was created or when the column was added, or an
error occurs.
A host variable. Replace the column's current value with the contents
of the host variable.
_ CURRENT DATE
_ CURRENT DEGREE
_ CURRENT PACKAGESET
_ CURRENT SERVER
_ CURRENT SQLID
_ CURRENT TIME
_ CURRENT TIMESTAMP
_ CURRENT TIMEZONE
_ USER
An expression. Replace the column's current value with the value that
results from an expression.
_ To update a single row, use a WHERE clause that locates one, and only
one, row
_ To update several rows, use a WHERE clause that locates only the rows
you want to update.
If you omit the WHERE clause; DB2 updates every row in the table or view
with the values you supply.
If DB2 finds an error while executing your UPDATE statement (for instance,
an update value that is too large for the column), it stops updating and
returns error codes in the SQLCODE and SQLSTATE fields in the SQLCA. No
rows in the table are changed (rows already changed, if any, are restored
to their previous values).
UPDATE YEMP
SET MIDINIT = 'H', JOB = 'FIELDREP'
WHERE EMPNO = '000200';
The following statement gives everyone in department D11 a $400 raise.
The statement can update several rows.
UPDATE YEMP
SET SALARY = SALARY + 400.00
WHERE WORKDEPT = 'D11';
If you are updating a parent table, you cannot modify a primary key for
which dependent rows exist. (Doing so would violate referential
constraints for dependent tables and leave some rows without a parent.)
Also, you cannot give a primary key a null value.
If you are updating a dependent table, any non-null foreign key values
that you enter must match the primary key for each relationship in which
the table is a dependent. For example, department numbers in the employee
table depend on the department numbers in the department table; you can
assign no department to an employee, but you cannot assign an employee to
a department that does not exist.
This DELETE statement deletes each row in the YEMP table that has an
employee number 000060.
When this statement is executed, DB2 deletes any row from the YEMP table
that meets the search condition.
Subtopics
2.2.2.4.1 Deleting from Tables with Referential Constraints
2.2.2.4.2 Deleting Every Row in a Table
Delete Rules:
DELETE RESTRICT
The row can be deleted only if no other row depends on it. If a
dependent row exists in the relationship, the DELETE fails.
For example, you cannot delete a department from the department table
if it is still responsible for some project, which is described by a
dependent row in the project table.
For example, you can delete an employee from the employee table even
if the employee manages some department. In that case, the value of
MGRNO is set to null in the department table.
DELETE CASCADE
First the named rows are deleted, then the dependent rows are deleted,
honoring the delete rules of their dependents.
For example, you can delete a department by deleting its row in the
department table; that also deletes the rows for all departments that
report to it, all departments that report to them, and so forth.
deletes every row in the YDEPT table. If the statement is executed, the
table continues to exist (that is, you can insert rows into it) but it is
empty. All existing views and authorizations on the table remain intact
when using DELETE. If you use DROP, all views and authorizations are
dropped which can invalidate plans and packages. Refer to "Dropping
Tables: DROP" in topic 2.2.3 for a description of the DROP statement.
Use the DROP TABLE statement with care: When a table is dropped, it loses
its data as well as its definition. When you drop a table, all synonyms,
views, indexes, and referential constraints associated with that table are
also dropped. All authorities granted on the table are lost. Similarly,
a view can be dropped, using the DROP VIEW statement. This does not cause
a loss of data in the table on which the view was created.
With the proper authorization, you can also drop a database. When a
database is dropped, all tables, views, indexes, and referential
constraints defined on that database are also dropped.
Dropping a table is NOT equivalent to deleting all its rows. Instead, when
you drop a table you also drop all the relationships in which the table
participates, either as parent or dependent. This can affect application
programs that depend on the existence of a parent table, so use DROP
carefully.
Subtopics
2.3.1 Conceptual Overview
2.3.2 Using Subqueries
2.3.3 Using Correlated Subqueries
But you cannot go further because the DSN8310.EMP table does not include
project number data. You do not know which employees are working on
project MA2111 without issuing another SELECT statement against the
DSN8310.EMPPROJACT table.
You can nest one SELECT statement within another to solve this problem.
The inner SELECT statement is called a subquery. The SELECT statement
surrounding the subquery is called the outer SELECT.
To better understand what results from this SQL statement, imagine that
DB2 goes through the following process:
.
.
.
(SELECT EMPNO
FROM DSN8310.EMPPROJACT
WHERE PROJNO = 'MA2111');
(from DSN8310.EMPPROJACT)
+------+
¦000200¦
+------¦
¦000220¦
+------+
2. The interim result table then serves as a list in the search condition
of the outer SELECT. Effectively, DB2 executes this statement:
Subtopics
2.3.1.1 Correlation
2.3.1.2 Subqueries and Predicates
2.3.1.3 The Subquery Result Table
2.3.1.4 Subqueries with UPDATE, DELETE, and INSERT
2.3.1.1 Correlation
A case in point is the previous query. Its content is the same for every
row of the table DSN8310.EMP. Subqueries like this are said to be
uncorrelated.
Some subqueries do vary in content from row to row or group to group. The
mechanism that allows this is called correlation, and the subqueries are
said to be correlated. Correlated subqueries are described on page 2.3.3.
All of the information described preceding that section applies to both
correlated and uncorrelated subqueries.
SELECT AVG(SALARY)
SELECT EMPNO
The result table produced by a subquery can have zero or more rows. For
some usages, no more than one row is allowed.
_ Basic predicate
_ Quantified Predicates: ALL, ANY, and SOME
_ Using the IN Keyword
_ Using the EXISTS Keyword
_ Correlated subqueries.
Subtopics
2.3.2.1 Basic Predicate
2.3.2.2 Quantified Predicates: ALL, ANY, and SOME
2.3.2.3 Using the IN Keyword
2.3.2.4 Using the EXISTS Keyword
2.3.2.1 Basic Predicate
You can use a subquery immediately after any of the comparison operators.
If you do, the subquery can return at most one value. DB2 compares that
value with the value to the left of the comparison operator.
For example, the following SQL statement returns the employee numbers,
names, and salaries for employees whose education level is higher than the
average company-wide education level.
You can use a subquery after a comparison operator followed by the keyword
ALL, ANY, or SOME. When used in this way, the subquery can return zero,
one, or many values, including null values. You use ALL, ANY, and SOME in
the following ways:
_ Use ALL to indicate that the value you have supplied must compare in
the indicated way to all the values the subquery returns. For
example, suppose you use the greater-than comparison operator with
ALL:
.
.
.
WHERE expression > ALL (subquery)
_ Use ANY or SOME to indicate that the value you have supplied must
compare in the indicated way to at least one of the values the
subquery returns. For example, suppose you use the greater-than
comparison operator with ANY:
.
.
.
WHERE expression > ANY (subquery)
The results when a subquery returns one or more null values could in some
cases surprise you. For applicable rules, read the description of
quantified predicates in Chapter 3 of SQL Reference.
In the subqueries presented thus far, DB2 evaluates the subquery and uses
the result as part of the WHERE clause of the outer SELECT. In contrast,
when you use the keyword EXISTS, DB2 simply checks whether the subquery
returns one or more rows. If it does, the condition is satisfied; if it
does not (if it returns no rows), the condition is not satisfied. For
example:
SELECT EMPNO,LASTNAME
FROM DSN8310.EMP
WHERE EXISTS
(SELECT *
FROM DSN8310.PROJ
WHERE PRSTDATE > '1986-01-01'); 2.3.3 Using Correlated Subqueries
Subtopics
2.3.3.1 An Example of a Correlated Subquery
2.3.3.2 Using Correlated Names in References
2.3.3.3 Using Correlated Subqueries in an UPDATE Statement
2.3.3.4 Using Correlated Subqueries in a DELETE Statement
As shown in the example, you do not need to specify column names in the
subquery of an EXISTS clause. Instead, you can code SELECT *. You can
also use the EXISTS keyword with the NOT keyword in order to select rows
when the data or condition you specify does not exist; that is, you can
code
Subtopics
2.3.3.1 An Example of a Correlated Subquery
2.3.3.2 Using Correlated Names in References
2.3.3.3 Using Correlated Subqueries in an UPDATE Statement
2.3.3.4 Using Correlated Subqueries in a DELETE Statement
Suppose that you want a list of all the employees whose education levels
are higher than the average education levels in their respective
departments. To get this information, DB2 must search the DSN8310.EMP
table. For each employee in the table, DB2 needs to compare the
employee's education level to the average education level for the
employee's department.
In the subquery, you tell DB2 to compute the average education level for
the department number in the current row. A query that does this follows:
Consider what happens when the subquery is executed for a given row of
DSN8310.EMP. Before it is executed, the occurrence of X.WORKDEPT is
replaced with the value of the WORKDEPT column for that row. Suppose, for
example, that the row is for CHRISTINE HAAS. Her work department is A00,
which is the value of WORKDEPT for this row. The subquery executed for
this row is therefore:
(SELECT AVG(EDLEVEL)
FROM DSN8310.EMP
WHERE WORKDEPT = 'A00');
Thus, for the row considered, the subquery produces the average education
level of Christine's department. This is then compared in the outer
statement to Christine's own education level. For some other row for
which WORKDEPT has a different value, that value appears in the subquery
in place of A00. For example, for the row for MICHAEL L THOMPSON, this
value is B01, and the subquery for his row delivers the average education
level for department B01.
The result table produced by the query has the following values:
(from DSN8310.EMP)
EMPNO LASTNAME WORKDEPT EDLEVEL
Fetch +------------------------------------------+
1--_ ¦ 000010 ¦ HAAS ¦ A00 ¦ 18 ¦
+---------+-----------+----------+---------¦
2--_ ¦ 000030 ¦ KWAN ¦ C01 ¦ 20 ¦
+---------+-----------+----------+---------¦
3--_ ¦ 000090 ¦ HENDERSON ¦ E11 ¦ 16 ¦
+---------+-----------+----------+---------¦
4--_ ¦ 000110 ¦ LUCCHESI ¦ A00 ¦ 19 ¦
+---------+-----------+----------+---------¦
_ _ _ _
_ _ _ _
_ _ _ _
The correlation name is defined in the FROM clause of some query. This
query could be the outer-level SELECT, or any of the subqueries that
contain the reference. Suppose, for example, that a query contains
subqueries A, B, and C, and that A contains B and B contains C. Then a
correlation name used in C could be defined in B, A, or the outer SELECT.
You can define a correlation name for each table name appearing in a FROM
clause. Simply append the correlation name after its table name. Leave
one or more blanks between a table name and its correlation name, and
place a comma after the correlation name if it is followed by another
table name. The following FROM clause, for example, defines the
correlation names TA and TB for the tables TABLEA and TABLEB, and no
correlation name for the table TABLEC.
To continue this example, suppose a row in the DSN8310.PROJ table has been
deleted. Rows related to the deleted project in the DSN8310.PROJACT table
must also be deleted. To do this, use:
DB2 determines, for each row in the DSN8310.PROJACT table, whether a row
with the same project number exists in the DSN8310.PROJ table. If not,
the DSN8310.PROJACT row is deleted.
A subquery of a DELETE statement must not reference the same table from
which rows are deleted. In the sample application, some departments
administer other departments. Consider the following statement, which
seems to delete every department that does not administer another one:
The result of an operation must not depend on the order in which rows of a
table are accessed. If this statement could be executed, its result would
depend on whether the row for any department was accessed before or after
deleting the rows for the departments it administers. Hence, the operation
is prohibited.
With the referential constraints defined for the sample tables, the
statement causes an error. The delete operation involves the table
referred to in the subquery (DSN8310.EMP is a dependent of DSN8310.DEPT)
and the last delete rule in the path to EMP is SET NULL, not RESTRICT. If
the statement could be executed, its results would again depend on the
order in which rows were accessed.
2.4 Chapter 2-4. Using SPUFI: Executing SQL from Your Terminal
This chapter explains how to enter and execute SQL statements at a TSO
terminal using the SPUFI (SQL processor using file input) facility. You
can execute most of the interactive SQL examples shown in "Section 2.
Using SQL Queries" by following the instructions provided in this chapter
and using the sample tables shown in Appendix A, "DB2 Sample Tables" in
topic APPENDIX1.1.
Subtopics
2.4.1 Step 1. Invoke SPUFI and Allocate an Input Data Set
2.4.2 Step 2. Change SPUFI Defaults (Optional)
2.4.3 Step 3. Enter SQL Statements
2.4.4 Step 4. Process SQL Statements
2.4.5 Step 5. Browse the Output
2.4.6 More SQL Examples
To invoke SPUFI, select SPUFI from the DB2I Primary Option Menu as shown
in Figure 6.
+----------------------------------------------------------------------------------+
¦ ¦
¦ DSNEPRI DB2I PRIMARY OPTION MENU SSID: DSN ¦
¦ COMMAND ===> 1 ¦
¦ ¦
¦ Select one of the following DB2 functions and press ENTER. ¦
¦ ¦
¦ 1 SPUFI (Process SQL statements) ¦
¦ 2 DCLGEN (Generate SQL and source language declarations) ¦
¦ 3 PROGRAM PREPARATION (Prepare a DB2 application program to run) ¦
¦ 4 PRECOMPILE (Invoke DB2 precompiler) ¦
¦ 5 BIND/REBIND/FREE (BIND, REBIND, or FREE plans or packages) ¦
¦ 6 RUN (RUN an SQL program) ¦
¦ 7 DB2 COMMANDS (Issue DB2 commands) ¦
¦ 8 UTILITIES (Invoke DB2 utilities) ¦
¦ D DB2I DEFAULTS (Set global parameters) ¦
¦ X EXIT (Leave DB2I) ¦
¦ ¦
¦ ¦
¦ ¦
¦ PRESS: END to exit HELP for more information ¦
¦ ¦
¦ ¦
+----------------------------------------------------------------------------------+
When the SPUFI panel is first displayed, enter the name of an input data
set (where you will put SQL statements you want DB2 to execute) and an
output data set (where DB2 will put the results of your queries). You can
also enter new processing option defaults to specify how you want the next
SPUFI processing sequence to proceed.
The next time (and subsequent times) the SPUFI panel is displayed, the
data entry fields on the panel will contain the values that were set on
the panel previously. You can specify data set names and processing
options each time the SPUFI panel displays, as needed. Values you do not
change will remain in effect.
+----------------------------------------------------------------------------------+
¦ ¦
¦ DSNESP01 SPUFI SSID: DSN ¦
¦ ===> ¦
¦ Enter the input data set name: (Can be sequential or partitioned) ¦
¦ 1 DATA SET NAME..... ===> EXAMPLES(XMP1) ¦
¦ 2 VOLUME SERIAL..... ===> (Enter if not cataloged) ¦
¦ 3 DATA SET PASSWORD. ===> (Enter if password protected) ¦
¦ ¦
¦ Enter the output data set name: (Must be a sequential data set) ¦
¦ 4 DATA SET NAME..... ===> RESULT ¦
¦ ¦
¦ Specify processing options: ¦
¦ 5 CHANGE DEFAULTS... ===> Y (Y/N - Display SPUFI defaults panel?) ¦
¦ 6 EDIT INPUT........ ===> Y (Y/N - Enter SQL statements?) ¦
¦ 7 EXECUTE........... ===> Y (Y/N - Execute SQL statements?) ¦
¦ 8 AUTOCOMMIT........ ===> Y (Y/N - Commit after successful run?) ¦
¦ 9 BROWSE OUTPUT..... ===> Y (Y/N - Browse output data set?) ¦
¦ ¦
¦ For remote SQL processing: ¦
¦ 10 CONNECT LOCATION ===> ¦
¦ ¦
¦ ¦
¦ PRESS: ENTER to process END to exit HELP for more information ¦
¦ ¦
+----------------------------------------------------------------------------------+
_ Allocate this data set before you invoke SPUFI. The name must
conform to standard TSO naming conventions.
_ The data set can be empty before you begin the session. You can
then add the SQL statements by editing the data set from SPUFI.
If you use this panel a second time, the name of the data set you
used previously appears. To create a new member of an existing
partitioned data set, change only the member name. If you need to
allocate an input data set, refer to ISPF/PDF Version 3 for MVS Guide
and Reference for information on ISPF and allocating data sets.
5 CHANGE DEFAULTS
The SPUFI defaults need not be changed for this example. However, if
you specify Y(YES) you can look at the SPUFI defaults panel. See
"Step 2. Change SPUFI Defaults (Optional)" in topic 2.4.2 for more
information about the values you can specify and how they affect
SPUFI processing and output characteristics.
6 EDIT INPUT
To edit the input data set, leave Y(YES) on line 6. You can use the
ISPF editor to create a new member of the input data set and enter
SQL statements in it. (To process a data set that already contains a
set of SQL statements you want to execute immediately, enter N(NO).
Specifying N bypasses the step described in "Step 3. Enter SQL
Statements" in topic 2.4.3.)
7 EXECUTE
To execute SQL statements contained in the input data set, leave
Y(YES) on line 7.
8 AUTOCOMMIT
To make changes to the DB2 data permanent, leave Y(YES) on line 8.
Specifying Y makes SPUFI issue COMMIT if all statements execute
successfully. If all statements do not execute successfully, SPUFI
issues a ROLLBACK statement, and changes already made to the file
(back to the last commit point) are deleted. We suggest that you
read about the COMMIT and the ROLLBACK functions in "The ISOLATION
Option" in topic 4.1.2.7.2 or Chapter 6 of SQL Reference.
9 BROWSE OUTPUT
To look at the results of your query, leave Y(YES) on line 9. The
results are saved in the output data set. You can look at them at
any time, until you delete or write over the data set.
10 CONNECT LOCATION
Specify the name of the application server, if applicable, to which
you want to submit SQL statements for execution. SPUFI will then
issue a type 1 CONNECT statement to this application server.
When you finish with the SPUFI panel, press the ENTER key. Because you
specified YES on line 5 of the SPUFI panel, the next panel you see is the
SPUFI Defaults panel, as shown in Figure 8.
+----------------------------------------------------------------------------------+
¦ ¦
¦ DSNESP02 CURRENT SPUFI DEFAULTS SSID: DSN ¦
¦ ===> ¦
¦ Enter the following to control your SPUFI session: ¦
¦ 1 ISOLATION LEVEL ... ===> RR (RR=Repeatable Read, CS=Cursor Stability) ¦
¦ 2 MAX SELECT LINES .. ===> 250 (Maximum number of lines to be ¦
¦ returned from a SELECT) ¦
¦ Output data set characteristics: ¦
¦ 3 RECORD LENGTH...... ===> 4092 (LRECL= logical record length) ¦
¦ 4 BLOCKSIZE ......... ===> 4096 (Size of one block) ¦
¦ 5 RECORD FORMAT...... ===> VB (RECFM= F, FB, FBA, V, VB, or VB) ¦
¦ 6 DEVICE TYPE........ ===> SYSDA (Must be a DASD unit name) ¦
¦ ¦
¦ Output format characteristics: ¦
¦ 7 MAX NUMERIC FIELD . ===> 33 (Maximum width for numeric field) ¦
¦ 8 MAX CHAR FIELD .... ===> 80 (Maximum width for character field) ¦
¦ 9 COLUMN HEADING .... ===> NAMES (NAMES, LABELS, ANY, or BOTH) ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ PRESS: ENTER to process END to exit HELP for more information ¦
¦ ¦
+----------------------------------------------------------------------------------+
Default values are provided for each user the first time SPUFI is used.
Defaults are set for all options except the DB2 subsystem name. Any
changes you make to these values remain in effect until the values are
changed again. Initial default values are shown in Figure 8 in
topic 2.4.1.
Specify values for the following options on the CURRENT SPUFI DEFAULTS
panel:
1 ISOLATION LEVEL
See "The ISOLATION Option" in topic 4.1.2.7.2 for more information.
3 RECORD LENGTH
The record length must be at least 80 bytes. The default value
allows a 4092-byte record.
4 BLOCKSIZE
Follow normal block size selection rules. For F, the block size is
equal to record length. For FB and FBA, choose a block size that is
an even multiple of LRECL. For VB and VBA only, the block size must
be 4 bytes larger than the block size for FB or FBA.
5 RECORD FORMAT
The record format default is VB (variable-length blocked).
6 DEVICE TYPE
SYSDA specifies that MVS is to select an appropriate direct access
storage device.
9 COLUMN HEADING
You can specify NAMES, LABELS, ANY or BOTH for column headings.
When you have specified SPUFI options, press the ENTER key to continue.
SPUFI continues by processing the next processing option for which YES has
been specified. If all other processing options are NO, SPUFI continues
by displaying the SPUFI panel.
If you press the END key, you return to the SPUFI panel, but all changes
made on the SPUFI Defaults panel are lost. If you press ENTER, your
changes are saved.
Next, SPUFI lets you edit the input data set. Initially, editing consists
of entering an SQL statement into the input data set. You can also edit
an input data set that contains SQL statements and you can change, delete,
or insert SQL statements.
Move the cursor to the first input line and enter the first part of an SQL
statement. You can enter the rest of the SQL statement on subsequent
lines, as shown in Figure 9. Line indentation and entry on several lines
are not necessary, although this format is easier to read.
You can put more than one SQL statement in the input data set. You can
put an SQL statement on one line of the input data set or on more than one
line. When the data set is processed, DB2 executes the statements one
after the other. Do not put more than one SQL statement on a single line.
The first one is executed, but other SQL statements on the same line are
ignored.
When using SPUFI, end each SQL statement with a semicolon (;). This tells
SPUFI that the statement is complete.
When you have entered the SQL statements that you want, press the END PF
key to save the file and to begin execution.
+----------------------------------------------------------------------------------+
¦ ¦
¦ EDIT --------userid.EXAMPLES(XMP1) --------------------- COLUMNS 001 072 ¦
¦ COMMAND INPUT ===> SAVE SCROLL ===> PAGE ¦
¦ ********************************** TOP OF DATA *********************** ¦
¦ 000100 SELECT LASTNAME, FIRSTNME, PHONENO ¦
¦ 000200 FROM DSN8310.EMP ¦
¦ 000300 WHERE WORKDEPT= 'D11' ¦
¦ 000400 ORDER BY LASTNAME; ¦
¦ ********************************* BOTTOM OF DATA ********************* ¦
¦ ¦
¦ ¦
¦ ¦
+----------------------------------------------------------------------------------+
Pressing the END PF key saves the data set. You can save the data set and
continue editing it by entering the SAVE command. In fact, it is a good
practice to save the data set after every 10 minutes or so of editing.
Figure 9 shows what the panel looks like if you enter the sample SQL
statement, followed by a SAVE command.
The editing step is bypassed when you reset the EDIT INPUT processing
option by specifying:
Subtopics
2.4.3.1 Comments in Your Input Data Set
You can put comments about SQL statements either on separate lines or on
the same line. In either case, two hyphens (--) are used to begin a
comment. Everything to the right of the two hyphens is ignored by DB2.
2.4.4 Step 4. Process SQL Statements
SPUFI passes the input data set to DB2 for processing. The SQL statement
in the input data set EXAMPLES(XMP1) is executed. Output is sent to the
output data set userid.RESULT.
The DB2 processing step is bypassed when you specify the EXECUTE
processing option:
Subtopics
2.4.4.1 Quitting While the Statement Is Executing
Your SQL statement might take a long time to execute, depending on how
large a table DB2 has to search, or on how many rows DB2 has to process.
To interrupt DB2's execution, press the PA1 key and respond to the
prompting message that asks you if you really want to stop processing.
This cancels the executing SQL statement and returns you to the ISPF-PDF
menu.
What happens to the output data set? This depends on how far execution
has progressed before you interrupted the execution of the input data set.
DB2 might not have opened the output data set yet, or the output data set
might contain all or part of the results data produced so far.
SPUFI formats and displays the output data set using the ISPF Browse
program. The output from the sample program is shown in Figure 10. An
output data set contains these items for each SQL statement executed by
DB2:
_ The SQL statement that was executed, copied from the input data set
_ At the end of the data set are summary statistics that describe the
execution of the input data set as a whole.
+-----------------------------------------------------------------------------------
-------+
¦
¦
¦
¦
¦
¦
¦ BROWSE-- userid.RESULT COLUMNS 001 072
¦
¦ COMMAND INPUT ===> SCROLL ===> PAGE
¦
¦ --------+---------+---------+---------+---------+---------+---------
+---------+ ¦
¦ SELECT LASTNAME, FIRSTNME, PHONENO
00010000 ¦
¦ FROM DSN8310.EMP
00020000 ¦
¦ WHERE WORKDEPT = 'D11'
00030000 ¦
¦ ORDER BY LASTNAME;
00040000 ¦
¦ ---------+---------+---------+---------+---------+---------+---------
+---------+ ¦
¦ LASTNAME FIRSTNME PHONENO
¦
¦ ADAMSON BRUCE 4510
¦
¦ BROWN DAVID 4501
¦
¦ JOHN REBA 0672
¦
¦ JONES WILLIAM 0942
¦
¦ LUTZ JENNIFER 0672
¦
¦ PIANKA ELIZABETH 3782
¦
¦ SCOUTTEN MARILYN 1682
¦
¦ STERN IRVING 6423
¦
¦ WALKER JAMES 2986
¦
¦ YAMAMOTO KIYOSHI 2890
¦
¦ YOSHIMURA MASATOSHI 2890
¦
¦ DSNE610I NUMBER OF ROWS DISPLAYED IS 11
¦
¦ DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 100
¦
¦ ---------+---------+---------+---------+---------+---------+----
¦
¦ ---------+---------+---------+---------+---------+---------+----
¦
¦ DSNE617I COMMIT PERFORMED, SQLCODE IS 0
¦
¦ DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 0
¦
¦ ---------+---------+---------+---------+---------+---------+----
¦
Figure 10. Result Data Set from the Sample Problem
Subtopics
2.4.5.1 Format of SELECT Statement Results
2.4.5.2 Content of the Messages
Subtopics
3.1 Chapter 3-1. Basics of Coding SQL in an Application Program
3.2 Chapter 3-2. Using a Cursor to Retrieve a Set of Rows
3.3 Chapter 3-3. Using DCLGEN
3.4 Chapter 3-4. Embedding SQL Statements in Host Languages
Suppose you are coding a COBOL application program to access data in a DB2
database. When your program executes an SQL statement, the program needs
to communicate with DB2. When DB2 completes processing an SQL statement,
DB2 sends back a return code; your program should test the return code to
examine the results of the operation.
_ Declare the tables you use, as described in "Declaring Table and View
Definitions" in topic 3.1.3. (This is optional.)
_ Declare the data items used to pass data between DB2 and a host
language, as described in "Accessing Data Using Host Variables and
Host Structures" in topic 3.1.4.
_ Code SQL statements to access DB2 data. See "Accessing Data Using
Host Variables and Host Structures" in topic 3.1.4.
Ada. See IBM Ada/370 SQL Module Processor for DB2 Database Manager
User's Guide for more information about writing applications in Ada.
APL2 (*). See APL2 Programming: Using Structured Query Language (SQL)
for more information about writing applications in APL2.
BASIC. See IBM BASIC Language Reference for more information about
writing applications in BASIC.
IBM SAA AD/Cycle* Prolog/MVS & VM Version 1. See IBM SAA AD/Cycle
Prolog/MVS & VM Programmer for more information about writing
applications in Prolog/MVS & VM.
Subtopics
3.1.1 Conventions Used in Examples of Coding SQL Statements
3.1.2 Delimiting an SQL Statement
3.1.3 Declaring Table and View Definitions
3.1.4 Accessing Data Using Host Variables and Host Structures
3.1.5 Checking the Execution of SQL Statements
The SQL statements shown in this section use the following conventions:
_ The APOST and APOSTSQL precompiler options are assumed (although they
are not the defaults). Character string literals within SQL and host
language statements are delimited by apostrophes (').
_ The SQL statements access data in the sample tables that are shipped
as part of DB2. Those tables contain data that a manufacturing
company might keep about its employees and its current projects. They
are described in Appendix A, "DB2 Sample Tables" in topic APPENDIX1.1.
_ An SQL example does not necessarily show the complete syntax of an SQL
statement. For the complete description and syntax of any of the
statements described in this book, see Chapter 6 of SQL Reference.
Some of the examples vary from these conventions. Exceptions are noted
where they occur.
Bracket an SQL statement in your program between EXEC SQL and a statement
terminator. The terminators for the languages described in this book are:
Language SQL Statement Terminator
C Semicolon (;)
COBOL END-EXEC
For example, use EXEC SQL and END-EXEC to delimit an SQL statement in a
COBOL program, like this:
EXEC SQL
an SQL statement
END-EXEC.
Before your program issues SQL statements that retrieve, update, delete,
or insert data, you can declare the tables and views your program accesses
by including an SQL DECLARE statement in your program.
You do not have to declare tables or views, but there are advantages if
you do. One advantage is documentation; for example, the DECLARE
statement specifies the structure of the table or view you are working
with, and the data type of each column. You can refer to the DECLARE
statement for the column names and data types in the table or view.
Another advantage is that the DB2 precompiler uses your declarations to
make sure you have used correct column names and data types in your SQL
statements. The DB2 precompiler issues a warning message when the column
names and data types do not correspond to the SQL DECLARE statements in
your program.
For example, the DECLARE TABLE statement for the DSN8310.DEPT table looks
like this:
EXEC SQL
DECLARE DSN8310.DEPT TABLE
(DEPTNO CHAR(3) NOT NULL,
DEPTNAME VARCHAR(36) NOT NULL,
MGRNO CHAR(6) ,
ADMRDEPT CHAR(3) NOT NULL,
LOCATION CHAR(16) )
END-EXEC.
You can access data using host variables and host structures.
A host variable is a data item declared in the host language (in this
case, COBOL) for use within an SQL statement. Using host variables, you
can:
_ Retrieve data and put it into the host variable for use by the
application program
_ Use the data in the host variable to insert into a table or to change
the contents of a row
_ Use the data in the host variable when evaluating a WHERE or HAVING
clause.
Etc.
Subtopics
3.1.4.1 Using Host Variables
3.1.4.2 Using Host Structures
Any valid host variable name can be used in an SQL statement. The name
must be declared in the host program before it is used. (For more
information see the appropriate language section in "Chapter 3-4.
Embedding SQL Statements in Host Languages" in topic 3.4.)
A host variable can be used to represent a data value but cannot be used
to represent a table, view, or column name. (Table, view, or column names
can be specified at execution time using dynamic SQL. See "Chapter 5-1.
Coding Dynamic SQL in Application Programs" in topic 5.1 for more
information.)
Host variables follow the naming conventions of the host language. (In
this chapter, COBOL is assumed to be the host language.) Host variables
used within SQL statements must be preceded by a colon (:) to tell DB2
that the variable is not a column name. (4) Host variables outside of SQL
statements must not be preceded by a colon.
For more information about declaring host variables, see the appropriate
language section:
_ Assembler: "Using Host Variables" in topic 3.4.1.4
_ C: "Using Host Variables" in topic 3.4.2.4
_ COBOL: "Using Host Variables" in topic 3.4.3.4
_ FORTRAN: "Using Host Variables" in topic 3.4.4.4
_ PL/I: "Using Host Variables" in topic 3.4.5.4.
Subtopics
3.1.4.1.1 Retrieving Data into a Host Variable
3.1.4.1.2 Inserting and Updating Data
3.1.4.1.3 Searching Data
3.1.4.1.4 Using Indicator Variables with Host Variables
3.1.4.1.5 Considerations
You can use a host variable to specify a program data area that is to
contain the column values of a retrieved row or rows.
Retrieving a Single Row of Data: The INTO clause of the SELECT statement
names one or more host variables to contain the column values returned.
The elementary data items involved correspond one-for-one with the list of
column names in the SELECT list.
For example, suppose you are retrieving the EMPNO, LASTNAME, and WORKDEPT
column values from rows in the DSN8310.EMP table. You can define a data
area in your program to hold each column, then name the data areas with an
INTO clause, as in the following example (where each host variable is
preceded by a colon):
EXEC SQL
SELECT EMPNO, LASTNAME, WORKDEPT
INTO :CBLEMPNO, :CBLNAME, :CBLDEPT
FROM DSN8310.EMP
WHERE EMPNO = :EMPID
END-EXEC.
In the DATA DIVISION of the program, the host variables CBLEMPNO, CBLNAME,
and CBLDEPT must be declared such that each is compatible with the data
type contained in the DSN8310.EMP table columns EMPNO, LASTNAME, and
WORKDEPT.
If the SELECT statement returns more than one row, this is an error, and
any data returned is undefined and unpredictable. To avoid this error see
"Retrieving Multiple Rows of Data."
The results are shown below with column headings that represent the names
of the host variables:
Retrieving Multiple Rows of Data: If you are unsure about the number of
rows that will be returned, or if you expect that more than one row will
be returned, then you must use an alternative to the SELECT ... INTO
statement.
You can set or change a value in a DB2 table to the value of a host
variable. Use the host variable name in the SET clause of UPDATE or the
VALUES clause of INSERT. This example changes an employee's phone number:
EXEC SQL
UPDATE DSN8310.EMP
SET PHONENO = :NEWPHONE
WHERE EMPNO = :EMPID
END-EXEC.
Verify that the value of a retrieved character string has not been
truncated when retrieved
Insert null values from host variables into columns.
Retrieving Data into Host Variables: If the value for the column you are
retrieving is null, DB2 puts a negative value in the indicator variable.
If it is null because of a numeric or character conversion error, or an
arithmetic expression error, DB2 sets the indicator variable to -2. See
"Handling Arithmetic or Conversion Errors" in topic 3.1.5.3 for more
information.
If you do not use an indicator variable and DB2 retrieves a null value, an
error results.
When DB2 retrieves the value of a column, you can test the indicator
variable. If the indicator variable's value is less than zero, the column
value is null. When the column value is null, DB2 puts nothing into the
host variable; its value is unchanged.
+-----------------------------------------------------------------------------------
---------------+
¦ EXEC SQL ¦ EXEC SQL
¦
¦ SELECT PHONENO ¦ SELECT PHONENO
¦
¦ INTO :CBLPHONE:INDNULL ¦ INTO :CBLPHONE
INDICATOR :INDNULL ¦
¦ FROM DSN8310.EMP ¦ FROM DSN8310.EMP
¦
¦ WHERE EMPNO = :EMPID ¦ WHERE EMPNO = :EMPID
¦
¦ END-EXEC. ¦ END-EXEC.
¦
+-----------------------------------------------------------------------------------
---------------+
You can then test INDNULL for a negative value. If it is negative, the
corresponding value of PHONENO is null, and you can disregard the contents
of CBLPHONE.
When a column value is fetched using a cursor, you can use the same
technique to determine whether the column value is null or not.
Inserting Null Values into Columns Using Host Variables: You can use an
indicator variable to insert a null value from a host variable into a
column. When DB2 processes INSERT and UPDATE statements, it checks the
indicator variable (if it exists). If the indicator variable is negative,
the column value is set to null value. If the indicator variable is
greater than -1, the associated host variable contains a value for the
column.
For example, you could put a value in a column (using INSERT or UPDATE),
but you are not sure whether the value is always specified with the input
data. To allow the possibility that the column's value might be null, you
can code:
EXEC SQL
UPDATE DSN8310.EMP
SET PHONENO = :NEWPHONE:PHONEIND
WHERE EMPNO = :EMPID
END-EXEC.
When NEWPHONE contains other than a null value, set PHONEIND to zero by
preceding the statement with:
MOVE 0 TO PHONEIND.
Otherwise, to tell DB2 that NEWPHONE contains a null value, set PHONEIND
to a negative value, as in the following statement:
MOVE -1 TO PHONEIND.
3.1.4.1.5 Considerations
If you transfer data between a DB2 column and a host variable, and the two
do not have the same data type or length attribute, you can expect the
data format to change. Values might be truncated, padded, or rounded
somehow. If you transfer or compare data, see Chapter 3 of SQL Reference
for the rules associated with these operations.
A host structure can be substituted for one or more host variables and,
like host variables, indicator variables (or structures) can be used with
host structures.
Subtopics
3.1.4.2.1 Example: Using a Host Structure
3.1.4.2.2 Using Indicator Variables with Host Structures
In the following example, assume that your COBOL program includes the
following SQL statement:
EXEC SQL
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT
INTO :EMPNO, :FIRSTNME, :MIDINIT, :LASTNAME, :WORKDEPT
FROM DSN8310.VEMP
WHERE EMPNO = :EMPID
END-EXEC.
In this example, if you want to avoid listing host variables, you can
substitute the name of a structure, say :PEMP, that contains :EMPNO,
:FIRSTNME, :MIDINIT, :LASTNAME, and :WORKDEPT. The example then reads:
EXEC SQL
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT
INTO :PEMP
FROM DSN8310.VEMP
WHERE EMPNO = :EMPID
END-EXEC.
You can declare a host structure yourself, or you can use DCLGEN to
generate a COBOL record description, PL/I structure declaration, or C
structure declaration that corresponds to the columns of a table For more
details about coding a host structure in your program, see "Chapter 3-4.
Embedding SQL Statements in Host Languages" in topic 3.4. For more
information on using DCLGEN and the restrictions that apply to the C
language, see "Chapter 3-3. Using DCLGEN" in topic 3.3.
01 PEMP-ROW.
10 EMPNO PIC X(6).
10 FIRSTNME.
49 FIRSTNME-LEN PIC S9(4) USAGE COMP.
49 FIRSTNME-TEXT PIC X(12).
10 MIDINIT PIC X(1).
10 LASTNAME.
49 LASTNAME-LEN PIC S9(4) USAGE COMP.
49 LASTNAME-TEXT PIC X(15).
10 WORKDEPT PIC X(3).
10 EMP-BIRTHDATE PIC X(10).
01 INDICATOR-TABLE.
02 EMP-IND PIC S9(4) COMP OCCURS 6 TIMES.
.
.
.
MOVE '000230' TO EMPNO.
.
.
.
EXEC SQL
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT, BIRTHDATE
INTO :PEMP-ROW:EMP-IND
FROM DSN8310.EMP
WHERE EMPNO = :EMPNO
END-EXEC.
Because this example selects rows from the DSN8310.EMP table, some of the
EMP-IND array values are always zero. The first five columns of each row
are defined NOT NULL. In the above example, DB2 selects the values for a
row of data into a host structure. Therefore, you must use a
corresponding structure for the indicator variables to determine which (if
any) selected column values are null. For information on using the IS
NULL keyword phrase in WHERE clauses, see "Chapter 2-1. Retrieving Data"
in topic 2.1.
A program that includes SQL statements needs to have an area set apart for
communication with DB2; this area is called the SQL communication area
(SQLCA). When DB2 processes an SQL statement in your program, it places
return codes in the SQLCODE (5) and SQLSTATE fields of the SQLCA. The
return codes indicate whether the statement you executed succeeded or
failed.
Subtopics
3.1.5.1 SQLCODE and SQLSTATE
3.1.5.2 The WHENEVER Statement
3.1.5.3 Handling Arithmetic or Conversion Errors
3.1.5.4 Handling SQL Error Return Codes
The WHENEVER statement causes DB2 to check the SQLCA and continue
processing your program, or branch to another area in your program if an
error, exception, or warning exists as a result of executing an SQL
statement. Your program can then examine the SQLCODE or SQLSTATE fields
to take an action specific to the error or exception situation.
The WHENEVER statement allows you to specify what should be done whenever
a general condition is true. You can specify more than one WHENEVER
statement in your program. When you do this, the first WHENEVER statement
applies to all subsequent SQL statements in the source program until
another WHENEVER statement is specified.
EXEC SQL
WHENEVER condition action
END-EXEC
SQLERROR Indicates what should be done when DB2 returns an error code
as the result of an SQL statement (SQLCODE < 0).
NOT FOUND Indicates what should be done when DB2 cannot find a row to
satisfy your SQL statement or when there are no more rows to
fetch (SQLCODE = 100).
CONTINUE
Specifies the next sequential statement of the source program.
GOTO or GO TO host-label
Specifies the statement identified by host-label. For
host-label, substitute a single token, optionally preceded by
a colon. The form of the token depends on the host language.
In COBOL, for example, it can be section-name or an
unqualified paragraph-name.
The WHENEVER statement must precede the first SQL statement it is to
affect. However, if your program checks the SQLCODE directly, the check
must be done after the SQL statement is executed.
For rows in which the error does occur, one or more selected items have no
meaningful value. This error is flagged by a -2 in the indicator variable
for the affected host variable, and an SQLCODE of +802 (SQLSTATE '01519')
in the SQLCA.
Subtopics
3.2.1 Cursor Functions
3.2.2 How to Use a Cursor: An Example
3.2.3 Maintaining Cursor Position
DB2 can be used to retrieve and process a set of rows. Each row in the
set satisfies the criteria specified in the search conditions of an SQL
statement. However, when a set of rows is selected by your program, the
program cannot process all the rows at once. The program needs to process
the rows one at a time.
The result table of a cursor is processed much like a sequential data set.
The cursor must be opened (with an OPEN statement) before any rows are
retrieved. A FETCH statement is used to retrieve the cursor's current
row. FETCH can be executed repeatedly until all rows have been retrieved.
When the end-of-data condition occurs, you must close the cursor with a
CLOSE statement (similar to end-of-file processing).
Your program can have several cursors. Each cursor requires its own:
You can use cursors to fetch, update, or delete a row of a table, but you
cannot use them to insert a row into a table.
+------------------------------------------------------------------------+
¦ Table 5. SQL Statements Required to Define and Use a Cursor in a COBOL ¦
¦ Program ¦
+------------------------------------------------------------------------¦
¦ SQL Statement ¦ Described in Section ¦
+------------------------------------+-----------------------------------¦
¦ EXEC SQL ¦ "Step 1: Define the Cursor" in ¦
¦ DECLARE THISEMP CURSOR FOR ¦ topic 3.2.2.1 ¦
¦ SELECT EMPNO, LASTNAME, ¦ ¦
¦ WORKDEPT, JOB ¦ ¦
¦ FROM DSN8310.EMP ¦ ¦
¦ WHERE WORKDEPT = 'D11' ¦ ¦
¦ FOR UPDATE OF JOB ¦ ¦
¦ END-EXEC. ¦ ¦
+------------------------------------+-----------------------------------¦
¦ EXEC SQL ¦ "Step 2: Open the Cursor" in ¦
¦ OPEN THISEMP ¦ topic 3.2.2.2 ¦
¦ END-EXEC. ¦ ¦
+------------------------------------+-----------------------------------¦
¦ EXEC SQL ¦ "Step 3: Specify What to Do When ¦
¦ WHENEVER NOT FOUND ¦ End-of-Data Is Reached" in ¦
¦ GO TO CLOSE-THISEMP ¦ topic 3.2.2.3 ¦
¦ END-EXEC. ¦ ¦
+------------------------------------+-----------------------------------¦
¦ EXEC SQL ¦ "Step 4: Retrieve a Row Using ¦
¦ FETCH THISEMP ¦ the Cursor" in topic 3.2.2.4 ¦
¦ INTO :EMP-NUM, :NAME2, ¦ ¦
¦ :DEPT, :JOB-NAME ¦ ¦
¦ END-EXEC. ¦ ¦
+------------------------------------+-----------------------------------¦
¦ ... for specific employees ¦ "Step 5a: Update the Current ¦
¦ in Department D11, ¦ Row" in topic 3.2.2.5 ¦
¦ update the JOB value: ¦ ¦
¦ ¦ ¦
¦ EXEC SQL ¦ ¦
¦ UPDATE DSN8310.EMP ¦ ¦
¦ SET JOB = :NEW-JOB ¦ ¦
¦ WHERE CURRENT OF THISEMP ¦ ¦
¦ END-EXEC. ¦ ¦
¦ ¦ ¦
¦ ... then print the row. ¦ ¦
+------------------------------------+-----------------------------------¦
¦ ... for other employees, ¦ "Step 5b: Delete the Current ¦
¦ delete the row: ¦ Row" in topic 3.2.2.6 ¦
¦ ¦ ¦
¦ EXEC SQL ¦ ¦
¦ DELETE FROM DSN8310.EMP ¦ ¦
¦ WHERE CURRENT OF THISEMP ¦ ¦
¦ END-EXEC. ¦ ¦
+------------------------------------+-----------------------------------¦
¦ Branch back to fetch and ¦ ¦
¦ process the next row. ¦ ¦
+------------------------------------+-----------------------------------¦
¦ CLOSE-THISEMP. ¦ "Step 6: Close the Cursor" in ¦
¦ EXEC SQL ¦ topic 3.2.2.7 ¦
¦ CLOSE THISEMP ¦ ¦
¦ END-EXEC. ¦ ¦
+------------------------------------------------------------------------+
Subtopics
3.2.2.1 Step 1: Define the Cursor
3.2.2.2 Step 2: Open the Cursor
3.2.2.3 Step 3: Specify What to Do When End-of-Data Is Reached
3.2.2.4 Step 4: Retrieve a Row Using the Cursor
3.2.2.5 Step 5a: Update the Current Row
3.2.2.6 Step 5b: Delete the Current Row
3.2.2.7 Step 6: Close the Cursor
EXEC SQL
DECLARE cursor-name CURSOR FOR
SELECT column-name-list
FROM table-name
WHERE search-condition
FOR UPDATE OF column-name
END-EXEC.
The SELECT statement shown here is rather simple. You can code several
other types of clauses in a SELECT statement within a DECLARE CURSOR
statement. Chapter 6 of SQL Reference illustrates several more clauses
that can be used within a SELECT statement.
A column of the identified table can be updated even though it is not part
of the result table. In this case, you do not need to name the column in
the SELECT statement (but do not forget to name it in the FOR UPDATE OF
clause). When the cursor retrieves a row (using FETCH) that contains a
column value you want to update, you can use UPDATE ... WHERE CURRENT OF
to update the row.
For example, assume that each row of the result table includes the EMPNO,
LASTNAME, and WORKDEPT columns from the DSN8310.EMP table. If you want to
update the JOB column (one of the columns in the DSN8310.EMP table), the
DECLARE CURSOR statement must include FOR UPDATE OF JOB even though JOB is
omitted from the SELECT statement.
To tell DB2 you are ready to process the first row of the result table,
have your program issue the OPEN statement. When this happens, DB2
processes the SELECT statement within the DECLARE CURSOR statement to
identify a set of rows using the current value of any host variables
specified in the SELECT statement. The result table can contain zero,
one, or many rows, depending on the extent to which the search condition
is satisfied. The OPEN statement looks like this:
EXEC SQL
OPEN cursor-name
END-EXEC.
When used with cursors, the CURRENT DATE, CURRENT TIME, and CURRENT
TIMESTAMP special registers are evaluated once when the OPEN statement is
executed; the value returned in the register is then used on all
subsequent FETCH statements.
Test the SQLCODE field for a value of 100 or the SQLSTATE field for a
value of '02000' to determine if the last row of data has been retrieved.
These codes occur when a FETCH statement has retrieved the last row in the
result table and your program issues a subsequent FETCH. For example:
EXEC SQL
WHENEVER NOT FOUND GO TO symbolic-address
END-EXEC.
To move the contents of a selected row into your program host variables,
use the FETCH statement. The SELECT statement within the DECLARE CURSOR
statement identifies rows that contain the column values your program
wants (that is, the result table is defined), but DB2 does not retrieve
any data for your application program until FETCH is issued.
When your program issues the FETCH statement, DB2 uses the cursor to point
to the next row in the result table, making it the current row. DB2 then
moves the current row contents into your program host variables (specified
with the INTO clause). This sequence is repeated each time FETCH is
issued, until you have processed all rows in the result table.
EXEC SQL
FETCH cursor-name
INTO :host variable1, :host variable2
END-EXEC.
When querying a remote subsystem with FETCH, it is possible that you may
experience reduced efficiency. To combat this problem, you can use block
fetch. For more information see "How to Ensure Block Fetching" in
topic 4.1.4.6.2. Block fetch processes rows ahead of the application's
current row. Block fetch cannot be used when a cursor is used for update
or delete.
When your program has retrieved the current row, you can update its data
by using the UPDATE statement. To do this, issue an UPDATE...WHERE
CURRENT OF statement; it is intended specifically for use with a cursor.
The UPDATE ... WHERE CURRENT OF statement looks like this:
EXEC SQL
UPDATE table-name
SET column1 = value, column2 = value
WHERE CURRENT OF cursor-name
END-EXEC.
When used with a cursor, the UPDATE statement differs from the one
described in "Chapter 2-2. Creating Tables and Modifying Data" in
topic 2.2.
_ The WHERE clause identifies the cursor that points to the row to be
updated.
_ Each column to be updated must have been named previously in the FOR
UPDATE OF clause of the SELECT statement associated with the DECLARE
CURSOR statement. (7)
After you have updated a row, the cursor points to the current row until
you issue a FETCH statement for the next row.
Remember that you cannot update a row if your update violates any
referential constraints the table might have. Refer to "Updating Tables
with Referential Constraints" in topic 2.2.2.3 for more information.
"Updating Current Values: UPDATE" in topic 2.2.2.2 showed you how to use
the UPDATE statement repeatedly when you update all rows that meet a
specific search condition. Alternatively, you can use the UPDATE... WHERE
CURRENT OF statement repeatedly when you want to obtain a copy of the row,
examine it, and then update it.
When your program has retrieved the current row, you can delete the row by
using the DELETE statement. To do this, you issue a DELETE...WHERE
CURRENT OF statement; it is intended specifically for use with a cursor.
The DELETE...WHERE CURRENT OF statement looks like this:
EXEC SQL
DELETE FROM table-name
WHERE CURRENT OF cursor-name
END-EXEC.
When used with a cursor, the DELETE statement differs from the one you
learned in "Chapter 2-2. Creating Tables and Modifying Data" in
topic 2.2.
After you have deleted a row, you cannot update or delete another row
using that cursor until you issue a FETCH statement to position the cursor
on the next row.
"Deleting Rows: DELETE" in topic 2.2.2.4 showed you how to use the DELETE
statement to delete all rows that meet a specific search condition.
Alternatively, you can use the DELETE...WHERE CURRENT OF statement
repeatedly when you want to obtain a copy of the row, examine it, and then
delete it.
Remember that you cannot delete a row if doing so will result in the
violation of any referential constraints the table might have. In the
example on page 3.2.2, the employee cannot be deleted from the employee
table unless the employee has already been deleted from the project table
and the project activity table. This is because of the way the
referential constraints have been defined on these tables. Refer to
"Updating Tables with Referential Constraints" in topic 2.2.2.3 for more
information.
When you are finished processing the rows of the result table and you want
to use the cursor again, issue a CLOSE statement to close the cursor:
EXEC SQL
CLOSE cursor-name
END-EXEC.
If you are finished processing the rows of the "result table" and you do
not want to use the cursor, you can let DB2 automatically close the cursor
when your program terminates. When a cursor is closed, locks can be
freed. To release page locks as soon as possible, issue a CLOSE statement
as soon as you are finished with the cursor. For further information see
"Planning for Concurrency" in topic 4.1.2.
To maintain a cursor and its position across commit points, use the WITH
HOLD option of the DECLARE CURSOR statement. The commit process releases
only locks that are not required to maintain cursor position. After the
commit process, open cursors are not closed. A cursor is positioned after
the last row retrieved and before the next logical row of the result table
to be returned.
The following example shows how to use a cursor to fetch data without
writing code to reposition the cursor after a commit point:
EXEC SQL
DECLARE EMPLUPDT CURSOR WITH HOLD FOR
SELECT EMPNO, LASTNAME, PHONENO, JOB, SALARY, WORKDEPT
FROM DSN8310.EMP
WHERE WORKDEPT < 'D11'
ORDER BY EMPNO
END-EXEC.
DECLARE CURSOR WITH HOLD should not be used with the new user signon
from a DB2 attachment facility, because all open cursors are closed.
DCLGEN must be used before the program is precompiled. Supply DCLGEN with
the table or view name before you precompile your program. To use the
declarations in your program, use the SQL INCLUDE statement.
DB2 must be active before you can use DCLGEN. You can invoke DCLGEN in
several different ways:
_ From ISPF through DB2I. Select the DCLGEN option on the DB2I Primary
Option Menu panel. Next, fill in the DCLGEN panel with the
information it needs to build the declarations and press ENTER.
_ Directly from TSO. To do this, sign on to TSO, issue the TSO command
"DSN", and then issue the subcommand "DCLGEN".
_ With JCL. Supply the required information, using JCL, and run DCLGEN
in batch.
If you wish to invoke DCLGEN in the foreground, and your table names
include DBCS characters, you need to use a terminal that can input and
display double-byte characters. If you do not have such a terminal,
you can enter DBCS character using the hex mode of ISPF edit.
Subtopics
3.3.1 Invoking DCLGEN through DB2I
3.3.2 Including the Data Declarations in Your Program
3.3.3 DCLGEN Support of C, COBOL, and PL/I Languages
3.3.4 Example: Adding a Table Declaration and Host-Variable Structure to a Library
The easiest way to invoke DCLGEN is through DB2I. Figure 14 shows the
DCLGEN panel you reach by selecting option 2, DCLGEN, on the DB2I Primary
Options Menu. For more instructions on using DB2I, see "Using ISPF and
DB2 Interactive (DB2I)" in topic 4.2.7.1.
+----------------------------------------------------------------------------------+
¦ ¦
¦ DSNEDP01 DCLGEN SSID: DSN ¦
¦ ===> ¦
¦ ¦
¦ Enter table name for which declarations are required: ¦
¦ 1 SOURCE TABLE NAME ===> (Unqualified table name) ¦
¦ 2 TABLE OWNER ===> ¦
¦ 3 AT LOCATION ..... ===> (Optional) ¦
¦ ¦
¦ Enter destination data set: (Can be sequential or partitioned) ¦
¦ 4 DATA SET NAME ... ===> ¦
¦ 5 DATA SET PASSWORD ===> (If password protected) ¦
¦ ¦
¦ Enter options as desired: ¦
¦ 6 ACTION .......... ===> (ADD new or REPLACE old declaration) ¦
¦ 7 COLUMN LABEL .... ===> (Enter YES for column label) ¦
¦ 8 STRUCTURE NAME .. ===> (Optional) ¦
¦ 9 FIELD NAME PREFIX ===> (Optional) ¦
¦ 10 DELIMIT DBCS .... ===> (Enter YES to delimit DBCS identifiers) ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ PRESS: ENTER to process END to exit HELP for more information ¦
¦ ¦
¦ ¦
+----------------------------------------------------------------------------------+
The following information explains the options on the DCGLEN panel and how
to fill in the necessary fields in order to invoke the declarations
generator.
'DON''S TABLE'
TABLE OWNER
Is the table name qualifier. If you do not specify this
value, and the table is a local table, DB2 assumes that the
table qualifier is your TSO logon ID. If the table is at a
remote location, you must specify this value.
AT LOCATION
Is the location of the table in an interconnected network.
The AT keyword option is used to prefix the table name on the
SQL DECLARE statement as follows:
location_name.owner_id.table_name
for example,
PLAINS_GA.CARTER.CROP_YIELD_89
ACTION
Tells what to do with the output when it is sent to a
partitioned data set. (The option is ignored if the data set
you specified in field 3 is sequential.)
COLUMN LABEL
Includes labels declared on any columns of the table or view
DCLGEN is operating on. If you enter YES in this field, and
if the table or view for which you are creating declarations
includes column labels, those labels is included as comments
in the data declarations DCLGEN produces. Specifying NO
causes DCLGEN to ignore any column labels it encounters.
STRUCTURE NAME
Names the generated data structure. The name can be up to 31
bytes in length. If the name is not a DBCS string, and the
first character is not alphabetic, then the name must be
enclosed in apostrophes. If you leave this field blank,
DCLGEN generates a name that contains the table or view name
with a prefix of DCL. If the language is COBOL or PL/I, and
the table or view name consists of a DBCS string, the prefix
consists of DBCS characters.
If you use the C language, the letters you enter will not be
folded to uppercase letters.
If you use the C language, the letters you enter will not be
folded to uppercase letters.
DELIMIT DBCS
Specifies whether to delimit DBCS table names and column names
in the DCLGEN table declaration. If you enter YES, DBCS table
and column names are surrounded by SQL delimiters. YES is the
default.
_ The name is a DBCS string, and you have requested that DBCS names be
delimited.
If you are using an SQL reserved word as an identifier, you must edit the
DCLGEN output in order to add the appropriate SQL delimiters.
Use the following SQL INCLUDE statement to insert the table declaration
and COBOL record description produced through the DCLGEN process into your
source program:
EXEC SQL
INCLUDE member name
END-EXEC.
EXEC SQL
INCLUDE DECEMP
END-EXEC.
For various reasons, there are times when DCLGEN does not produce the
results you expect. You might need to edit the results, tailoring the
output to your specific needs. For example, DCLGEN does not generate
columns that are named NOT NULL WITH DEFAULT.
Variable names provided by DCLGEN are derived from the source in the
database. In Table 6, var represents variable names that are provided by
DCLGEN when it is necessary to clarify the host language declaration.
+-----------------------------------------------------------------------------------
----------------------------------+
¦ Table 6. Declarations Generated by DCLGEN
¦
+-----------------------------------------------------------------------------------
----------------------------------¦
¦ SQL Data Type ¦ C ¦ COBOL
¦ PL/I ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ SMALLINT ¦ short int ¦ PIC S9(4)
¦ BIN FIXED(15) ¦
¦ ¦ ¦ USAGE COMP
¦ ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ INTEGER ¦ long int ¦ PIC S9(9)
¦ BIN FIXED(31) ¦
¦ ¦ ¦ USAGE COMP
¦ ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ DECIMAL(p,s) or ¦ Not generated (no ¦ PIC S9(p-s)V9(s)
¦ DEC FIXED(p,s) ¦
¦ NUMERIC(p,s) ¦ exact equivalent); ¦ USAGE COMP-3
¦ If p>15, a warning ¦
¦ ¦ comment replaces ¦ If p>18, a warning
¦ is generated. ¦
¦ ¦ the declaration. ¦ is generated.
¦ ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ REAL or ¦ float ¦ USAGE COMP-1
¦ BIN FLOAT(n) ¦
¦ FLOAT(n) ¦ ¦
¦ ¦
¦ 1 <= n <= 21 ¦ ¦
¦ ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ DOUBLE PRECISION ¦ double ¦ USAGE COMP-2
¦ BIN FLOAT(n) ¦
¦ or FLOAT(n) ¦ ¦
¦ ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ CHAR(1) ¦ char ¦ PIC X(1)
¦ CHAR(1) ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ CHAR(n) ¦ char var [n+1] ¦ PIC X(n)
¦ CHAR(n) ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ VARCHAR(n) ¦ struct ¦ 10 var.
¦ CHAR(n) VAR ¦
¦ ¦ {short int var_len; ¦ 49 var_LEN PIC 9(4) USAGE COMP.
¦ ¦
¦ ¦ char var_data[n]¦ 49 var_TEXT PIC X(n).
¦ ¦
¦ ¦ } var; ¦
¦ ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ GRAPHIC(n) ¦ Not generated (no ¦ PIC G(n) USAGE DISPLAY-1.(1)
¦ GRAPHIC(n) ¦
¦ ¦ exact equivalent); ¦ or
¦ ¦
¦ ¦ comment replaces ¦ PIC N(n).(1)
¦ ¦
¦ ¦ declaration. ¦
¦ ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ VARGRAPHIC(n) ¦ Not generated (no ¦ 10 var.
¦ GRAPHIC(n) VAR ¦
¦ ¦ exact equivalent); ¦ 49 var_LEN PIC 9(4) USAGE COMP.
¦ ¦
¦ ¦ comment replaces ¦ 49 var_TEXT PIC G(n) USAGE
DISPLAY-1.(1) ¦ ¦
¦ ¦ declaration. ¦ or
¦ ¦
¦ ¦ ¦ 10 var.
¦ ¦
¦ ¦ ¦ 49 var_LEN PIC 9(4) USAGE COMP.
¦ ¦
¦ ¦ ¦ 49 var_TEXT PIC N(n).(1)
¦ ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ DATE ¦ char var[11](2) ¦ PIC X(10)(2)
¦ CHAR(10)(2) ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ TIME ¦ char var[9](3) ¦ PIC X(8)(3)
¦ CHAR(8)(3) ¦
+---------------------+------------------------
+-------------------------------------------------+--------------------¦
¦ TIMESTAMP ¦ char var[27] ¦ PIC X(26)
¦ CHAR(26) ¦
+-----------------------------------------------------------------------------------
----------------------------------¦
¦ Notes:
¦
¦
¦
¦ 1. DCLGEN chooses the format based on the character you specify as the DBCS
symbol on the COBOL Defaults panel. ¦
¦
¦
¦ 2. This declaration is used unless there is a date installation exit for
formatting dates, in which case the ¦
¦ length is that specified for the LOCAL DATE LENGTH installation option.
¦
¦
¦
¦ 3. This declaration is used unless there is a time installation exit for
formatting times, in which case the ¦
¦ length is that specified for the LOCAL TIME LENGTH installation option.
¦
+-----------------------------------------------------------------------------------
----------------------------------+
For further details about the DCLGEN subcommand, see Chapter 2 of Command
and Utility Reference.
Subtopics
3.3.4.1 Step 1. Specify VS COBOL II as the Host Language
3.3.4.2 Step 2. Create the Table Declaration and Host Structure
3.3.4.3 Step 3. Examine the Results
Select option D on the ISPF/PDF menu to display the DB2I Defaults panel.
Specify COB2 as the application language as shown in Figure 15, and then
press Enter. The COBOL Defaults panel is then displayed as shown in
Figure 16.
Fill in the COBOL defaults panel as necessary and press Enter to save the
new defaults, if any, and return to the DB2I Primary Option menu.
+----------------------------------------------------------------------------------+
¦ ¦
¦ ¦
¦ ¦
¦ DSNEOP01 DB2I DEFAULTS ¦
¦ COMMAND ===>_ ¦
¦ ¦
¦ Change defaults as desired: ¦
¦ ¦
¦ 1 DB2 NAME ............. ===> DSN (Subsystem identifier) ¦
¦ 2 DB2 CONNECTION RETRIES ===> 0 (How many retries for DB2 connection¦
¦ 3 APPLICATION LANGUAGE ===> COB2 (ASM/ASMH,C,COBOL/COB2,FORTRAN,PLI) ¦
¦ 4 LINES/PAGE OF LISTING ===> 80 (A number from 5 to 999) ¦
¦ 5 MESSAGE LEVEL ........ ===> I (Information, Warning, Error, Severe¦
¦ 6 SQL STRING DELIMITER ===> DEFAULT (DEFAULT, ' or ") ¦
¦ 7 DECIMAL POINT ........ ===> . (. or ,) ¦
¦ 8 STOP IF RETURN CODE >= ===> 8 (Lowest terminating return code) ¦
¦ 9 NUMBER OF ROWS ===> 20 (For ISPF Tables) ¦
¦ ¦
¦ 10 DB2I JOB STATEMENT: (Optional if your site has a SUBMIT exit) ¦
¦ ===> //USRT001A JOB (ACCOUNT),'NAME' ¦
¦ ===> //* ¦
¦ ===> //* ¦
¦ ===> //* ¦
¦ ¦
¦ ¦
¦ PRESS: ENTER to process END to cancel HELP for more information ¦
¦ ¦
¦ ¦
+----------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------+
¦ ¦
¦ ¦
¦ ¦
¦ DSNEOP02 COBOL DEFAULTS ¦
¦ COMMAND ===>_ ¦
¦ ¦
¦ Change defaults as desired: ¦
¦ ¦
¦ 1 COBOL STRING DELIMITER ===> (DEFAULT, ' or ") ¦
¦ 2 DBCS SYMBOL FOR DCLGEN ===> (G/N - Character in PIC clause) ¦
¦ ¦
¦ ¦
Figure 16. The COBOL Defaults Panel. Shown only if the application
language is COBOL or COB2.
Fill in the fields as shown in Figure 17, and then press Enter.
+----------------------------------------------------------------------------------+
¦ ¦
¦ DSNEDP01 DCLGEN SSID: DSN ¦
¦ ===> ¦
¦ Enter table name for which declarations are required: ¦
¦ ¦
¦ 1 SOURCE TABLE NAME ===> DSN8310.VPHONE ¦
¦ 2 TABLE OWNER ===> ¦
¦ 3 AT LOCATION ..... ===> (Location of table, optional) ¦
¦ ¦
¦ Enter destination data set: (Can be sequential or partitioned) ¦
¦ 4 DATA SET NAME ... ===> TEMP(VPHONEC) ¦
¦ 5 DATA SET PASSWORD ===> (If password protected) ¦
¦ ¦
¦ Enter options as desired: ¦
¦ 6 ACTION .......... ===> ADD (ADD new or REPLACE old declaration) ¦
¦ 7 COLUMN LABEL .... ===> NO (Enter YES for column label) ¦
¦ 8 STRUCTURE NAME .. ===> (Optional) ¦
¦ 9 FIELD NAME PREFIX ===> (Optional) ¦
¦ 10 DELIMIT DBCS ===> YES (Enter YES to delimit DBCS identifiers) ¦
¦ ¦
¦ ¦
¦ PRESS: ENTER to process END to exit HELP for more information ¦
¦ ¦
+----------------------------------------------------------------------------------+
Figure 17. DCLGEN Panel--Selecting Source Table and Destination Data Set
+----------------------------------------------------------------------------------+
¦ ¦
¦ EXECUTION COMPLETE, MEMBER VPHONEC ADDED ¦
¦ *** ¦
¦ ¦
DB2 then displays the screen as shown in Figure 19. Press Enter to return
to the DB2I Primary Option menu.
+----------------------------------------------------------------------------------+
¦ ¦
¦ DSNEDP01 DCLGEN SSID: DSN ¦
¦ ===> ¦
¦ DSNE294I SYSTEM RETCODE=000 USER OR DSN RETCODE=0 ¦
¦ Enter table name for which declarations are required: ¦
¦ 1 SOURCE TABLE NAME ===> DSN8310.VPHONE ¦
¦ 2 TABLE OWNER ===> ¦
¦ 3 AT LOCATION ..... ===> (Location of table, optional) ¦
¦ ¦
¦ Enter destination data set: (Can be sequential or partitioned) ¦
¦ 4 DATA SET NAME ... ===> TEMP(VPHONEC) ¦
¦ 5 DATA SET PASSWORD ===> (If password protected) ¦
¦ ¦
¦ Enter options as desired: ¦
¦ 6 ACTION .......... ===> ADD (ADD new or REPLACE old declaration) ¦
¦ 7 COLUMN LABEL .... ===> NO (Enter YES for column label) ¦
¦ 8 STRUCTURE NAME .. ===> (Optional) ¦
¦ 9 FIELD NAME PREFIX ===> (Optional) ¦
¦ 10 DELIMIT DBCS ===> (Enter YES to delimit DBCS identifiers) ¦
¦ ¦
¦ ¦
¦ PRESS: ENTER to process END to exit HELP for more information ¦
¦ ¦
+----------------------------------------------------------------------------------+
To browse or edit the results, first exit from DB2I by entering X on the
command line of the DB2I Primary Option menu. The ISPF/PDF menu is then
displayed, and you can select either the browse or the edit option to view
the results.
As with any application, you must plan and design programs to meet the
application's requirements. Designing a DB2 database application requires
that you also plan for binding, locking, recovery, and perhaps for using
distributed data. This chapter includes the following subjects:
Subtopics
4.1.1 Planning to Precompile and Bind
4.1.2 Planning for Concurrency
4.1.3 Planning for Recovery
4.1.4 Planning to Access Distributed Data
DB2 application programs include SQL statements. You cannot compile these
programs until you change the SQL statements into language recognized by
your compiler or assembler. To do this, you must communicate the SQL
requests to DB2 by some other means. The DB2 precompiler does the
following:
After you have precompiled your source program, you create a load module,
possibly one or more packages, and an application plan. It does not
matter which you do first. Creating a load module is similar to compiling
and link-editing an application containing no SQL statements. Creating a
package or an application plan, a process unique to DB2, involves binding
one or more DBRMs.
PICTURE 2
Subtopics
4.1.1.1 Planning to Precompile
4.1.1.2 Planning to Bind
4.1.1.3 Automatic Rebinding
The DB2 precompiler provides many options. Most of the options do not
affect the way you design or code the program. They allow you to tell the
precompiler what you have already done--for example, what host language
you use or what value you depend on for the maximum precision of a decimal
number. Or, they tell the precompiler what you want it to do--how many
lines per page in the listing or whether you want a cross-reference
report. In many cases, you may want to accept the default value provided.
A few options, however, can affect the way you code. For example, you
need to know if you are using NOFOR or STDSQL(86) before you begin coding.
Before you begin coding, please review the list of options in Table 24 in
topic 4.2.2.4.
To access DB2 data, an SQL statement requires an access path. For dynamic
SQL, such as statements issued through SPUFI, DB2 determines the access
path when the statement executes. For statements that are not executed
often, this method is usually acceptable. However, an application
typically runs the same SQL statements repeatedly. In this case,
determining the access path at execution time wastes system resources,
because the same path must be determined repeatedly. To reduce use of
system resources, the access paths used each time the statements execute
can be established once through binding.
Depending upon how you design your DB2 application, you might bind all
your DBRMs in one operation, creating only a single application plan. Or,
you might bind some or all of your DBRMs into separate packages in
separate operations. After that, you must still perform a bind process
for the entire application, listing the packages that are included and
binding any DBRMs that are not bound into packages. Regardless of what
the plan contains, you must bind a plan before the application can run.
Subtopics
4.1.1.2.1 Deciding How to Use Packages
4.1.1.2.2 Deciding What to Put into a Plan
4.1.1.2.3 Rebinding a Package
4.1.1.2.4 Rebinding a Plan
The question of how to use packages affects your application design from
the beginning. For example, you might decide to put certain SQL
statements together in the same program in order to precompile them into
the same DBRM and then bind them into the same package.
At its simplest, you can bind each DBRM into its own package. A
one-to-one correspondence between programs and packages might easily allow
you to keep track of each. However, your application could consist of too
many packages to track easily.
At the other extreme, you can bind all your DBRMs to a single plan. This
approach has the disadvantage that, whenever your plan is rebound, the
operation includes all of the DBRMs, even though not all of them have
changed. For more information about rebinding, see"Automatic Rebinding"
in topic 4.1.1.3 .
You must decide how to use packages based on your application design and
your operational objectives. Keep in mind the following:
_ When using packages, the entire plan need not be rebound when a change
is made to one SQL statement. Only the package associated with the
changed statement has to be rebound.
_ Most options specified when binding the plan apply only to the DBRMs
bound directly to the plan. You can use different options when you
bind a package that is included in the plan.
_ By using packages, you can use different qualifiers for SQL statements
in different parts of your application. When you bind a package, you
can name a qualifier for the unqualified object names in its DBRM.
When you bind the plan, you can name a different qualifier for
unqualified object names in DBRMs bound directly to the plan. Hence,
by rebinding, you can redirect your SQL statements from, say, a test
table to a production table.
+--- CICS -----------------------------------------------------------+
¦ ¦
¦ With packages, you probably do not need a dynamic plan selection ¦
¦ and its accompanying exit routine. A package listed within a plan ¦
¦ is not accessed until it is executed. However, it is possible to ¦
¦ use dynamic plan selection and packages together. Doing so can ¦
¦ reduce the number of plans in an application, and fewer plans can ¦
¦ mean that less effort is required to maintain the dynamic plan ¦
¦ exit). See "Using Packages with Dynamic Plan Selection" in ¦
¦ topic 4.2.4.4 for information on using packages with dynamic plan ¦
¦ selection. ¦
¦ ¦
+--------------------------------------------------------------------+
_ Develop a naming convention and strategy for the most effective and
efficient use of your packages.
Input to binding the plan can include DBRMs only, a package list only, or
a combination of the two.
Binding All DBRMs to a Plan: Binding all DBRMs to a plan is suitable for
small applications that are unlikely to change or that require all
resources to be acquired when the plan is allocated rather than when your
program first uses them.
Binding with a Package List Only: Binding a plan that includes only a
package list makes maintenance easier when the application will change
significantly over time. Because different BIND options can be specified
when binding each package, you can control such things as qualifiers and
isolation level.
Binding with Both DBRMs and a Package List: Binding DBRMs directly to the
plan and specifying a package list is suitable for maintaining existing
applications. You can add a package list when rebinding an existing plan.
To migrate gradually to using packages, bind DBRMs as packages when some
change is needed.
The following example shows the options for rebinding a package in the
collection GROUP1. In the example below, the location ID is SNTERSA, the
package ID is PROGA, and the version ID is V1. The connection types shown
in the REBIND subcommand replace connection types that might have been
specified during the original BIND operation.
REBIND PACKAGE(*)
If DBRMs for an application are bound directly to a plan, then the entire
plan must be recreated using BIND with the REPLACE option.
DB2 allows more than one application process to access the same data at
essentially the same time. This is known as concurrency, and it cannot be
provided without cost. To control such undesirable effects as lost
updates, access to uncommitted data, and unrepeatable reads, concurrency
must be controlled.
Subtopics
4.1.2.1 The Object of a Lock
4.1.2.2 The Size of a Lock
4.1.2.3 The Duration of a Lock
4.1.2.4 The Mode of a Lock
4.1.2.5 Lock Compatibility
4.1.2.6 Effects of DB2 Locks
4.1.2.7 Specifying the Bind Options that Affect Locking
4.1.2.8 Explicitly Locking a Table
4.1.2.9 Access Paths
The object of a lock is the resource being locked. You have most control
over locks on user data in tables. But there are also locks on DB2
internal objects. Most of those you are never aware of, but sometimes you
have to consider locks on:
Simple Tablespaces
Generally it contains a single table. However it can contain multiple tables.
It is possible to store the records from related tables together, in an interleaved
fashion.
This particularly improves the performance of table join queries.
However the queries involving sequential tablespace scans will suffer.
Partitioned Tablespaces
A Partitioned Tablespace contains exactly 1 table.
Very large tables are generally partitioned.
The partitioning is done on the value ranges of a column or combination of columns.
Each individual partition can be individually recovered or reorganised.
Each partition can be associated to independent storage groups and thus stored on
different DASD volumes to reduce the I/O load.
Segmented Tablespaces
A Segmented Tablespace can contain multiple tables.
However the cross clustering of tables is not allowed.
A Table can span across multiple Segments.
One Segment can contain records from a single Table only.
Segment size can be defined while defining the table using SEGSIZE parameter.
It has to be a multiple of 4 pages ranging from 4 to 64 pages.
More Than One Table in a Table Space: In a segmented table space, a lock
can apply to the entire table space, to a single table, or to a single
page. In a simple table space or a partitioned table space, a lock can
apply only to the entire table space or to a single page.
In a simple table space, a single page can contain rows from more than one
table. A lock on the page or on the entire table space locks all the data
in the page or table space, no matter what table the data belongs to. A
lock needed to access data from one table can make data from other tables
temporarily unavailable.
The duration of a lock is the length of time the lock is held. It varies
according to when the lock is acquired and when it is released.
Duration of Table and Table Space Locks: Table and table space locks can
be acquired when a plan is first allocated, or you can delay acquiring
them until the resource they lock is first used. For the principal means
of controlling the duration of these locks, see: "The ACQUIRE and RELEASE
Options" in topic 4.1.2.7.1.
Duration of Page Locks: Page locks are acquired when the page is first
accessed. When they are released depends on many factors. For details on
controlling the duration of page locks, see "The ISOLATION Option" in
topic 4.1.2.7.2.
The mode (sometimes state) of a lock tells what access to the locked
object is permitted to the lock owner and to any concurrent application
processes.
Figure 23 shows the possible modes for page locks; Figure 24 shows the
modes for table and table space locks. When a page is locked, the table
or table space containing it is also locked. In that case, the table or
table space lock has one of the intent modes: IS, IX, or SIX. (In
contrast, the modes S, U, and X of table and table space locks are
sometimes called gross modes.)
+------------------------------------------------------------------------+
¦ ¦
¦ Page Lock Modes ¦
¦ ¦
¦ Modes and their effects are listed in the order of increasing control ¦
¦ over resources. ¦
¦ ¦
¦ S (SHARE) ¦
¦ The lock owner and any concurrent processes can read, but not ¦
¦ change, the locked page. Concurrent processes can acquire S or ¦
¦ U locks on the page or might read data without acquiring a page ¦
¦ lock. ¦
¦ ¦
¦ U (UPDATE) ¦
¦ The lock owner can read, but not change, the locked page; ¦
¦ however, the owner can promote the lock to an X lock and then ¦
¦ can change the page. Processes concurrent with the U lock can ¦
¦ acquire S locks and read the page, but no concurrent process can ¦
¦ acquire a U lock. ¦
¦ ¦
¦ U locks reduce the chance of deadlocks when the lock owner is ¦
¦ reading a page to determine whether to change it. If the lock ¦
¦ is promoted to mode X, that lock is held at least until a commit ¦
¦ point. But if the lock is not promoted, it might be released ¦
¦ before the commit point. ¦
¦ ¦
¦ X (EXCLUSIVE) ¦
¦ The lock owner can read or change the locked page. Concurrent ¦
¦ processes cannot acquire any lock on the page nor can they ¦
¦ access the locked page. ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
+------------------------------------------------------------------------+
Figure 23. Modes of Page Locks
+------------------------------------------------------------------------+
¦ ¦
¦ Table and Table Space Lock Modes ¦
¦ ¦
¦ Modes and their effects are listed in the order of increasing control ¦
¦ over resources. ¦
¦ ¦
¦ ¦
¦ ¦
¦ IS (INTENT SHARE) ¦
¦ The lock owner can read data in the table or table space, but ¦
¦ not change it. Concurrent processes can both read and change ¦
¦ the data. The lock owner might acquire a page lock on any data ¦
¦ it reads. ¦
¦ ¦
¦ IX (INTENT EXCLUSIVE) ¦
¦ The lock owner and concurrent processes can read and change data ¦
¦ in the table or table space. The lock owner must acquire a page ¦
¦ lock on any data it reads or changes. ¦
¦ ¦
¦ S (SHARE) ¦
¦ The lock owner and any concurrent processes can read, but not ¦
¦ change, data in the table or table space. The lock owner does ¦
¦ not need page locks on data it reads. ¦
¦ ¦
¦ U (UPDATE) ¦
¦ The lock owner can read, but not change, the locked data; ¦
¦ however, the owner can promote the lock to an X lock and then ¦
¦ can change the data. Processes concurrent with the U lock can ¦
¦ acquire S locks and read the data, but no concurrent process can ¦
¦ acquire a U lock. The lock owner does not need page locks. ¦
¦ ¦
¦ U locks reduce the chance of deadlocks when the lock owner is ¦
¦ reading data to determine whether to change it. ¦
¦ ¦
¦ SIX (SHARE with INTENT EXCLUSIVE) ¦
¦ The lock owner can read and change data in the table or table ¦
¦ space. Concurrent processes can read data in the table or table ¦
¦ space, but not change it. Only when the lock owner changes ¦
¦ data, does it acquire page locks. ¦
¦ ¦
¦ X (EXCLUSIVE) ¦
¦ The lock owner can read or change data in the table or table ¦
¦ space. No concurrent process can access the data. The lock ¦
¦ owner does not need page locks. ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
+------------------------------------------------------------------------+
Figure 24. Modes of Table and Table Space Locks
+------------------------------+
¦ Table 19. Compatibility of ¦
¦ Page Lock Modes ¦
+------------------------------¦
¦ Page ¦ ¦ ¦ ¦
¦ Lock Mode¦ S ¦ U ¦ X ¦
+------------+-----+-----+-----¦
¦ S ¦ Yes ¦ Yes ¦ No ¦
+------------+-----+-----+-----¦
¦ U ¦ Yes ¦ No ¦ No ¦
+------------+-----+-----+-----¦
¦ X ¦ No ¦ No ¦ No ¦
+------------------------------+
REFER NOTES