SQL Programming
SQL Programming
RBAF-Y000-00
AS/400e IBM
RBAF-Y000-00
© Copyright International Business Machines Corporation 1997, 1999. All rights reserved.
Note to U.S. Government Users — Documentation related to restricted rights — Use, duplication or disclosure is
subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.
Contents
About DB2 UDB for AS/400 SQL Programming. . . . . . . . . . . . xvii
Who should read this book . . . . . . . . . . . . . . . . . . . . xvii
Assumptions Relating to Examples of SQL Statements . . . . . . . . . xvii
How to Interpret Syntax Diagrams in this Guide . . . . . . . . . . . xviii
AS/400 Operations Navigator . . . . . . . . . . . . . . . . . . . xix
Installing Operations Navigator. . . . . . . . . . . . . . . . . . xx
How this book has changed . . . . . . . . . . . . . . . . . . . . xxi
Prerequisite and related information . . . . . . . . . . . . . . . . . xxi
How to send your comments . . . . . . . . . . . . . . . . . . . xxi
Contents v
Returning a Completion Status to the Calling Program . . . . . . . . . . 134
Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Example 1. ILE C and PL/I Procedures Called From ILE C Applications . . 136
Chapter 11. Common Concepts and Rules for Using SQL with Host
Languages . . . . . . . . . . . . . . . . . . . . . . . . . 215
Using Host Variables in SQL Statements . . . . . . . . . . . . . . . 215
Assignment Rules . . . . . . . . . . . . . . . . . . . . . . 216
Indicator Variables . . . . . . . . . . . . . . . . . . . . . . 219
Handling SQL Error Return Codes . . . . . . . . . . . . . . . . . 221
Handling Exception Conditions with the WHENEVER Statement . . . . . . 222
Contents vii
Names . . . . . . . . . . . . . . . . . . . . . . . . . . 254
COBOL Compile-Time Options. . . . . . . . . . . . . . . . . . 254
Statement Labels . . . . . . . . . . . . . . . . . . . . . . 255
WHENEVER Statement . . . . . . . . . . . . . . . . . . . . 255
Multiple source programs. . . . . . . . . . . . . . . . . . . . 255
Using Host Variables . . . . . . . . . . . . . . . . . . . . . . 255
Declaring Host Variables . . . . . . . . . . . . . . . . . . . . 255
Using Host Structures . . . . . . . . . . . . . . . . . . . . . . 264
Host Structure . . . . . . . . . . . . . . . . . . . . . . . . 265
Host Structure Indicator Array . . . . . . . . . . . . . . . . . . 268
Using Host Structure Arrays . . . . . . . . . . . . . . . . . . . 268
Host Structure Array . . . . . . . . . . . . . . . . . . . . . 269
Host Array Indicator Structure . . . . . . . . . . . . . . . . . . 272
Using External File Descriptions . . . . . . . . . . . . . . . . . . 272
Using External File Descriptions for Host Structure Arrays. . . . . . . . 273
Determining Equivalent SQL and COBOL Data Types . . . . . . . . . . 274
Notes on COBOL Variable Declaration and Usage . . . . . . . . . . 276
Using Indicator Variables . . . . . . . . . . . . . . . . . . . . . 276
Chapter 15. Coding SQL Statements in RPG for AS/400 Applications . . . 297
Defining the SQL Communications Area . . . . . . . . . . . . . . . 297
Defining SQL Descriptor Areas. . . . . . . . . . . . . . . . . . . 298
Embedding SQL Statements . . . . . . . . . . . . . . . . . . . 298
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Comments . . . . . . . . . . . . . . . . . . . . . . . . . 299
Continuation for SQL Statements . . . . . . . . . . . . . . . . . 299
Including Code . . . . . . . . . . . . . . . . . . . . . . . 299
Sequence Numbers . . . . . . . . . . . . . . . . . . . . . . 299
Names . . . . . . . . . . . . . . . . . . . . . . . . . . 299
Statement Labels . . . . . . . . . . . . . . . . . . . . . . 300
WHENEVER Statement . . . . . . . . . . . . . . . . . . . . 300
Using Host Variables . . . . . . . . . . . . . . . . . . . . . . 300
Chapter 16. Coding SQL Statements in ILE RPG for AS/400 Applications . 309
Defining the SQL Communications Area . . . . . . . . . . . . . . . 309
Defining SQL Descriptor Areas. . . . . . . . . . . . . . . . . . . 310
Embedding SQL Statements . . . . . . . . . . . . . . . . . . . 311
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Comments . . . . . . . . . . . . . . . . . . . . . . . . . 311
Continuation for SQL Statements . . . . . . . . . . . . . . . . . 311
Including Code . . . . . . . . . . . . . . . . . . . . . . . 312
Sequence Numbers . . . . . . . . . . . . . . . . . . . . . . 312
Names . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Statement Labels . . . . . . . . . . . . . . . . . . . . . . 312
WHENEVER Statement . . . . . . . . . . . . . . . . . . . . 312
Using Host Variables . . . . . . . . . . . . . . . . . . . . . . 312
Declaring Host Variables . . . . . . . . . . . . . . . . . . . . 313
Using Host Structures . . . . . . . . . . . . . . . . . . . . . . 314
Using Host Structure Arrays . . . . . . . . . . . . . . . . . . . . 314
Declaring LOB Host Variables . . . . . . . . . . . . . . . . . . . 315
LOB Host Variables . . . . . . . . . . . . . . . . . . . . . . 315
LOB Locators . . . . . . . . . . . . . . . . . . . . . . . . 316
LOB File Reference Variables . . . . . . . . . . . . . . . . . . 316
Using External File Descriptions . . . . . . . . . . . . . . . . . . 316
External File Description Considerations for Host Structure Arrays. . . . . 317
Determining Equivalent SQL and RPG Data Types . . . . . . . . . . . 318
Notes on ILE/RPG 400 Variable Declaration and Usage . . . . . . . . 322
Using Indicator Variables . . . . . . . . . . . . . . . . . . . . . 322
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 322
SQLDA Example of the SQLDA for a Multiple Row-Area Fetch . . . . . . . 323
Contents ix
Avoiding REXX Conversion . . . . . . . . . . . . . . . . . . . 332
Using Indicator Variables . . . . . . . . . . . . . . . . . . . . . 332
Chapter 18. Preparing and Running a Program with SQL Statements . . . 333
Basic Processes of the SQL Precompiler . . . . . . . . . . . . . . . 333
Input to the Precompiler . . . . . . . . . . . . . . . . . . . . 334
Source File CCSIDs . . . . . . . . . . . . . . . . . . . . . 334
Output from the Precompiler . . . . . . . . . . . . . . . . . . 335
Non-ILE Precompiler Commands . . . . . . . . . . . . . . . . . . 340
Compiling a Non-ILE Application Program . . . . . . . . . . . . . 340
ILE Precompiler Commands. . . . . . . . . . . . . . . . . . . . 341
Compiling an ILE Application Program . . . . . . . . . . . . . . . 341
Precompiling for the VisualAge C++ for OS/400 Compiler . . . . . . . . 342
Interpreting Application Program Compile Errors . . . . . . . . . . . . 343
Error and Warning Messages during a Compile . . . . . . . . . . . 343
Binding an Application . . . . . . . . . . . . . . . . . . . . . . 344
Program References . . . . . . . . . . . . . . . . . . . . . 345
Displaying Precompiler Options . . . . . . . . . . . . . . . . . . 345
Running a Program with Embedded SQL . . . . . . . . . . . . . . . 346
OS/400 DDM Considerations . . . . . . . . . . . . . . . . . . 346
Override Considerations . . . . . . . . . . . . . . . . . . . . 346
SQL Return Codes . . . . . . . . . . . . . . . . . . . . . . 347
Chapter 23. Using the DB2 UDB for AS/400 Predictive Query Governor . . 391
Cancelling a Query . . . . . . . . . . . . . . . . . . . . . . . 392
General Implementation Considerations . . . . . . . . . . . . . . . 392
User Application Implementation Considerations . . . . . . . . . . . . 392
Controlling the Default Reply to the Inquiry Message . . . . . . . . . . 393
Using the Governor for Performance Testing. . . . . . . . . . . . . . 393
Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 394
Chapter 24. DB2 UDB for AS/400 Data Management and Query Optimizer
Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
General Optimization Tips . . . . . . . . . . . . . . . . . . . . 395
Data Management Methods . . . . . . . . . . . . . . . . . . . . 396
Access Path . . . . . . . . . . . . . . . . . . . . . . . . 396
Access Method . . . . . . . . . . . . . . . . . . . . . . . 397
Data Access Methods . . . . . . . . . . . . . . . . . . . . . . 420
The Optimizer . . . . . . . . . . . . . . . . . . . . . . . . . 422
Cost Estimation . . . . . . . . . . . . . . . . . . . . . . . 423
Access Plan Validation. . . . . . . . . . . . . . . . . . . . . 425
Optimizer Decision-Making Rules . . . . . . . . . . . . . . . . . 425
Join Optimization . . . . . . . . . . . . . . . . . . . . . . . 426
Grouping Optimization . . . . . . . . . . . . . . . . . . . . . 442
Effectively Using SQL Indexes . . . . . . . . . . . . . . . . . . . 446
Using Indexes With Sort Sequence . . . . . . . . . . . . . . . . . 449
Using Indexes and Sort Sequence With Selection, Joins, or Grouping . . . 449
Ordering . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Example Indexes . . . . . . . . . . . . . . . . . . . . . . . 450
Tips for using VARCHAR and VARGRAPHIC data types . . . . . . . . . 456
Contents xi
Improving Performance of SQL PREPARE Statements . . . . . . . . . . 470
Effects on Performance When Using Long Object Names . . . . . . . . . 470
Improving Performance Using the Precompile Options . . . . . . . . . . 471
Improving Performance by Using Structure Parameter Passing Techniques . . 472
Background Information on Parameter Passing. . . . . . . . . . . . 472
Some Differences Because of Structure Parameter Passing Techniques . . 473
Controlling Parallel Processing . . . . . . . . . . . . . . . . . . . 473
Controlling Parallel Processing System Wide . . . . . . . . . . . . 474
Controlling Parallel Processing for a Job . . . . . . . . . . . . . . 474
Appendix C. Sample Programs Using DB2 UDB for AS/400 Statements . . 605
Examples of programs that use SQL statements . . . . . . . . . . . . 605
SQL Statements in ILE C and C++ Programs . . . . . . . . . . . . . 606
SQL Statements in COBOL and ILE COBOL Programs. . . . . . . . . . 613
SQL Statements in PL/I . . . . . . . . . . . . . . . . . . . . . 621
SQL Statements in RPG for AS/400 Programs . . . . . . . . . . . . . 628
SQL Statements in ILE RPG for AS/400 Programs . . . . . . . . . . . 634
SQL Statements in REXX Programs. . . . . . . . . . . . . . . . . 640
Report Produced by Sample Programs. . . . . . . . . . . . . . . . 643
Contents xiii
CRTSQLPLI (Create Structured Query Language PL/I) Command. . . . . . 712
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . 715
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 715
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 728
CRTSQLRPG (Create Structured Query Language RPG) Command . . . . . 728
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . 731
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 732
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 744
CRTSQLRPGI (Create SQL ILE RPG Object) Command . . . . . . . . . 744
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . 748
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 748
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 761
CRTSQLPKG (Create Structured Query Language Package) Command . . . 762
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . 763
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 763
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 765
CVTSQLCPP (Convert Structured Query Language C++ Source) Command . . 766
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . 769
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 769
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 781
DLTSQLPKG (Delete Structured Query Language Package) Command. . . . 781
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . 782
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 782
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 783
PRTSQLINF (Print Structured Query Language Information) Command . . . . 783
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . 783
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 783
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 784
RUNSQLSTM (Run Structured Query Language Statement) Command . . . . 784
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . 786
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 786
Parameters for SQL procedures . . . . . . . . . . . . . . . . . 792
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 794
STRSQL (Start Structured Query Language) Command . . . . . . . . . 794
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . 796
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 796
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 801
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . 845
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847
Contents xv
xvi DB2 UDB for AS/400 SQL Programming V4R4
About DB2 UDB for AS/400 SQL Programming
This book explains to programmers and database administrators:
v How to use the DB2 SQL for AS/400 licensed program
v How to access data in a database
v How to prepare, run, test, and optimize an application program containing SQL
statements.
For more information on DB2 UDB for AS/400 SQL guidelines and examples for
implementation in an application programming environment, see the following
books:
v DB2 UDB for AS/400 SQL Reference
v DB2 UDB for AS/400 SQL Call Level Interface
Note: The DB2 UDB for AS/400 library will only be available in the AS/400e
Information Center beginning in Version 4, Release 4.
v DATABASE 2/400 Advanced Database Functions, GG24-4249.
Because this guide is for the application programmer, most of the examples are
shown as if they were written in an application program. However, many examples
can be slightly changed and run interactively by using interactive SQL. The syntax
of an SQL statement, when using interactive SQL, differs slightly from the format of
the same statement when it is embedded in a program.
ÊÊ required_item ÊÍ
ÊÊ required_item ÊÍ
optional_item
If an optional item appears above the main path, that item has no effect on the
execution of the statement and is used only for readability.
optional_item
ÊÊ required_item ÊÍ
v If you can choose from two or more items, they appear vertically, in a stack.
If you must choose one of the items, one item of the stack appears on the main
path.
ÊÊ required_item required_choice1 ÊÍ
required_choice2
If choosing one of the items is optional, the entire stack appears below the main
path.
If one of the items is the default, it will appear above the main path and the
remaining choices will be shown below.
default_choice
ÊÊ required_item ÊÍ
optional_choice
optional_choice
v An arrow returning to the left, above the main line, indicates an item that can be
repeated.
ÊÊ required_item · repeatable_item ÊÍ
If the repeat arrow contains a comma, you must separate repeated items with a
comma.
ÊÊ required_item · repeatable_item ÊÍ
A repeat arrow above a stack indicates that you can repeat the items in the
stack.
v Keywords appear in uppercase (for example, FROM). They must be spelled exactly
as shown. Variables appear in all lowercase letters (for example, column-name).
They represent user-supplied names or values.
v If punctuation marks, parentheses, arithmetic operators, or other such symbols
are shown, you must enter them as part of the syntax.
This new interface has been designed to make you more productive and is the only
user interface to new, advanced features of OS/400. Therefore, IBM recommends
that you use AS/400 Operations Navigator, which has online help to guide you.
While this interface is being developed, you may still need to use a traditional
emulator such as PC5250 to do some of your tasks.
To select the subcomponents that you want to install, select the Custom installation
option. (After Operations Navigator has been installed, you can add subcomponents
by using Client Access Selective Setup.)
1. Display the list of currently installed subcomponents in the Component
Selection window of Custom installation or Selective Setup.
2. Select AS/400 Operations Navigator.
3. Select any additional subcomponents that you want to install and continue with
Custom installation or Selective Setup.
After you install Client Access, double-click the AS400 Operations Navigator icon
on your desktop to access Operations Navigator and create an AS/400 connection.
SQL consists of statements and clauses that describe what you want to do with the
data in a database and under what conditions you want to do it.
SQL can access data in a remote relational database, using the IBM Distributed
Relational Database Architecture* (DRDA*). This function is described in
Chapter 28. Distributed Relational Database Function, of this guide. Further
information about DRDA is contained in the Distributed Database Programming
book.
SQL Concepts
DB2 UDB for AS/400 SQL consists of the following main parts:
v SQL run-time support
SQL run-time parses SQL statements and runs any SQL statements. This
support is that part of the Operating System/400* (OS/400) licensed program
which allows applications that contain SQL statements to be run on systems
where the DB2 UDB Query Manager and SQL Development Kit licensed program
is not installed.
v SQL precompilers
SQL precompilers support precompiling embedded SQL statements in host
languages. The following languages are supported:
– ILE C for AS/400*
– ILE C++ for AS/400
– VisualAge C++ for AS/400
– ILE COBOL for AS/400*
– COBOL for AS/400*
– AS/400 PL/I*
– RPG III (part of RPG for AS/400*)
– ILE RPG for AS/400*
The SQL host language precompilers prepare an application program containing
SQL statements. The host language compilers then compile the precompiled host
source programs. For more information on precompiling, see Chapter 18.
Preparing and Running a Program with SQL Statements. The precompiler
support is part of the DB2 UDB Query Manager and SQL Development Kit
licensed program.
v SQL interactive interface
SQL interactive interface allows you to create and run SQL statements. For more
information on interactive SQL, see Chapter 19. Using Interactive SQL.
Interactive SQL is part of the DB2 UDB Query Manager and SQL Development
Kit licensed program.
v Run SQL Statements CL command
SQL Terminology
There are two naming conventions that can be used in DB2 UDB for AS/400
programming: system (*SYS) and SQL (*SQL). The naming convention used affects
the method for qualifying file and table names and the terms used on the interactive
SQL displays. The naming convention used is selected by a parameter on the SQL
commands or, for REXX, selected through the SET OPTION statement.
System naming (*SYS): In the system naming convention, files are qualified by
library name in the form:
library/file
If the table name is not explicitly qualified and a default collection name is specified
for the default relational database collection (DFTRDBCOL) parameter of the
CRTSQLxxx 1 or the CRTSQLPKG commands, the default collection name is used.
If the table name is not explicitly qualified and the default collection name is not
specified, the qualification rules are:
v The following CREATE statements resolve to unqualified objects as follows:
– CREATE TABLE – The table is created in the current library (*CURLIB).
– CREATE VIEW – The view is created in the first library referenced in the
subselect.
– CREATE INDEX – The index is created into the collection or library that
contains the table on which the index is being built.
1. The xxx in this command refers to the host language indicators: CI for the ILE C for AS/400 language, CPPI for the ILE C++ for
AS/400 language, CBL for the COBOL for AS/400 language, CBLI for the ILE COBOL for AS/400 language, PLI for the AS/400
PL/I language, RPG for the RPG for AS/400 language, and RPGI for the ILE RPG for AS/400 language. The CVTSQLCPP
command is considered part of this group of commands even though it does not start with CRT.
SQL naming (*SQL): In the SQL naming convention, tables are qualified by the
collection name in the form:
collection.table
If the table name is not explicitly qualified and the default collection name is
specified in the default relational database collection (DFTRDBCOL) parameter of
the CRTSQLxxx command, the default collection name is used. If the table name is
not explicitly qualified and the default collection name is not specified, the rules are:
v For static SQL, the default qualifier is the user profile of the program owner.
v For dynamic SQL or interactive SQL, the default qualifier is the user profile of the
job running the statement.
SQL Objects
SQL objects used on the AS/400 system are collections, tables, aliases, views, SQL
packages, indexes, and catalogs. SQL creates and maintains these objects as
AS/400 database objects. A brief description of these objects follows.
Data Dictionary
A collection contains a data dictionary if it was created prior to Version 3 Release 1
or if the WITH DATA DICTIONARY clause was specified on the CREATE
COLLECTION or the CREATE SCHEMA statements. A data dictionary is a set of
tables containing object definitions. If SQL created the dictionary, then it is
automatically maintained by the system. You can work with data dictionaries by
using the interactive data definition utility (IDDU), which is part of the OS/400
program. For more information on IDDU, see the IDDU Use book.
Catalogs
An SQL catalog consists of a set of tables and views which describe tables, views,
indexes, packages, procedures, files, and constraints. This information is contained
in a set of cross-reference tables in libraries QSYS and QSYS2. Library QSYS2
also contains a set of catalog views built over the QSYS catalog tables which
describe information about all the tables, views, indexes, packages, procedures,
files, and constraints on the system. In each SQL collection there is a set of views
built over the catalog tables which contains information about the tables, views,
indexes, packages, files, and constraints in the collection.
A catalog is automatically created when you create a collection. You cannot drop or
explicitly change the catalog.
For more information about SQL catalogs, see the DB2 UDB for AS/400 SQL
Reference book.
Data in a table can be distributed across AS/400 systems. For more information
about distributed tables, see the DB2 Multisystem for AS/400 book.
Columns
Aliases
An alias is an alternate name for a table or view. You can use an alias to refer to a
table or view in those cases where an existing table or view can be referred to. For
more information on aliases, see the DB2 UDB for AS/400 SQL Reference book.
Views
A view appears like a table to an application program; however, a view contains no
data. It is created over one or more tables. A view can contain all the columns of
given tables or some subset of them, and can contain all the rows of given tables or
some subset of them. The columns can be arranged differently in a view than they
are in the tables from which they are taken. A view in SQL is a special form of a
nonkeyed logical file.
The following figure shows a view created from the preceding example of an SQL
table. Notice that the view is created only over the PROJNO and PROJNAME
columns of the table and for rows MA2110 and MA2100.
Columns
PROJNO PROJNAME
The index is used by the system for faster data retrieval. Creating an index is
optional. You can create any number of indexes. You can create or drop an index at
any time. The index is automatically maintained by the system. However, because
the indexes are maintained by the system, a large number of indexes can adversely
affect the performance of applications that change the table.
Constraints
Constraints are rules enforced by the database manager. DB2 UDB for AS/400
supports the following constraints:
v Unique constraints
A unique constraint is the rule that the values of the key are valid only if they
are unique. Unique constraints can be created using the CREATE TABLE and
ALTER TABLE statements. 2
Unique constraints are enforced during the execution of INSERT and UPDATE
statements. A PRIMARY KEY constraint is a form of UNIQUE constraint. The
difference is that a PRIMARY KEY cannot contain any nullable columns.
v Referential constraints
A referential constraint is the rule that the values of the foreign key are valid
only if:
– They appear as values of a parent key, or
– Some component of the foreign key is null.
Referential constraints are enforced during the execution of INSERT, UPDATE,
and DELETE statements.
v Check constraints
A check constraint is a rule that limits the values allowed in a column or group
of columns. Check constraints can be added using the CREATE TABLE and
ALTER TABLE statements. Check constraints are enforced during the execution
of INSERT and UPDATE statements. To satisfy the constraint, each row of data
inserted or updated in the table must make the specified condition either TRUE
or unknown (due to a null value).
Triggers
A trigger is a set of actions that are executed automatically whenever a specified
event occurs to a specified base table. An event can be an insert, update, or delete
operation. The trigger can be run either before or after the event. For more
information on triggers, see Chapter 6. Data Integrity in this book or see the DB2
UDB for AS/400 Database Programming book.
2. Although CREATE INDEX can create a unique index that also guarantees uniqueness, such an index is not a constraint.
| User-defined functions
| A user-defined function is a program that can be invoked like any built-in function.
| DB2 UDB for AS/400 supports external functions, SQL functions, and sourced
| functions. External functions can be any AS/400 ILE program or service program.
| An SQL function is defined entirely in SQL and can contain SQL statements,
| including SQL control statements. A sourced function is built over any built-in or any
| existing user-defined function. For more information on user-defined functions, see
| “Chapter 9. Writing User-Defined Functions (UDFs)” on page 185.
Packages
An SQL package is an object that contains the control structure produced when the
SQL statements in an application program are bound to a remote relational
database management system (DBMS). The DBMS uses the control structure to
process SQL statements encountered while running the application program.
SQL packages are created when a relational database name (RDB parameter) is
specified on a Create SQL (CRTSQLxxx) command and a program object is
created. Packages can also be created using the CRTSQLPKG command. For
more information about packages and distributed relational database function, see
Chapter 28. Distributed Relational Database Function
SQL packages can also be created using the QSQPRCED API. For more
information on QSQPRCED, see the System API Reference book.
With DB2 UDB for AS/400 you may need to manage the following objects:
v The original source
v Optionally, the module object for ILE programs
v The program or service program
v The SQL package for distributed programs
With a nondistributed non-ILE DB2 UDB for AS/400 program, you must manage
only the original source and the resulting program. The following shows the objects
User Temporary
Source Precompile Source Compile
Program
File File
Member Member
Processed Access
SQL Plan
Statements
RV2W565-1
With a nondistributed ILE DB2 UDB for AS/400 program, you may need to manage
the original source, the modules, and the resulting program or service program. The
following shows the objects involved and steps that happen during the precompile
and compile processes for a nondistributed ILE DB2 UDB for AS/400 program when
OBJTYPE(*PGM) is specified on the precompile command:
User Temporary
Source Precompile Source Compile Module Bind Program
File File
Member Member
RV2W569-0
With a distributed non-ILE DB2 UDB for AS/400 program, you must manage the
original source, the resulting program, and the resulting package. The following
shows the objects and steps that occur during the precompile and compile
processes for a distributed non-ILE DB2 UDB for AS/400 program:
Create
User Temporary
Source Precompile Source Compile SQL
Program SQL
File File Package
Member Package
Member
Processed Access
SQL Plan Access
Statements Plan
RV2W566-2
With a distributed ILE DB2 UDB for AS/400 program, you must manage the original
source, module objects, the resulting program or service program, and the resulting
packages. An SQL package can be created for each distributed module in a
distributed ILE program or service program. The following shows the objects and
steps that occur during the precompile and compile processes for a distributed ILE
DB2 UDB for AS/400 program:
RV2W570-1
Note: The access plans associated with the DB2 UDB for AS/400 distributed
program object are not created until the program is run locally.
Program
A program is the object which you can run that is created as a result of the compile
process for non-ILE compiles or as a result of the bind process for ILE compiles.
An access plan is a set of internal structures and information that tells SQL how to
run an embedded SQL statement most effectively. It is created only when the
program has successfully created. Access plans are not created during program
creation for SQL statements if the statements:
v Refer to a table or view that cannot be found
v Refer to a table or view to which you are not authorized
The access plans for such statements are created when the program is run. If, at
that time, the table or view still cannot be found or you are still not authorized, a
negative SQLCODE is returned. Access plans are stored and maintained in the
program object for nondistributed SQL programs and in the SQL package for
distributed SQL programs.
When a distributed SQL program is created, the name of the SQL package and an
internal consistency token are saved in the program. These are used at run time to
find the SQL package and to verify that the SQL package is correct for this
program. Because the name of the SQL package is critical for running distributed
SQL programs, an SQL package cannot be:
v Moved
v Renamed
v Duplicated
v Restored to a different library
Module
A module is an Integrated Language Environment (ILE) object that is created by
compiling source code using the CRTxxxMOD command (or any of the CRTBNDxxx
commands where xxx is C, CBL, CPP, or RPG). You can run a module only if you
use the Create Program (CRTPGM) command to bind it into a program. You usually
bind several modules together, but you can bind a module by itself. Modules
contain information about the SQL statements; however, the SQL access plans are
not created until the modules are bound into either a program or service program.
Service Program
A service program is an Integrated Language Environment (ILE) object that
provides a means of packaging externally supported callable routines (functions or
procedures) into a separate object. Bound programs and other service programs
can access these routines by resolving their imports to the exports provided by a
service program. The connections to these services are made when the calling
programs are created. This improves call performance to these routines without
including the code in the calling program.
The syntax for each of the SQL statements used in this chapter is described in
detail in the DB2 UDB for AS/400 SQL Reference book. A description of how to use
SQL statements and clauses in more complex situations is provided in Chapter 3.
Basic Concepts and Techniques and Chapter 5. Advanced Coding Techniques.
| In this chapter, the examples use the interactive SQL interface to show the
| execution of SQL statements. Each SQL interface provides methods for using SQL
| statements to define tables, views, and other objects, methods for updating the
| objects, and methods for reading data from the objects. Some tasks described here
| can also be done using Operations Navigator. In those cases, the information about
| the task notes that it can be done using Operations Navigator.
and press Enter. When the Enter SQL Statements display appears, you are ready
to start typing SQL Statements. For more information on interactive SQL and the
STRSQL command, see Chapter 19. Using Interactive SQL.
If you are reusing an existing interactive SQL session, make sure that you set the
naming mode to SQL naming. You can specify this on the F13 (Services) panel,
option 1 (Change session attributes).
| Note: Running this statement causes several objects to be created and takes
| several seconds.
| After you have successfully created a collection, you can create tables, views, and
| indexes in it. Tables, views, and indexes can also be created in libraries instead of
| collections.
For an example of creating a table using interactive SQL, see “Example: Creating a
Table (INVENTORY_LIST)”.
| When creating a table, you need to understand the concepts of null value and
| default value. A null value indicates the absence of a column value for a row. It is
| not the same as a value of zero or all blanks. It means ″unknown″. It is not equal to
| any value, not even to other null values. If a column does not allow the null value, a
| value must be assigned to the column, either a default value or a user supplied
| value.
| On the Enter SQL Statements display, type CREATE TABLE and press F4 (Prompt).
| The following display is shown (with the input areas not yet filled in):
| Type the table name and collection name of the table you are creating,
| INVENTORY_LIST in SAMPLECOLL, for the Table and Collection prompts. Each
| column you want to define for the table is represented by an entry in the list on the
| lower part of the display. For each column, type the name of the column, the data
| type of the column, its length and scale, and the null attribute.
| Press F11 to see more attributes that can be specified for the columns. This is
| where a default value may be specified.
| Specify CREATE TABLE Statement
|
| Type information, press Enter.
|
| Table . . . . . . . . . INVENTORY_LIST______ Name
| Collection . . . . . . SAMPLECOLL__ Name, F4 for list
|
| Data: 1=BIT, 2=SBCS, 3=MIXED, 4=CCSID
|
| Column Data Allocate
CCSID CONSTRAINT Default
| ITEM NUMBER_______ _ __________ N __________________
| ITEM NAME_________ _ __________ N '***UNKNOWN***'___
| UNIT_COST_________ _ __________ N __________________
| QUANTITY_ON_HAND__ _ __________ N NULL______________
| LAST_ORDER_DATE___ _ __________ N __________________
| ORDER_QUANTITY____ _ __________ N 20________________
| __________________ _ __________ _ __________________
| Bottom
| Table CONSTRAINT . . . . . . . . . . . . . N Y=Yes, N=No
| Distributed Table . . . . . . . . . . . . N Y=Yes, N=No
|
| F3=Exit F4=Prompt F5=Refresh F6=Insert line F10=Copy line
| F11=Display more attributes F12=Cancel F14=Delete line F24=More keys
|
| Note: Another way of entering column definitions is to press F4 (Prompt) with your
| cursor on one of the column entries in the list. This will bring up a display
| that shows all of the attributes for defining a single column.
| When all the values have been entered, press Enter to create the table. The Enter
| SQL Statements display will be shown again with a message indicating that the
| table has been created.
To change the labels for our columns, type LABEL ON COLUMN on the Enter SQL
Statements display and press F4 (Prompt). The following display will appear:
Type in the name of the table and collection containing the columns for which you
want to add labels and press Enter. The following display will be shown, prompting
you for each of the columns in the table.
Specify LABEL ON Statement
Column Heading
Column ....+....1....+....2....+....3....+....4....+....5....
ITEM_NUMBER 'ITEM NUMBER'___________________________
ITEM_NAME 'ITEM NAME'_____________________________
UNIT_COST 'UNIT COST'_____________________________
QUANTITY_ON_HAND 'QUANTITY ON HAND'_________
LAST_ORDER_DATE 'LAST ORDER DATE'_________
ORDER_QUANTITY 'NUMBER ORDERED'__________________________
Bottom
F3=Exit F5=Refresh F6=Insert line F10=Copy line F12=Cancel
F14=Delete line F19=Display system column names F24=More keys
Type the column headings for each of the columns. Column headings are defined in
20 character sections. Each section will be displayed on a different line when
showing the output of a SELECT statement. The ruler across the top of the column
heading entry area can be used to easily space the headings correctly. When the
headings are typed, press Enter.
The following message indicates that the LABEL ON statement was successful.
LABEL ON for INVEN00001 in SAMPLECOLL completed.
The table name in the message is the system table name for this table, not the
name that was actually specified in the statement. DB2 UDB for AS/400 maintains
The LABEL ON statement can also be keyed in directly on the Enter SQL
statements display as follows:
LABEL ON SAMPLECOLL/INVENTORY_LIST
(ITEM_NUMBER IS 'ITEM NUMBER',
ITEM_NAME IS 'ITEM NAME',
UNIT_COST IS 'UNIT COST',
QUANTITY_ON_HAND IS 'QUANTITY ON HAND',
LAST_ORDER_DATE IS 'LAST ORDER DATE',
ORDER_QUANTITY IS 'NUMBER ORDERED')
| For an example of inserting data into a table using interactive SQL, see “Example:
| Inserting Information into a Table (INVENTORY_LIST)”.
Type the table name and collection name in the input fields as shown. Change the
Select columns to insert INTO prompt to Yes. Press Enter to see the display where
the columns you want to insert values into can be selected.
Bottom
F3=Exit F5=Refresh F12=Cancel F19=Display system column names
F20=Display entire name F21=Display statement
In this example, we only want to insert into four of the columns. We will let the other
| columns have their default value inserted. The sequence numbers on this display
| indicate the order that the columns and values will be listed in the INSERT
| statement. Press Enter to show the display where values for the selected columns
| can be typed.
| Specify INSERT Statement
|
| Type values to insert, press Enter.
|
| Column Value
| ITEM_NUMBER '153047'_____________________________________________
| ITEM_NAME 'Pencils, red'_______________________________________
| UNIT_COST 10.00________________________________________________
| QUANTITY_ON_HAND 25___________________________________________________
|
|
|
|
|
|
|
|
|
|
|
| Bottom
| F3=Exit F5=Refresh F6=Insert line F10=Copy line F11=Display type
| F12=Cancel F14=Delete line F15=Split line F24=More keys
|
| Note: To see the data type and length for each of the columns in the insert list,
| press F11 (Display type). This will show a different view of the insert values
| display, providing information about the column definition.
| Type the values to be inserted for all of the columns and press Enter. A row
| containing these values will be added to the table. The values for the columns that
| were not specified will have a default value inserted. For LAST_ORDER_DATE it
| will be the null value since no default was provided and the column allows the null
| value. For ORDER_QUANTITY it will be 20, the value specified as the default value
| on the CREATE TABLE statement.
| You can type the INSERT statement on the Enter SQL Statements display as:
| INSERT INTO SAMPLECOLL.INVENTORY_LIST
| (ITEM_NUMBER,
| ITEM_NAME,
| UNIT_COST,
| QUANTITY_ON_HAND)
| To add the next row to the table, press F9 (Retrieve) on the Enter SQL Statements
| display. This will copy the previous INSERT statement to the typing area. You can
| either type over the values from the previous INSERT statement or press F4
| (Prompt) to use the Interactive SQL displays to enter data.
| Continue using the INSERT statement to add the following rows to the table. Values
| not shown in the chart below should not be inserted so that the default will be used.
| In the INSERT statement column list, specify only the column names for which you
| want to insert a value. For example, to insert the third row, you would specify only
| ITEM_NUMBER and UNIT_COST for the column names and only the two values
| for these columns in the VALUES list.
| The sample collection now contains two tables with several rows of data in each.
In addition to the three main clauses, there are several other clauses described in
“Using Basic SQL Statements and Clauses” on page 31, and in the DB2 UDB for
AS/400 SQL Reference book, which affect the final form of returned data.
To see the values we inserted into the INVENTORY_LIST table, type SELECT and
press F4 (prompt). The following display will be shown:
Specify SELECT Statement
Bottom
Type choices, press Enter.
Type the table name in the FROM tables field on the display. To select all columns
from the table, type * for the SELECT columns field on the display. Press Enter and
the statement will run to select all of the data for all of the columns in the table. The
following output will be shown:
Display Data
Data width . . . . . . : 71
Position to line . . . . . Shift to column . . . . . .
....+....1....+....2....+....3....+....4....+....5....+....6....+....7.
ITEM ITEM UNIT QUANTITY LAST NUMBER
NUMBER NAME COST ON ORDER ORDERED
HAND DATE
153047 Pencils, red 10.00 25 - 20
229740 Lined tablets 1.50 120 - 20
544931 ***UNKNOWN*** 5.00 - - 20
303476 Paper clips 2.00 100 - 20
559343 Envelopes, legal 3.00 500 - 20
291124 Envelopes, standard .00 - - 20
775298 Chairs, secretary 225.00 6 - 20
073956 Pens, black 20.00 25 - 20
******** End of data ********
The column headings that were defined using the LABEL ON statement are shown.
The ITEM_NAME for the third entry has the default value that was specified in the
CREATE TABLE statement. The QUANTITY_ON_HAND column has a null value for
This statement could be entered on the Enter SQL Statements display as:
SELECT *
FROM SAMPLECOLL.INVENTORY_LIST
To limit the number of columns returned by the SELECT statement, the columns
you want to see must be specified. To restrict the number of output rows returned,
the WHERE clause is used. To see only the items that cost more than 10 dollars,
and only have the values for the columns ITEM_NUMBER, UNIT_COST, and
ITEM_NAME returned, type SELECT and press F4 (Prompt). The Specify SELECT
Statement display will be shown.
Specify SELECT Statement
Bottom
Type choices, press Enter.
Although only one line is initially shown for each prompt on the Specify SELECT
Statement display, F6 (Insert line) can be used to add more lines to any of the input
areas in the top part of the display. This could be used if more columns were to be
entered in the SELECT columns list, or a longer, more complex WHERE condition
were needed.
Fill in the display as shown above. When Enter is pressed, the SELECT statement
is run. The following output will be seen:
Display Data
Data width . . . . . . : 41
Position to line . . . . . Shift to column . . . . . .
....+....1....+....2....+....3....+....4.
ITEM UNIT ITEM
NUMBER COST NAME
775298 225.00 Chairs, secretary
073956 20.00 Pens, black
******** End of data ********
The only rows returned are those whose data values compare with the condition
specified in the WHERE clause. Furthermore, the only data values returned are
This statement could have been entered on the Enter SQL Statements display as:
SELECT ITEM_NUMBER, UNIT_COST, ITEM_NAME
FROM SAMPLECOLL.INVENTORY_LIST
WHERE UNIT_COST > 10.00
Suppose you want to see a list of all the suppliers and the item numbers and item
names for their supplied items. The item name is not in the SUPPLIERS table. It is
in the INVENTORY_LIST table. Using the common column, ITEM_NUMBER, we
can see all three of the columns as if they were from a single table.
Whenever the same column name exists in two or more tables being joined, the
column name must be qualified by the table name to specify which column is really
being referenced. In this SELECT statement, the column name ITEM_NUMBER is
defined in both tables so the column name needs to be qualified by the table name.
If the columns had different names, there would be no confusion so qualification
would not be needed.
To perform this join, the following SELECT statement can be used. Enter it by
typing it directly on the Enter SQL Statements display or by prompting. If using
prompting, both table names need to be typed on the FROM tables input line.
SELECT SUPPLIER_NUMBER, SAMPLECOLL.INVENTORY_LIST.ITEM_NUMBER, ITEM_NAME
FROM SAMPLECOLL.SUPPLIERS, SAMPLECOLL.INVENTORY_LIST
WHERE SAMPLECOLL.SUPPLIERS.ITEM_NUMBER
= SAMPLECOLL.INVENTORY_LIST.ITEM_NUMBER
Another way to enter the same statement is to use a correlation name. A correlation
name provides another name for a table name to use in a statement. A correlation
name must be used when the table names are the same. It can be specified
following each table name in the FROM list. The previous statement could be
rewritten as:
SELECT SUPPLIER_NUMBER, Y.ITEM_NUMBER, ITEM_NAME
FROM SAMPLECOLL.SUPPLIERS X, SAMPLECOLL.INVENTORY_LIST Y
WHERE X.ITEM_NUMBER = Y.ITEM_NUMBER
For more information on correlation names, see the DB2 UDB for AS/400 SQL
Reference book.
The data values in the result table represent a composite of the data values
contained in the two tables INVENTORY_LIST and SUPPLIERS. This result table
contains the supplier number from the SUPPLIER table and the item number and
item name from the INVENTORY_LIST table. Any item numbers that do not appear
in the SUPPLIER table are not shown in this result table. The results are not
guaranteed to be in any order unless the ORDER BY clause is specified for the
SELECT statement. Since we did not change any column headings for the
SUPPLIER table, the SUPPLIER_NUMBER column name is used as the column
heading.
| If you want to limit the number of rows being changed during a single statement
| execution, use the WHERE clause with the UPDATE statement. For more
| information see, “The UPDATE Statement” on page 33. If you do not specify the
| WHERE clause, all of the rows in the specified table are changed. However, if you
| use the WHERE clause, the system changes only the rows satisfying the conditions
| that you specify. For more information, see “The WHERE Clause” on page 38.
| After typing the table name and collection name, press Enter. The display will be
| shown again with the list of columns in the table.
| Specify UPDATE Statement
|
| Type choices, press Enter.
|
| Table . . . . . . . . INVENTORY_LIST______ Name, F4 for list
| Collection . . . . . SAMPLECOLL__ Name, F4 for list
|
| Correlation . . . . . ____________________ Name
|
|
| Type information, press Enter.
|
| Column Value
| ITEM_NUMBER _____________________________________________________
| ITEM_NAME _____________________________________________________
| UNIT_COST _____________________________________________________
| QUANTITY_ON_HAND _____________________________________________________
| LAST_ORDER_DATE CURRENT DATE_________________________________________
| ORDER_QUANTITY 50___________________________________________________
|
| Bottom
| F3=Exit F4=Prompt F5=Refresh F6=Insert line F10=Copy line
| F11=Display type F12=Cancel F14=Delete line F24=More keys
|
| Specifying CURRENT DATE for a value will change the date in all the selected
| rows to be today’s date.
| After typing the values to be updated for the table, press Enter to see the display
| on which the WHERE condition can be specified. If a WHERE condition is not
| specified, all the rows in the table will be updated using the values from the
| previous display.
| After typing the condition, press Enter to perform the update on the table. A
| message will indicate that the function is complete.
| This statement could have been typed on the Enter SQL Statements display as:
| UPDATE SAMPLECOLL.INVENTORY_LIST
| SET LAST_ORDER_DATE = CURRENT DATE,
| ORDER_QUANTITY = 50
| WHERE ITEM_NUMBER = '303476'
| Running a SELECT statement to get all the rows from the table (SELECT * FROM
SAMPLECOLL.INVENTORY_LIST), returns the following result:
Display Data
Data width . . . . . . : 71
Position to line . . . . . Shift to column . . . . . .
....+....1....+....2....+....3....+....4....+....5....+....6....+....7.
ITEM ITEM UNIT QUANTITY LAST NUMBER
NUMBER NAME COST ON ORDER ORDERED
HAND DATE
153047 Pencils, red 10.00 25 - 20
229740 Lined tablets 1.50 120 - 20
544931 ***UNKNOWN*** 5.00 - - 20
303476 Paper clips 2.00 100 05/30/94 50
559343 Envelopes, legal 3.00 500 - 20
291124 Envelopes, standard .00 - - 20
775298 Chairs, secretary 225.00 6 - 20
073956 Pens, black 20.00 25 - 20
******** End of data ********
Bottom
F3=Exit F12=Cancel F19=Left F20=Right F21=Split
Only the entry for Paper clips was changed. The LAST_ORDER_DATE was
changed to be the current date. This date is always the date the update is run. The
NUMBER_ORDERED shows its updated value.
To check a column for the null value, the IS NULL comparison is used. Running
another SELECT statement after the delete has completed will return the following
result table:
Display Data
Data width . . . . . . : 71
Position to line . . . . . Shift to column . . . . . .
....+....1....+....2....+....3....+....4....+....5....+....6....+....7.
ITEM ITEM UNIT QUANTITY LAST NUMBER
NUMBER NAME COST ON ORDER ORDERED
HAND DATE
153047 Pencils, red 10.00 25 - 20
229740 Lined tablets 1.50 120 - 20
303476 Paper clips 2.00 100 05/30/94 50
559343 Envelopes, legal 3.00 500 - 20
775298 Chairs, secretary 225.00 6 - 20
073956 Pens, black 20.00 25 - 20
******** End of data ********
Bottom
F3=Exit F12=Cancel F19=Left F20=Right F21=Split
You can create a view using Operations Navigator. Or you can use the SQL
CREATE VIEW statement. Using the CREATE VIEW statement, defining a view on
a table is like creating a new table containing just the columns and rows you want.
When your application uses a view, it cannot access rows or columns of the table
that are not included in the view. However, rows that do not match the selection
criteria may still be inserted through a view if the SQL WITH CHECK OPTION is not
used. See Chapter 6. Data Integrity for more information on using WITH CHECK
OPTION.
| In order to create a view you must have the proper authority to the tables or
physical files on which the view is based. See the CREATE VIEW statement in the
SQL Reference for a list of authorities needed.
If you do not specify column names in the view definition, the column names will be
the same as those for the table on which the view is based.
You can make changes to a table through a view even if the view has a different
number of columns or rows than the table. For INSERT, columns in the table that
are not in the view must have a default value.
You can use the view as though it were a table, even though the view is totally
dependent on one or more tables for data. The view has no data of its own and
therefore requires no storage for the data. Because a view is derived from a table
that exists in storage, when you update the view data, you are really updating data
in the table. Therefore, views are automatically kept up-to-date as the tables they
depend on are updated.
In the example above, the columns in the view have the same name as the
columns in the table because no column list follows the view name. The collection
that the view is created into does not need to be the same collection as the table it
is built over. Any collection or library could be used. The following display is the
result of running the SQL statement:
SELECT * FROM SAMPLECOLL.RECENT_ORDERS
The only row selected by the view is the row that we updated to have the current
date. All other dates in our table still have the null value so they are not returned.
Example: Creating a view combining data from more than one table
You can create a view that combines data from two or more tables by naming more
than one table in the FROM clause. In the following example, the
INVENTORY_LIST table contains a column of item numbers called
ITEM_NUMBER, and a column with the cost of the item, UNIT_COST. These are
joined with the ITEM_NUMBER column and the SUPPLIER_COST column of the
SUPPLIERS table. A WHERE clause is used to limit the number of rows returned.
The view will only contain those item numbers for suppliers that can supply an item
at lower cost than the current unit cost.
Display Data
Data width . . . . . . : 51
Position to line . . . . . Shift to column . . . . . .
....+....1....+....2....+....3....+....4....+....5.
SUPPLIER_NUMBER ITEM UNIT SUPPLIER_COST
NUMBER COST
9988 153047 10.00 8.00
2424 153047 10.00 9.00
1234 229740 1.50 1.00
3366 303476 2.00 1.50
3366 073956 20.00 17.00
******** End of data ********
Bottom
F3=Exit F12=Cancel F19=Left F20=Right F21=Split
The rows that can be seen through this view are only those rows that have a
supplier cost that is less than the unit cost.
You can write SQL statements on one line or on many lines. The rules for the
continuation of lines are the same as those of the host language (the language the
program is written in).
Notes:
1. The SQL statements described in this section can be run on SQL tables and
views, and database physical and logical files. The tables, views, and files can
be either in an SQL collection or in a library.
2. Character strings specified in an SQL statement (such as those used with
WHERE or VALUES clauses) are case sensitive; that is, uppercase characters
must be entered in uppercase and lowercase characters must be entered in
lowercase.
WHERE ADMRDEPT='a00' (does not return a result)
Note: Because views are built on tables and actually contain no data, working with
views can be confusing. See “Creating and Using Views” on page 95 for
more information on inserting data by using a view.
The INTO clause names the columns for which you specify values. The VALUES
clause specifies a value for each column named in the INTO clause.
You must provide a value in the VALUES clause for each column named in an
INSERT statement’s column list. The column name list can be omitted if all columns
in the table have a value provided in the VALUES clause. If a column has a default
value, the keyword DEFAULT may be used as a value on the VALUES clause.
It is a good idea to name all columns into which you are inserting values because:
v Your INSERT statement is more descriptive.
v You can verify that you are giving the values in the proper order based on the
column names.
v You have better data independence. The order in which the columns are defined
in the table does not affect your INSERT statement.
If the column is defined to allow null values or to have a default, you do not need to
name it in the column name list or specify a value for it. The default value is used.
If the column is defined to have a default value, the default value is placed in the
column. If DEFAULT was specified for the column definition without an explicit
default value, SQL places the default value for that data type in the column. If the
column does not have a default value defined for it, but is defined to allow the null
value (NOT NULL was not specified in the column definition), SQL places the null
value in the column.
v For numeric columns, the default value is 0.
v For fixed length character or graphic columns, the default is blanks.
| v For varying length character or graphic columns or LOB columns, the default is a
| zero length string.
v For date, time, and timestamp columns, the default value is the current date,
time, or timestamp. When inserting a block of records, the default date/time value
is extracted from the system when the block is written. This means that the
column will be assigned the same default value for each row in the block.
| v For DataLink columns, the default value corresponds to DLVALUE(’’,’URL’,’’).
| v For distinct-type columns, the default value is the default value of the
| corresponding source type.
When your program attempts to insert a row that duplicates another row already in
the table, an error might occur. Multiple null values may or may not be considered
duplicate values, depending on the option used when the index was created.
v If the table has a primary key, unique key, or unique index, the row is not
inserted. Instead, SQL returns an SQLCODE of −803.
v If the table does not have a primary key, unique key, or unique index, the row
can be inserted without error.
If SQL finds an error while running the INSERT statement, it stops inserting data. If
you specify COMMIT(*ALL), COMMIT(*CS), COMMIT(*CHG), or COMMIT(*RR), no
rows are inserted. Rows already inserted by this statement, in the case of INSERT
A table created by SQL is created with the Reuse Deleted Records parameter of
*YES. This allows the database manager to reuse any rows in the table that were
marked as deleted. The CHGPF command can be used to change the attribute to
*NO. This causes INSERT to always add rows to the end of the table.
The order in which rows are inserted does not guarantee the order in which they
will be retrieved.
If the row is inserted without error, the SQLERRD(3) field of the SQLCA has a value
of 1.
Note: For blocked INSERT or for INSERT with select-statement, more than one
row can be inserted. The number of rows inserted is reflected in
SQLERRD(3).
For example, suppose an employee was relocated. To update several items of the
employee’s data in the CORPDATA.EMPLOYEE table to reflect the move, you can
specify:
UPDATE CORPDATA.EMPLOYEE
SET JOB = :PGM-CODE,
PHONENO = :PGM-PHONE
WHERE EMPNO = :PGM-SERIAL
Use the SET clause to specify a new value for each column you want to update.
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 constant. Replace the column’s current value with the value provided in the
SET clause.
A null value. Replace the column’s current value with the null value, using the
keyword NULL. The column must be defined as capable of containing a null
value when the table was created, or an error occurs.
A host variable. Replace the column’s current value with the contents of a host
variable.
A special register. Replace the column’s current value with a special register
value; for example, USER.
An expression. Replace the column’s current value with the value that results
from an expression. The expression can contain any of the values in this list.
You can omit the WHERE clause. If you do, SQL updates each row in the table or
view with the values you supply.
If the database manager finds an error while running your UPDATE statement, it
stops updating and returns a negative SQLCODE. If you specify COMMIT(*ALL),
COMMIT(*CS), COMMIT(*CHG), or COMMIT(*RR), no rows in the table are
changed (rows already changed by this statement, if any, are restored to their
previous values). If COMMIT(*NONE) is specified, any rows already changed are
not restored to previous values.
If the database manager cannot find any rows that satisfy the search condition, an
SQLCODE of +100 is returned.
Note: UPDATE with a WHERE clause may have updated more than one row. The
number of rows updated is reflected in SQLERRD(3).
For example, suppose department D11 was moved to another place. You want to
delete each row in the CORPDATA.EMPLOYEE table with a WORKDEPT value of
D11 as follows:
DELETE FROM CORPDATA.EMPLOYEE
WHERE WORKDEPT = 'D11'
The WHERE clause tells SQL which rows you want to delete from the table. SQL
deletes all the rows that satisfy the search condition from the base table. You can
If SQL finds an error while running your DELETE statement, it stops deleting data
and returns a negative SQLCODE. If you specify COMMIT(*ALL), COMMIT(*CS),
COMMIT(*CHG), or COMMIT(*RR), no rows in the table are deleted (rows already
deleted by this statement, if any, are restored to their previous values). If
COMMIT(*NONE) is specified, any rows already deleted are not restored to their
previous values.
If SQL cannot find any rows that satisfy the search condition, an SQLCODE of +100
is returned.
Note: DELETE with WHERE clause may have deleted more than one row. The
number of rows deleted is reflected in SQLERRD(3).
The format and syntax shown here are very basic. SELECT INTO statements can
be more varied than the examples presented in this chapter. A SELECT INTO
statement can include the following:
1. The name of each column you want
2. The name of each host variable used to contain retrieved data
3. The name of the table or view that contains the data
4. A search condition to uniquely identify the row that contains the information you
want
5. The name of each column used to group your data
6. A search condition that uniquely identifies a group that contains the information
you want
7. The order of the results so a specific row among duplicates can be returned.
The SELECT, INTO, and FROM clauses must be specified. The other clauses are
optional.
The result table for a SELECT INTO should contain just one row. For example,
each row in the CORPDATA.EMPLOYEE table has a unique EMPNO (employee
number) column. The result of a SELECT INTO statement for this table if the
WHERE clause contains an equal comparison on the EMPNO column, would be
exactly one row (or no rows). Finding more than one row is an error, but one row is
still returned. You can control which row will be returned in this error condition by
specifying the ORDER BY clause. If you use the ORDER BY clause, the first row in
the result table is returned.
If you want more than one row to be the result of a select-statement, use a
DECLARE CURSOR statement to select the rows, followed by a FETCH statement
to move the column values into host variables one or many rows at a time. Using
cursors is described in “Chapter 4. Using a Cursor” on page 55.
The FROM clause names the table (or view) that contains the data you are
interested in.
PGM-DEPTNAME PGM-MGRNO
INFORMATION CENTER 000030
If SQL is unable to find a row that satisfies the search condition, an SQLCODE of
+100 is returned.
You can retrieve data from a view in exactly the same way you retrieve data from a
table. However, there are several restrictions when you attempt to update, insert, or
delete data in a view. These restrictions are described in “Creating and Using
Views” on page 95.
If SQL finds a data mapping error while running a statement, one of two things
occurs:
v If the error occurs on an expression in the SELECT list and an indicator variable
is provided for the expression in error:
– SQL returns a −2 for the indicator variable corresponding to the expression in
error.
– SQL returns all valid data for that row.
– SQL returns a positive SQLCODE.
v If an indicator variable is not provided, SQL returns the corresponding negative
SQLCODE in the SQLCA.
For data mapping errors, the SQLCA reports only the last error detected. The
indicator variable corresponding to each result column having an error is set to −2.
If the full-select contains DISTINCT in the select list and a column in the select list
contains numeric data that is not valid, the data is considered equal to a null value
if the query is completed as a sort. If an existing index is used, the data is not
considered equal to a null.
The impact of data mapping errors on the ORDER BY clause depends on the
situation:
v If the data mapping error occurs while data is being assigned to a host variable
in a SELECT INTO or FETCH statement, and that same expression is used in
the ORDER BY clause, the result record is ordered based on the value of the
expression. It is not ordered as if it were a null (higher than all other values). This
is because the expression was evaluated before the assignment to the host
variable is attempted.
v If the data mapping error occurs while an expression in the select-list is being
evaluated and the same expression is used in the ORDER BY clause, the result
column is normally ordered as if it were a null value (higher than all other
values). If the ORDER BY clause is implemented by using a sort, the result
column is ordered as if it were a null value. If the ORDER BY clause is
You can specify that only one column be retrieved, or as many as 8000 columns.
The value of each column you name is retrieved in the order specified in the
SELECT clause.
If you want to retrieve all columns (in the same order as they appear in the row),
use an asterisk (*) instead of naming the columns:
SELECT *
.
.
.
When using the select-statement in an application program, list the column names
to give your program more data independence. There are two reasons for this:
1. When you look at the source code statement, you can easily see the one-to-one
correspondence between the column names in the SELECT clause and the host
variables named in the INTO clause.
2. If a column is added to a table or view you access and you use “SELECT * ...,”
and you create the program again from source, the INTO clause does not have
a matching host variable named for the new column. The extra column causes
you to get a warning (not an error) in the SQLCA (SQLWARN4 will contain a
“W”).
If the search condition contains character or UCS-2 graphic column predicates, the
sort sequence that is in effect when the query is run is applied to those predicates.
See “Using Sort Sequence in SQL” on page 50 for more information on sort
sequence and selection.
However, you cannot compare character strings to numbers. You also cannot
perform arithmetic operations on character data (even though EMPNO is a
character string that appears to be a number). You can add and subtract
date/time values.
v An expression identifies two values that are added (+), subtracted (−), multiplied
(*), divided (/), have exponentiation (**), or concatenated (CONCAT or ||) to result
in a value. The operands of an expression can be:
A constant (that is, a literal value)
A column
A host variable
A value returned from a function
A special register
Another expression
For example:
... WHERE INTEGER(PRENDATE - PRSTDATE) > 100
Operators on the same precedence level are applied from left to right.
v A constant specifies a literal value for the expression. For example:
... WHERE 40000 < SALARY
A search condition need not be limited to two column names or constants separated
by arithmetic or comparison operators. You can develop a complex search condition
that specifies several predicates separated by AND and OR. No matter how
complex the search condition, it supplies a TRUE or FALSE value when evaluated
against a row. There is also an unknown truth value, which is effectively false. That
is, if the value of a row is null, this null value is not returned as a result of a search
because it is not less than, equal to, or greater than the value specified in the
search condition. More complex search conditions and predicates are described in
“Performing Complex Search Conditions” on page 72.
To fully understand the WHERE clause, you need to know how SQL evaluates
search conditions and predicates, and compares the values of expressions. This
topic is discussed in the DB2 UDB for AS/400 SQL Reference book.
Comparison Operators
SQL supports the following comparison operators:
= Equal to
<> or ¬= Not equal to
< Less than
> Greater than
<= or ¬> Less than or equal to (or not greater than)
> = or ¬< Greater than or equal to (or not less than)
| The GROUP BY clause allows you to find the characteristics of groups of rows
| rather than individual rows. When you specify a GROUP BY clause, SQL divides
| the selected rows into groups such that the rows of each group have matching
| values in one or more columns or expressions. Next, SQL processes each group to
| produce a single-row result for the group. You can specify one or more columns or
For example, the CORPDATA.EMPLOYEE table has several sets of rows, and each
set consists of rows describing members of a specific department. To find the
average salary of people in each department, you could issue:
RV2W551-1
| When you use GROUP BY, you list the columns or expressions you want SQL to
| use to group the rows. For example, suppose you want a list of the number of
| people working on each major project described in the CORPDATA.PROJECT
| table. You could issue:
RV2W552-3
| You can also specify that you want the rows grouped by more than one column or
| expression. For example, you could issue a select-statement to find the average
| salary for men and women in each department, using the CORPDATA.EMPLOYEE
| table. To do this, you could issue:
RV2W553-1
Because you did not include a WHERE clause in this example, SQL examines and
process all rows in the CORPDATA.EMPLOYEE table. The rows are grouped first
by department number and next (within each department) by sex before SQL
derives the average SALARY value for each group.
The HAVING clause follows the GROUP BY clause and can contain the same kind
of search condition you can specify in a WHERE clause. In addition, you can
specify column functions in a HAVING clause. For example, suppose you wanted to
retrieve the average salary of women in each department. To do this, you would
use the AVG column function and group the resulting rows by WORKDEPT and
specify a WHERE clause of SEX = 'F'.
To specify that you want this data only when all the female employees in the
selected department have an education level equal to or greater than 16 (a college
graduate), use the HAVING clause. The HAVING clause tests a property of the
group. In this case, the test is on MIN(EDLEVEL), which is a group property:
RV2W554-3
You can use multiple predicates in a HAVING clause by connecting them with AND
and OR, and you can use NOT for any predicate of a search condition.
Note: If you intend to update a column or delete a row, you cannot include a
GROUP BY or HAVING clause in the SELECT statement within a DECLARE
CURSOR statement. (The DECLARE CURSOR statement is described in
“Chapter 4. Using a Cursor” on page 55.)
Predicates with arguments that are not column functions can be coded in either
WHERE or HAVING clauses. It is usually more efficient to code the selection criteria
in the WHERE clause. It is processed during the initial phase of the query
processing. The HAVING selection is performed in post processing of the result
table.
For example, to retrieve the names and department numbers of female employees
listed in the alphanumeric order of their department numbers, you could use this
select-statement:
RV2W555-3
Notes:
1. All columns named in the ORDER BY clause must also be named in the
SELECT list.
2. Null values are ordered as the highest value.
| To order by a column function, or something other than a column name, you can
| specify an AS clause in the select-list. To order by an expression, you can either
| specify the exact same expression in the ORDER BY clause, or you can specify an
| AS clause in the select-list.
The AS clause names the result column. This name can be specified in the ORDER
BY clause. To order by a name specified in the AS clause:
v The name must be unique in the select-list.
v The name must not be qualified.
For example, to retrieve the full name of employees listed in alphabetic order, you
could use this select-statement:
SELECT LASTNAME CONCAT FIRSTNAME AS FULLNAME ...
ORDER BY FULLNAME
| Instead of naming the columns to order the results, you can use a number. For
example, ORDER BY 3 specifies that you want the results ordered by the third
column of the results table, as specified by the select-statement. Use a number to
order the rows of the results table when the sequencing value is not a named
column.
You can also specify whether you want SQL to collate the rows in ascending (ASC)
or descending (DESC) sequence. An ascending collating sequence is the default. In
the above select-statement, SQL first returns the row with the lowest department
As with GROUP BY, you can specify a secondary ordering sequence (or several
levels of ordering sequences) as well as a primary one. In the example above, you
might want the rows ordered first by department number, and within each
department, ordered by employee name. To do this, specify:
... ORDER BY WORKDEPT, LASTNAME
If character columns or UCS-2 graphic columns are used in the ORDER BY clause,
ordering for these columns is based on the sort sequence in effect when the query
is run. See “Using Sort Sequence in SQL” on page 50 for more information on sort
sequence and its affect on ordering.
To get the rows that do not have a null value for the manager number, you could
change the WHERE clause like this:
WHERE MGRNO IS NOT NULL
For more information on the use of null values, see the DB2 UDB for AS/400 SQL
Reference book.
If a single statement contains more than one reference to any of CURRENT DATE,
CURRENT TIME, or CURRENT TIMESTAMP special registers, or the CURDATE,
CURTIME, or NOW scalar functions, all values are based on a single clock reading.
For remotely run SQL statements, the special registers and their contents are
shown in the following table:
When a query over a distributed table references a special register, the contents of
the special register on the system that requests the query are used. For more
information on distributed tables, see DB2 Multisystem for AS/400 book.
Date/Time Arithmetic
Addition and subtraction are the only arithmetic operators applicable to date, time,
and timestamp values. You can increment and decrement a date, time, or
timestamp by a duration; or subtract a date from a date, a time from a time, or a
timestamp from a timestamp. For a detailed description of date and time arithmetic,
see Chapter 2 of the DB2 UDB for AS/400 SQL Reference book.
| A table alias defines a name for the file, including the specific member name. You
| can use this alias name in an SQL statement in the same way that you would use a
| table name. Unlike overrides, alias names are objects that exist until they are
| dropped.
For example, if there is a multiple member file MYLIB.MYFILE with members MBR1
and MBR2, an alias can be created for the second member so that SQL can easily
refer to it.
CREATE ALIAS MYLIB.MYMBR2_ALIAS FOR MYLIB.MYFILE (MBR2)
Alias names can also be specified on DDL statements. Assume that alias
MYLIB.MYALIAS exists and is an alias for table MYLIB.MYTABLE. The following
DROP statement will drop table MYLIB.MYTABLE.
DROP TABLE MYLIB.MYALIAS
If you really want to drop the alias name instead, specify the ALIAS keyword on the
drop statement:
DROP ALIAS MYLIB.MYALIAS
Using LABEL ON
Sometimes the table name, column name, view name, alias name, or SQL package
name does not clearly define data that is shown on an interactive display of the
table. By using the LABEL ON statement, you can create a more descriptive label
for the table name, column name, view name, alias name, or SQL package name.
These labels can be seen in the SQL catalog in the LABEL column.
LABEL ON
COLUMN CORPDATA.DEPARTMENT.ADMRDEPT IS 'Reports to Dept.'
After these statements are run, the table named DEPARTMENT displays the text
description as Department Structure Table and the column named ADMRDEPT
displays the heading Reports to Dept. The label for tables, views, SQL packages,
This LABEL ON statement provides 3 levels of column headings for the SALARY
column.
*...+....1....+....2....+....3....+....4....+....5....+....6..*
LABEL ON COLUMN CORPDATA.EMPLOYEE.SALARY IS
'Yearly Salary (in dollars)'
This LABEL ON statement provides column text for the EDLEVEL column.
*...+....1....+....2....+....3....+....4....+....5....+....6..*
LABEL ON COLUMN CORPDATA.EMPLOYEE.EDLEVEL TEXT IS
'Number of years of formal education'
For more information about the LABEL ON statement, see the DB2 UDB for AS/400
SQL Reference book.
Using COMMENT ON
| After you create an SQL object such as a table, view, index, package, procedure,
| parameter, user-defined type, or function, you can supply information about it for
| future referral, such as the purpose of the object, who uses it, and anything unusual
| or special about it. You can also include similar information about each column of a
| table or view. Your comment must not be more than 2000 bytes.
A comment is especially useful if your names do not clearly indicate the contents of
the columns or objects. In that case, use a comment to describe the specific
contents of the column or objects.
The sort sequence is used for all character and UCS-2 graphic comparisons
performed in SQL statements. There are sort sequence tables for both single byte
and double byte character data. Each single byte sort sequence table has an
associated double byte sort sequence table, and vice versa. Conversion between
the two tables is performed when necessary to implement a query. In addition, the
CREATE INDEX statement has the sort sequence (in effect at the time the
statement was run) applied to the character columns referred to in the index.
In the following examples, the results are shown for each statement using:
v *HEX sort sequence
v Shared-weight sort sequence using the language identifier ENU
v Unique-weight sort sequence using the language identifier ENU
ORDER BY
The following SQL statement causes the result table to be sorted using the values
in the JOB column:
SELECT * FROM STAFF ORDER BY JOB
Table 3 shows the result table using a *HEX sort sequence. The rows are sorted
based on the EBCDIC value in the JOB column. In this case, all lowercase letters
sort before the uppercase letters.
Table 3. ″SELECT * FROM STAFF ORDER BY JOB″ Using the *HEX Sort Sequence.
ID NAME DEPT JOB YEARS SALARY COMM
100 Plotz 42 mgr 6 18352.80 0
90 Koonitz 42 sales 6 18001.75 1386.70
80 James 20 Clerk 0 13504.60 128.20
10 Sanders 20 Mgr 7 18357.50 0
50 Hanes 15 Mgr 10 20659.80 0
30 Merenghi 38 MGR 5 17506.75 0
20 Pernal 20 Sales 8 18171.25 612.45
40 OBrien 38 Sales 6 18006.00 846.55
70 Rothman 15 Sales 7 16502.83 1152.00
60 Quigley 38 SALES 0 16808.30 650.25
Table 4 shows how sorting is done for a unique-weight sort sequence. After the sort
sequence is applied to the values in the JOB column, the rows are sorted. Notice
that after the sort, lowercase letters are before the same uppercase letters, and the
values 'mgr', 'Mgr', and 'MGR' are adjacent to each other.
Table 4. ″SELECT * FROM STAFF ORDER BY JOB″ Using the Unique-Weight Sort
Sequence for the ENU Language Identifier.
ID NAME DEPT JOB YEARS SALARY COMM
80 James 20 Clerk 0 13504.60 128.20
100 Plotz 42 mgr 6 18352.80 0
10 Sanders 20 Mgr 7 18357.50 0
50 Hanes 15 Mgr 10 20659.80 0
30 Merenghi 38 MGR 5 17506.75 0
90 Koonitz 42 sales 6 18001.75 1386.70
20 Pernal 20 Sales 8 18171.25 612.45
40 OBrien 38 Sales 6 18006.00 846.55
70 Rothman 15 Sales 7 16502.83 1152.00
60 Quigley 38 SALES 0 16808.30 650.25
Table 5 on page 52 shows how sorting is done for a shared-weight sort sequence.
After the sort sequence is applied to the values in the JOB column, the rows are
sorted. For the
Chapter 3. Basic Concepts and Techniques 51
sort comparison, each lowercase letter is treated the same as the corresponding
uppercase letter. In Table 5, notice that all the values 'MGR', 'mgr' and 'Mgr' are
mixed together.
Table 5. ″SELECT * FROM STAFF ORDER BY JOB″ Using the Shared-Weight Sort
Sequence for the ENU Language Identifier.
ID NAME DEPT JOB YEARS SALARY COMM
80 James 20 Clerk 0 13504.60 128.20
10 Sanders 20 Mgr 7 18357.50 0
30 Merenghi 38 MGR 5 17506.75 0
50 Hanes 15 Mgr 10 20659.80 0
100 Plotz 42 mgr 6 18352.80 0
20 Pernal 20 Sales 8 18171.25 612.45
40 OBrien 38 Sales 6 18006.00 846.55
60 Quigley 38 SALES 0 16808.30 650.25
70 Rothman 15 Sales 7 16502.83 1152.00
90 Koonitz 42 sales 6 18001.75 1386.70
Record selection
The following SQL statement selects records with the value 'MGR' in the JOB
column:
SELECT * FROM STAFF WHERE JOB='MGR'
Table 6 shows how record selection is done with a *HEX sort sequence. In Table 6,
the rows that match the record selection criteria for the column 'JOB' are selected
exactly as specified in the select statement. Only the uppercase 'MGR' is selected.
Table 6. ″SELECT * FROM STAFF WHERE JOB=’MGR’ Using the *HEX Sort Sequence.″
ID NAME DEPT JOB YEARS SALARY COMM
30 Merenghi 38 MGR 5 17506.75 0
Table 7 shows how record selection is done with a unique-weight sort sequence. In
Table 7, the lowercase and uppercase letters are treated as unique. The lowercase
'mgr' is not treated the same as uppercase 'MGR'. Therefore, the lower case 'mgr'
is not selected.
Table 7. ″SELECT * FROM STAFF WHERE JOB = ’MGR’ ″ Using Unique-Weight Sort
Sequence for the ENU Language Identifier.
ID NAME DEPT JOB YEARS SALARY COMM
30 Merenghi 38 MGR 5 17506.75 0
Table 8 shows how record selection is done with a shared-weight sort sequence. In
Table 8, the rows that match the record selection criteria for the column 'JOB' are
selected by treating uppercase letters the same as lowercase letters. Notice that in
Table 8 all the values 'mgr', 'Mgr' and 'MGR' are selected.
Table 8. ″SELECT * FROM STAFF WHERE JOB = ’MGR’ ″ Using the Shared-Weight Sort
Sequence for the ENU Language Identifier.
ID NAME DEPT JOB YEARS SALARY COMM
10 Sanders 20 Mgr 7 18357.50 0
The following SQL statements and tables show how views and sort sequences
work. View V1, used in the following examples, was created with a shared-weight
sort sequence of SRTSEQ(*LANGIDSHR) and LANGID(ENU). The CREATE VIEW
statement would be as follows:
CREATE VIEW V1 AS SELECT *
FROM STAFF
WHERE JOB = 'MGR' AND ID < 100
Any queries run against view V1 are run against the result table shown in Table 9.
The query shown below is run with a sort sequence of SRTSEQ(*LANGIDUNQ)
and LANGID(ENU).
Table 10. ″SELECT * FROM V1 WHERE JOB = ’MGR’″ Using the Unique-Weight Sort
Sequence for Language Identifier ENU
ID NAME DEPT JOB YEARS SALARY COMM
30 Merenghi 38 MGR 5 17506.75 0
If defining a referential constraint, the sort sequence between the parent and
dependent table must match. For more information on sort sequence and
constraints, see the DB2 UDB for AS/400 Database Programming book.
The sort sequence used at the time a check constraint is defined is the same sort
sequence the system uses to validate adherence to the constraint at the time of an
INSERT or UPDATE.
Types of cursors
SQL supports serial and scrollable cursors. The type of cursor determines the
positioning methods which can be used with the cursor.
Serial cursor
A serial cursor is one defined without the SCROLL keyword.
For a serial cursor, each row of the result table can be fetched only once per OPEN
of the cursor. When the cursor is opened, it is positioned before the first row in the
result table. When a FETCH is issued, the cursor is moved to the next row in the
result table. That row is then the current row. If host variables are specified (with
the INTO clause on the FETCH statement), SQL moves the current row’s contents
into your program’s host variables.
This sequence is repeated each time a FETCH statement is issued until the
end-of-data (SQLCODE = 100) is reached. When you reach the end-of-data, close
the cursor. You cannot access any rows in the result table after you reach the
end-of-data. To use the cursor again, you must first close the cursor and then
re-issue the OPEN statement. You can never back up.
Scrollable cursor
For a scrollable cursor, the rows of the result table can be fetched many times. The
cursor is moved through the result table based on the position option specified on
the FETCH statement. When the cursor is opened, it is positioned before the first
row in the result table. When a FETCH is issued, the cursor is positioned to the row
in the result table that is specified by the position option. That row is then the
current row. If host variables are specified (with the INTO clause on the FETCH
This sequence is repeated each time a FETCH statement is issued. The cursor
does not need to be closed when an end-of-data or beginning-of-data condition
occurs. The position options enable the program to continue fetching rows from the
table.
The following scroll options are used to position the cursor when issuing a FETCH
statement. These positions are relative to the current cursor location in the result
table.
NEXT Positions the cursor on the next row. This is the default if no
position is specified.
PRIOR Positions the cursor on the previous row.
FIRST Positions the cursor on the first row.
LAST Positions the cursor on the last row.
BEFORE Positions the cursor before the first row.
AFTER Positions the cursor after the last row.
CURRENT Does not change the cursor position.
RELATIVE n Evaluates a host variable or integer n in relationship to the
cursor’s current position. For example, if n is -1, the cursor is
positioned on the previous row of the result table. If n is +3,
the cursor is positioned three rows after the current row.
For the serial cursor example, the program processes all of the rows from the table,
updating the job for all members of department D11 and deleting the records of
employees from the other departments.
Table 11. A Serial Cursor Example
Serial Cursor SQL Statement Described in Section
EXEC SQL “Step 1: Define the Cursor” on page 58.
DECLARE THISEMP CURSOR FOR
SELECT EMPNO, LASTNAME,
WORKDEPT, JOB
FROM CORPDATA.EMPLOYEE
FOR UPDATE OF JOB
END-EXEC.
EXEC SQL “Step 2: Open the Cursor” on page 59.
OPEN THISEMP
END-EXEC.
EXEC SQL “Step 3: Specify What to Do When
WHENEVER NOT FOUND End-of-Data Is Reached” on page 59.
GO TO CLOSE-THISEMP
END-EXEC.
EXEC SQL
UPDATE CORPDATA.EMPLOYEE
SET JOB = :NEW-CODE
WHERE CURRENT OF THISEMP
END-EXEC.
EXEC SQL
DELETE FROM CORPDATA.EMPLOYEE
WHERE CURRENT OF THISEMP
END-EXEC.
Branch back to fetch and process the next
row.
CLOSE-THISEMP. “Step 6: Close the Cursor” on page 62.
EXEC SQL
CLOSE THISEMP
END-EXEC.
For the scrollable cursor example, the program uses the RELATIVE position option
to obtain a representative sample of salaries from department D11.
Table 12. Scrollable Cursor Example
Scrollable Cursor SQL Statement Described in Section
EXEC SQL “Step 1: Define the Cursor” on page 58.
DECLARE THISEMP DYNAMIC SCROLL CURSOR FOR
SELECT EMPNO, LASTNAME,
SALARY
FROM CORPDATA.EMPLOYEE
WHERE WORKDEPT = ’D11’
END-EXEC.
EXEC SQL “Step 2: Open the Cursor” on page 59.
OPEN THISEMP
END-EXEC.
EXEC SQL “Step 3: Specify What to Do When
WHENEVER NOT FOUND End-of-Data Is Reached” on page 59.
GO TO CLOSE-THISEMP
END-EXEC.
For a scrollable cursor, the statement looks like this (the WHERE clause is
optional):
EXEC SQL
DECLARE cursor-name DYNAMIC SCROLL CURSOR FOR
SELECT column-1, column-2 ,...
FROM table-name ,...
WHERE column-1 = expression ...
END-EXEC.
The select-statements shown here are rather simple. However, you can code
several other types of clauses in a select-statement within a DECLARE CURSOR
statement for a serial and a scrollable cursor.
If you intend to update any columns in any or all of the rows of the identified table
(the table named in the FROM clause), include the FOR UPDATE OF clause. It
names each column you intend to update. If you do not specify the names of
columns, and you specify either the ORDER BY clause or FOR READ ONLY
clause, a negative SQLCODE is returned if an update is attempted. If you do not
You can update a column of the identified table 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. 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 CORPDATA.EMPLOYEE table. If
you want to update the JOB column (one of the columns in each row of the
CORPDATA.EMPLOYEE table), the DECLARE CURSOR statement should include
FOR UPDATE OF JOB ... even though JOB is omitted from the SELECT statement.
The result table and cursor are read-only if any of the following are true:
v The first FROM clause identifies more than one table or view.
v The first FROM clause identifies a read-only view.
v The first SELECT clause specifies the keyword DISTINCT.
v The outer subselect contains a GROUP BY clause.
v The outer subselect contains a HAVING clause.
v The first SELECT clause contains a column function.
v The select-statement contains a subquery such that the base object of the outer
subselect and of the subquery is the same table.
v The select-statement contains a UNION or UNION ALL operator.
v The select-statement contains an ORDER BY clause, and the FOR UPDATE OF
clause and DYNAMIC SCROLL are not specified.
v The select-statement includes a FOR READ ONLY clause.
v The SCROLL keyword is specified without DYNAMIC.
| v The select-list includes a DataLink column and a FOR UPDATE OF clause is not
| specified.
3. A result table can contain zero, one, or many rows, depending on the extent to which the search condition is satisfied.
or
When you are using a serial cursor and the end-of-data is reached, every
subsequent FETCH statement returns the end-of-data condition. You cannot
position the cursor on rows that are already processed. The CLOSE statement is
the only operation that can be performed on the cursor.
When you are using a scrollable cursor and the end-of-data is reached, the result
table can still process more data. You can position the cursor anywhere in the result
table using a combination of the position options. You do not need to CLOSE the
cursor when the end-of-data is reached.
When your program issues the FETCH statement, SQL uses the current cursor
position as a starting point to locate the requested row in the result table. This
changes that row to the current row. If an INTO clause was specified, SQL moves
the current row’s contents into your program’s host variables. This sequence is
repeated each time the FETCH statement is issued.
SQL maintains the position of the current row (that is, the cursor points to the
current row) until the next FETCH statement for the cursor is issued. The UPDATE
statement does not change the position of the current row within the result table,
although the DELETE statement does.
After you update a row, the cursor’s position remains on that row (that is, the
current row of the cursor does not change) until you issue a FETCH statement for
the next row.
After you delete a row, you cannot update or delete another row using that cursor
until you issue a FETCH statement to position the cursor.
“The DELETE Statement” on page 34 shows you how to use the DELETE
statement to delete all rows that meet a specific search condition. You can also use
the FETCH and DELETE ... WHERE CURRENT OF statements when you want to
obtain a copy of the row, examine it, then delete it.
If you processed the rows of a result table and you do not want to use the cursor
again, you can let the system close the cursor. The system automatically closes the
cursor when:
v A COMMIT without HOLD statement is issued and the cursor is not declared
using the WITH HOLD clause.
v A ROLLBACK without HOLD statement is issued.
v The job ends.
v The activation group ends and CLOSQLCSR(*ENDACTGRP) was specified on
the precompile.
v The first SQL program in the call stack ends and neither
CLOSQLCSR(*ENDJOB) or CLOSQLCSR(*ENDACTGRP) was specified when
the program was precompiled.
v The connection to the application server is ended using the DISCONNECT
statement.
v The connection to the application server was released and a successful COMMIT
occurred.
v An *RUW CONNECT occurred.
Because an open cursor still holds locks on referred-to-tables or views, you
should explicitly close any open cursors as soon as they are no longer needed.
There are two ways to define the storage where fetched rows are placed: a host
structure array or a row storage area with an associated descriptor. Both methods
can be coded in all of the languages supported by the SQL precompilers, with the
exception of the host structure array in REXX. Refer to Chapter 12. Coding SQL
Statements in C and C++ Applications, through Chapter 17. Coding SQL
Statements in REXX Applications, for more information on the programming
languages. Both forms of the multiple-row FETCH statement allow the application to
code a separate indicator array. The indicator array should contain one indicator for
each host variable that is null capable.
The multiple-row FETCH statement can be used with both serial and scrollable
cursors. The operations used to define, open, and close a cursor for a multiple-row
FETCH remain the same. Only the FETCH statement changes to specify the
number of rows to retrieve and the storage where the rows are placed.
...
01 TABLE-1.
02 DEPT OCCURS 10 TIMES.
05 EMPNO PIC X(6).
05 LASTNAME.
49 LASTNAME-LEN PIC S9(4) BINARY.
49 LASTNAME-TEXT PIC X(15).
05 WORKDEPT PIC X(3).
05 JOB PIC X(8).
01 TABLE-2.
02 IND-ARRAY OCCURS 10 TIMES.
05 INDS PIC S9(4) BINARY OCCURS 4 TIMES.
...
EXEC SQL
DECLARE D11 CURSOR FOR
SELECT EMPNO, LASTNAME, WORKDEPT, JOB
FROM CORPDATA.EMPLOYEE
WHERE WORKDEPT = "D11"
END-EXEC.
...
EXEC SQL
OPEN D11
...
FETCH-PARA.
EXEC SQL WHENEVER NOT FOUND GO TO ALL-DONE END-EXEC.
EXEC SQL FETCH D11 FOR 10 ROWS INTO :DEPT :IND-ARRAY
END-EXEC.
...
The host structure array DEPT and the associated indicator array IND-ARRAY are
defined in the application. Both arrays have a dimension of ten. The indicator array
has an entry for each column in the result table.
The attributes of type and length of the DEPT host structure array elementary items
match the columns that are being retrieved.
When the multiple-row FETCH statement has successfully completed, the host
structure array contains the data for all eight rows. The indicator array, IND_ARRAY,
contains zeros for every column in every row because no NULL values were
returned.
The SQLCA that is returned to the application contains the following information:
v SQLCODE contains 0
v SQLSTATE contains '00000'
v SQLERRD3 contains 8, the number of rows fetched
v SQLERRD4 contains 34, the length of each row
v SQLERRD5 contains +100, indicating the last row in the result table is in the
block
See Appendix B of the DB2 UDB for AS/400 SQL Reference book for a description
of the SQLCA.
See Appendix C of the DB2 UDB for AS/400 SQL Reference book for a description
of the SQLDA.
...
...
...
EXEC SQL
OPEN D11;
/* SET UP THE DESCRIPTOR FOR THE MULTIPLE-ROW FETCH */
/* 4 COLUMNS ARE BEING FETCHED */
SQLD = 4;
SQLN = 4;
SQLDABC = 366;
SQLTYPE(1) = 452; /* FIXED LENGTH CHARACTER - */
/* NOT NULLABLE */
SQLLEN(1) = 6;
SQLTYPE(2) = 456; /*VARYING LENGTH CHARACTER */
/* NOT NULLABLE */
SQLLEN(2) = 15;
SQLTYPE(3) = 452; /* FIXED LENGTH CHARACTER - */
SQLLEN(3) = 3;
SQLTYPE(4) = 452; /* FIXED LENGTH CHARACTER - */
/* NOT NULLABLE */
SQLLEN(4) = 8;
/*ISSUE THE MULTIPLE-ROW FETCH STATEMENT TO RETRIEVE*/
/*THE DATA INTO THE DEPT ROW STORAGE AREA */
/*USE A HOST VARIABLE TO CONTAIN THE COUNT OF */
/*ROWS TO BE RETURNED ON THE MULTIPLE-ROW FETCH */
In this example, a cursor has been defined for the CORPDATA.EMPLOYEE table to
select all rows where the WORKDEPT column equal 'D11'. The sample EMPLOYEE
table in Appendix A. DB2 UDB for AS/400 Sample Tables shows the result table
contains eight rows. The DECLARE CURSOR and OPEN statements do not have
special syntax when they are used with a multiple-row FETCH statement. Another
FETCH statement that returns a single row against the same cursor can be coded
elsewhere in the program. The multiple-row FETCH statement is used to retrieve all
rows in the result table. Following the FETCH, the cursor position remains on the
eighth record in the block.
The row area, ROWAREA, is defined as a character array. The data from the result
table is placed in the host variable. In this example, a pointer variable is assigned to
the address of ROWAREA. Each item in the rows that are returned is examined
and used with the based structure DEPT.
The attributes (type and length) of the items in the descriptor match the columns
that are retrieved. In this case, no indicator area is provided.
After the FETCH statement is completed, the ROWAREA contains eight rows. The
SQLCA that is returned to the application contains the following:
v SQLCODE contains 0
v SQLSTATE contains '00000'
v SQLERRD3 contains 8, the number of rows returned
v SQLERRD4 contains 34, for the length of the row fetched
v SQLERRD5 contains +100, indicating the last row in the result table was fetched
In this example, the application has taken advantage of the fact that SQLERRD5
contains an indication of the end of the file being reached. As a result, the
application does not need to call SQL again to attempt to retrieve more rows. If the
If you want to continue processing from the current cursor position after a COMMIT
or ROLLBACK, you must specify COMMIT HOLD or ROLLBACK HOLD. When
HOLD is specified, any open cursors are left open and keep their cursor position so
processing can resume. On a COMMIT statement, the cursor position is
maintained. On a ROLLBACK statement, the cursor position is restored to just after
the last row retrieved from the previous unit of work. All record locks are still
released.
After issuing a COMMIT or ROLLBACK statement without HOLD, all locks are
released and all cursors are closed. You can open the cursor again, but you will
begin processing at the first row of the result table.
One use for this kind of INSERT statement is to move data into a table you created
for summary data. For example, suppose you want a table that shows each
employee’s time commitments to projects. You could create a table called
EMPTIME with the columns EMPNUMBER, PROJNUMBER, STARTDATE,
ENDDATE, and TTIME, and then use the following INSERT statement to fill the
table:
INSERT INTO CORPDATA.EMPTIME
(EMPNUMBER, PROJNUMBER, STARTDATE, ENDDATE)
SELECT EMPNO, PROJNO, EMSTDATE, EMENDATE
FROM CORPDATA.EMP_ACT
DSTRUCT is a host structure array with five elements that is declared in the
program. The five elements correspond to EMPNO, FIRSTNME, MIDINIT,
LASTNAME, and WORKDEPT. DSTRUCT has a dimension of at least ten to
accommodate inserting ten rows. ISTRUCT is a host structure array that is declared
in the program. ISTRUCT has a dimension of at least ten small integer fields for the
indicators.
Blocked INSERT statements are supported for non-distributed SQL applications and
for distributed applications where both the application server and the application
requester are AS/400 systems.
The previous update can also be written by specifying all of the columns and then
all of the values:
UPDATE EMPLOYEE
SET (WORKDEPT, PHONENO, JOB)
= ('D11', '7213', 'DESIGNER')
WHERE EMPNO = '000270'
Another way to select a value (or multiple values) for an update is to use a
scalar-subselect. The scalar-subselect allows you to update one or more columns
by setting them to one or more values selected from another table. In the following
example, an employee moves to a different department but continues working on
the same projects. The employee table has already been updated to contain the
new department number. Now the project table needs to be updated to reflect the
new department number of this employee (employee number is ’000030’).
UPDATE PROJECT
SET DEPTNO =
(SELECT WORKDEPT FROM EMPLOYEE
WHERE PROJECT.RESPEMP = EMPLOYEE.EMPNO)
WHERE RESPEMP='000030'
This same technique could be used to update a list of columns with multiple values
returned from a single select.
It is also possible to update an entire row in one table with values from a row in
another table.
Suppose there is a master class schedule table that needs to be udpated with
changes that have been made in a copy of the table. The changes are made to the
work copy and merged into the master table every night. The two tables have
exactly the same columns and one column, CLASS_CODE, is a unique key
column.
UPDATE CL_SCHED
SET ROW =
(SELECT * FROM MYCOPY
WHERE CL_SCHED.CLASS_CODE = MYCOPY.CLASS_CODE)
This update will update all of the rows in CL_SCHED with the values from
MYCOPY.
DISTINCT means you want to select only the unique rows. If a selected row
duplicates another row in the result table, the duplicate row is ignored (it is not put
The result is two rows (in this example, JOB-DEPT is set to D11).
fetch JOB
1 Designer
RV2W557-2
If you do not include DISTINCT in a SELECT clause, you might find duplicate rows
in your result, because SQL retrieves the JOB column’s value for each row that
satisfies the search condition. Null values are treated as duplicate rows for
DISTINCT.
If you include DISTINCT in a SELECT clause and you also include a shared-weight
sort sequence, fewer values are returned. The sort sequence causes values that
contain the same characters to be weighted the same. If 'MGR', 'Mgr', and 'mgr'
were all in the same table, only one of these values would be returned.
Note: Constants are shown in the following examples to keep the examples simple.
However, you could just as easily code host variables instead. Remember to
precede each host variable with a colon.
For character and UCS-2 graphic column predicates, the sort sequence is applied
to the operands before evaluation of the predicates for BETWEEN, IN, EXISTS, and
LIKE clauses. See “Using Sort Sequence in SQL” on page 50 for more information
on the using sort sequence with selection.
v BETWEEN ... AND ... is used to specify a search condition that is satisfied by
any value that falls on or between two other values. For example, to find all
employees who were hired in 1987, you could use this:
... WHERE HIREDATE BETWEEN '1987-01-01' AND '1987-12-31'
Note: If you are operating on MIXED data, the following distinction applies: an
SBCS underline character refers to one SBCS character. No such
restriction applies to the percent sign; that is, a percent sign refers to any
number of SBCS or DBCS characters. See the DB2 UDB for AS/400 SQL
Reference book for more information on the LIKE predicate and MIXED
data.
Use the underline character or percent sign either when you do not know or do
not care about all the characters of the column’s value. For example, to find out
which employees live in Minneapolis, you could specify:
... WHERE ADDRESS LIKE '%MINNEAPOLIS%'
In this case, you should be sure that MINNEAPOLIS was not part of a street
address or part of another city name. SQL returns any row with the string
MINNEAPOLIS in the ADDRESS column, no matter where the string occurs.
In another example, to list the towns whose names begin with 'SAN', you could
specify:
... WHERE TOWN LIKE 'SAN%'
If you want to search for a character string that contains either the underscore or
percent character, use the ESCAPE clause to specify an escape character. For
example, to see all businesses that have a percent in their name, you could
specify:
... WHERE BUSINESS_NAME LIKE '%@%%' ESCAPE '@'
The first and last percent characters are interpreted as usual. The combination
’@%’ is taken as the actual percent character.
For example, if you did a search using the search pattern ’ABC%’ contained in a
host variable with a fixed length of 10, these are some the values that could be
returned assuming the column has a length of 12:
'ABCDE ' 'ABCD ' 'ABCxxx ' 'ABC '
Note that all returned values start with ’ABC’ and end with at least six blanks.
This is because the last six characters in the host variable were not assigned a
specific value so blanks were used.
You can join any two predicates with the connectors AND and OR. In addition, you
can use the NOT keyword to specify that the desired search condition is the
negated value of the specified search condition. A WHERE clause can have as
many predicates as you want.
v AND says that, for a row to qualify, the row must satisfy both predicates of the
search condition. For example, to find out which employees in department D21
were hired after December 31, 1987, you would specify:
...
WHERE WORKDEPT = 'D21' AND HIREDATE > '1987-12-31'
v OR says that, for a row to qualify, the row can satisfy the condition set by either
or both predicates of the search condition. For example, to find out which
employees are in either department C01 or D11, you could specify 4:
...
WHERE WORKDEPT = 'C01' OR WORKDEPT = 'D11'
v NOT says that, to qualify, a row must not meet the criteria set by the search
condition or predicate that follows the NOT. For example, to find all employees in
department E11 except those with a job code equal to analyst, you could specify:
...
WHERE WORKDEPT = 'E11' AND NOT JOB = 'ANALYST'
When SQL evaluates search conditions that contain these connectors, it does so in
a specific order. SQL first evaluates the NOT clauses, next evaluates the AND
clauses, and then the OR clauses.
4. You could also use IN to specify this request: WHERE WORKDEPT IN ('C01', 'D11').
The parentheses determine the meaning of the search condition. In this example,
you want all rows that have a:
WORKDEPT value of E11 or E21, and
EDLEVEL value greater than 12
Your result is different. The selected rows are rows that have:
WORKDEPT = E11 and EDLEVEL > 12, or
WORKDEPT = E21, regardless of the EDLEVEL value
Four different types of joins are supported by DB2 UDB for AS/400: inner join, left
outer join, exception join, and cross join.
v An “Inner Join” returns only the rows from each table that have matching values
in the join columns. Any rows that do not have a match between the tables will
not appear in the result table.
v A “Left Outer Join” on page 76 returns values for all of the rows from the first
table (the table on the left) and the values from the second table for the rows that
match. Any rows that do not have a match in the second table will return the null
value for all columns from the second table.
v An “Exception Join” on page 77 returns only the rows from the left table that do
not have a match in the right table. Columns in the result table that come from
the right table have the null value.
v A “Cross Join” on page 78 returns a row in the result table for each combination
of rows from the tables being joined (a Cartesian Product).
Inner Join
With an inner join, column values from one row of a table are combined with
column values from another row of another (or the same) table to form a single row
of data. SQL examines both tables specified for the join to retrieve data from all the
rows that meet the search condition for the join. There are two ways of specifying
an inner join: using the JOIN syntax, and using the WHERE clause.
In this example, the join is done on the two tables using the EMPNO and
RESPEMP columns from the tables. Since only employees that have last names
starting with at least ’S’ are to be returned, this additional condition is provided in
the WHERE clause.
Suppose you want to find all employees and the projects they are currently
responsible for. You want to see those employees that are not currently in charge of
The result of this query contains some employees that do not have a project
number. They are listed in the query, but have the null value returned for their
project number.
Notes
Using the RRN scalar function to return the relative record number for a column in
the table on the right in a left outer join or exception join will return a value of 0 for
the unmatched rows.
Exception Join
An exception join returns only the records from the first table that do NOT have a
match in the second table. Using the same tables as before, return those
employees that are not responsible for any projects.
SELECT EMPNO, LASTNAME, PROJNO
FROM CORPDATA.EMPLOYEE EXCEPTION JOIN CORPDATA.PROJECT
ON EMPNO = RESPEMP
WHERE LASTNAME > 'S'
An exception join can also be written as a subquery using the NOT EXISTS
predicate. The previous query could be rewritten in the following way:
The only difference in this query is that it cannot return values from the PROJECT
table.
Cross Join
A cross join (or Cartesian Product join) will return a result table where each row
from the first table is combined with each row from the second table. The number of
rows in the result table is the product of the number of rows in each table. If the
tables involved are large, this join can take a very long time.
A cross join can be specified in two ways: using the JOIN syntax or by listing the
tables in the FROM clause separated by commas without using a WHERE clause
to supply join criteria.
The result table for either of these select statements looks like this:
Notes on Joins
When you join two or more tables:
v If there are common column names, you must qualify each common name with
the name of the table (or a correlation name). Column names that are unique do
not need to be qualified.
v If you do not list the column names you want, but instead use SELECT *, SQL
returns rows that consist of all the columns of the first table, followed by all the
columns of the second table, and so on.
v You must be authorized to select rows from each table or view specified in the
FROM clause.
v The sort sequence is applied to all character and UCS-2 graphic columns being
joined.
|
| Using Table Expressions
| You can use table expressions to specify an intermediate result table. They can be
| used in place of a view to avoid creating the view when general use of the view is
| not required. Table expressions consist of nested table expressions and common
| table expressions.
| Nested table expressions are specified within parentheses in the FROM clause. For
| example, suppose you want a result table that shows the manager number,
| department number, and maximum salary for each department. The manager
| number is in the DEPARTMENT table, the department number is in both the
| DEPARTMENT and EMPLOYEE tables, and the salaries are in the EMPLOYEE
| table. You can use a table expression in the from clause to select the maximum
| salary for each department. You add a correlation name, T2, following the nested
| table expression to name the derived table. The outer select then uses T2 to qualify
| columns that are selected from the derived table, in this case MAXSAL and
| For example, suppose you want a table that shows the minimum and maximum of
| the average salary of a certain set of departments. The first character of the
| department number has some meaning and you want to get the minimum and
| maximum for those departments that start with the letter ’D’ and those that start
| with the letter ’E’. You can use a common table expression to select the average
| salary for each department. Again, you must name the derived table; in this case,
| the name is DT. You can then specify a SELECT statement using a WHERE clause
| to restrict the selection to only the departments that begin with a certain letter.
| Specify the minimum and maximum of column AVGSAL from the derived table DT.
| Specify a UNION to get the results for the letter ’E’ and the results for the letter ’D’.
| WITH DT AS (SELECT E.WORKDEPT AS DEPTNO, AVG(SALARY) AS AVGSAL
| FROM CORPDATA.DEPARTMENT D , CORPDATA.EMPLOYEE E
| WHERE D.DEPTNO = E.WORKDEPT
| GROUP BY E.WORKDEPT)
| SELECT 'E', MAX(AVGSAL), MIN(AVGSAL) FROM DT
| WHERE DEPTNO LIKE 'E%'
| UNION
| SELECT 'D', MAX(AVGSAL), MIN(AVGSAL) FROM DT
| WHERE DEPTNO LIKE 'D%'
You can use UNION to eliminate duplicates when merging lists of values obtained
from several tables. For example, you can obtain a combined list of employee
numbers that includes:
v People in department D11
v People whose assignments include projects MA2112, MA2113, and AD3111
The combined list is derived from two tables and contains no duplicates. To do this,
specify:
MOVE 'D11' TO WORK-DEPT.
...
EXEC SQL
DECLARE XMP6 CURSOR FOR
SELECT EMPNO
FROM CORPDATA.EMPLOYEE
WHERE WORKDEPT = :WORK-DEPT
UNION
SELECT EMPNO
FROM CORPDATA.EMP_ACT
WHERE PROJNO = 'MA2112' OR
PROJNO = 'MA2113' OR
PROJNO = 'AD3111'
ORDER BY EMPNO
END-EXEC.
...
EXEC SQL
FETCH XMP6
INTO :EMP-NUMBER
END-EXEC.
To better understand what results from these SQL statements, imagine that SQL
goes through the following process:
fetch EMP-NUMBER
1 000060
2 000150
3 000160
4 000170
5 000180
... ...
RV3W186-0
If the result columns are unnamed, use numbers to order the result. The number
refers to the position of the expression in the list of expressions you include in
your subselects.
SELECT A + B ...
UNION SELECT X ... ORDER BY 1
For information on compatibility of the length and data type for columns in a
UNION, see chapter 4 of the DB2 UDB for AS/400 SQL Reference book.
Note: Sort sequence is applied after the fields across the UNION pieces are made
compatible. The sort sequence is used for the distinct processing that
implicitly occurs during UNION processing.
fetch EMP-NUMBER
1 000060
2 000150
3 000150
4 000150
5 000160
6 000160
7 000170
8 000170
... ...
RV3W187-0
Using Subqueries
In the WHERE and HAVING clauses you have seen so far, you specified a search
condition by using a literal value, a column name, an expression, or the registers. In
those search conditions, you know that you are searching for a specific value, but
sometimes you cannot supply that value until you have retrieved other data from a
table. For example, suppose you want a list of the employee numbers, names, and
job codes of all employees working on a particular project, say project number
MA2100. The first part of the statement is easy to write:
DECLARE XMP CURSOR FOR
SELECT EMPNO, LASTNAME, JOB
FROM CORPDATA.EMPLOYEE
WHERE EMPNO ...
But you cannot go further because the CORPDATA.EMPLOYEE table does not
include project number data. You do not know which employees are working on
project MA2100 without issuing another SELECT statement against the
CORPDATA.EMP_ACT table.
With SQL, 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-level SELECT. Using a
subquery, you could issue just one SQL statement to retrieve the employee
numbers, names, and job codes for employees who work on project MA2100:
DECLARE XMP CURSOR FOR
SELECT EMPNO, LASTNAME, JOB
FROM CORPDATA.EMPLOYEE
WHERE EMPNO IN
(SELECT EMPNO
FROM CORPDATA.EMP_ACT
WHERE PROJNO = 'MA2100')
To better understand what will result from this SQL statement, imagine that SQL
goes through the following process:
000010
000110
Step 2: The interim results The final result table looks like this:
table then serves as a list
in the search condition of
the outer-level SELECT.
Essentially, this is what is
executed.
RV2W559-2
Correlation
The purpose of a subquery is to supply information needed to qualify a row
(WHERE clause) or a group of rows (HAVING clause). This is done through the
result table that the subquery produces. Conceptually, the subquery is evaluated
whenever a new row or group of rows must be qualified. In fact, if the subquery is
the same for every row or group, it is evaluated only once. For example, the
previous subquery has the same content for every row of the table
CORPDATA.EMPLOYEE. Subqueries like this are said to be uncorrelated.
Some subqueries 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. More information on correlated subqueries can be found in “Correlated
Subqueries” on page 88. Even so, what is said before that point applies equally to
correlated and uncorrelated subqueries.
Subqueries can also appear in the search conditions of other subqueries. Such
subqueries are said to be nested at some level of nesting. For example, a
subquery within a subquery within an outer-level SELECT is nested at a nesting
level of two. SQL allows nesting down to a nesting level of 32, but few queries
require a nesting level greater than 1.
Basic Comparisons
You can use a subquery immediately after any of the comparison operators. If you
do, the subquery can return at most one value. The value can be the result of a
column function or an arithmetic expression. SQL then compares the value that
results from the subquery with the value to the left of the comparison operator. For
example, suppose you want to find the employee numbers, names, and salaries for
employees whose education level is higher than the average education level
throughout the company.
DECLARE XMP CURSOR FOR
SELECT EMPNO, LASTNAME, SALARY
FROM CORPDATA.EMPLOYEE
WHERE EDLEVEL >
(SELECT AVG(EDLEVEL)
FROM CORPDATA.EMPLOYEE)
SQL first evaluates the subquery and then substitutes the result in the WHERE
clause of the SELECT statement. In this example, the result is (as it should be) the
company-wide average educational level. Besides returning a single value, a
subquery could return no value at all. If it does, the result of the compare is
unknown. Consider, for example, the first query shown in this section, and assume
that there are not any employees currently working on project MA2100. Then the
subquery would return no value, and the search condition would be unknown for
every row. In this case, then, the result produced by the query would be an empty
table.
To satisfy this WHERE clause, the value in the expression must be greater than
all the values (that is, greater than the highest value) returned by the subquery. If
the subquery returns an empty set (that is, no values were selected), the
condition is satisfied.
To satisfy this WHERE clause, the value in the expression must be greater than
at least one of the values (that is, greater than the lowest value) returned by the
subquery. If what the subquery returns is empty, the condition is not satisfied.
Note: The results when a subquery returns one or more null values may surprise
you, unless you are familiar with formal logic. For applicable rules, read the
discussion of quantified predicates in the DB2 UDB for AS/400 SQL
Reference .
In the example, the search condition holds if any project represented in the
CORPDATA.PROJECT table has an estimated start date that is later than January
1, 1982. Please note that this example does not show the full power of EXISTS,
because the result is always the same for every row examined for the outer-level
SELECT. As a consequence, either every row appears in the results, or none
appear. In a more powerful example, the subquery itself would be correlated, and
would change from row to row. See “Correlated Subqueries” on page 88 for more
information on correlated subqueries.
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 could 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 could use:
... WHERE NOT EXISTS (SELECT ...)
For all general types of usage for subqueries but one (using a subquery with the
EXISTS keyword), the subquery must produce a one-column result table. This
The result table produced by a subquery can have zero or more rows. For some
usages, no more than one row is allowed.
Correlated Subqueries
In the subqueries previously discussed, SQL evaluates the subquery once,
substitutes the result of the subquery in the right side of the search condition, and
evaluates the outer-level SELECT based on the value of the search condition. You
can also write a subquery that SQL may have to re-evaluate as it examines each
A correlated subquery looks like an uncorrelated one, except for the presence of
one or more correlated references. In the example, the single correlated reference
is the occurrence of X.WORKDEPT in the subselect’s FROM clause. Here, the
qualifier X is the correlation name defined in the FROM clause of the outer SELECT
statement. In that clause, X is introduced as the correlation name of the table
CORPDATA.EMPLOYEE.
Now, consider what happens when the subquery is executed for a given row of
CORPDATA.EMPLOYEE. 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 I HAAS. Her work department is A00,
which is the value of WORKDEPT for this row. The subquery executed for this row
is:
(SELECT AVG(EDLEVEL)
FROM CORPDATA.EMPLOYEE
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 would be B01, and the subquery for his row
would deliver the average education level for department B01.
The result table produced by the query would have the following values:
RV2W560-3
Consider what happens when the subquery is executed for a given department of
CORPDATA.EMPLOYEE. Before it is executed, the occurrence of X.WORKDEPT is
replaced with the value of the WORKDEPT column for that group. Suppose, for
example, that the first group selected has A00 for the value of WORKDEPT. The
subquery executed for this group is:
(SELECT AVG(SALARY)
FROM CORPDATA.EMPLOYEE
WHERE SUBSTR('A00',1,1) = SUBSTR(WORKDEPT,1,1))
Thus, for the group considered, the subquery produces the average salary for the
area. This is then compared in the outer statement to the average salary for
department 'A00'. For some other group for which WORKDEPT is ’B01’, the
subquery would result in the average salary for the area where department B01
belongs.
The result table produced by the query would have the following values:
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 one with
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-level SELECT.
You can define a correlation name for each table name appearing in a FROM
clause. Simply include the correlation names after the table names. 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.
FROM TABLEA TA, TABLEC, TABLEB TB
Before the subquery is executed, a value from the referenced column is always
substituted for the correlated reference. The value is determined as follows:
Note: Use D to designate the query in which the correlation name is defined. Then
the subquery is either in the WHERE clause of D, or in its HAVING clause.
v If the subquery is in the WHERE clause, its results are used by D to qualify a
row. The substituted value is then taken from this row. This is the case for the
example, where the defining query is the outer one and the subquery appears in
the outer query’s WHERE clause.
v If the subquery is in the HAVING clause, its results are used by D to qualify a
group of rows. The substituted value is then taken from this group. Note that in
this case, the column specified must be identified in the GROUP BY clause in D.
If it is not, the specified column could have more than one value for the group.
SQL determines, for each row in the CORPDATA.EMP_ACT table, whether a row
with the same project number exists in the CORPDATA.PROJECT table. If not, the
CORPDATA.EMP_ACT row is deleted.
You can add, change, or drop columns and add or remove constraints all with one
ALTER TABLE statement. However, a single column can be referenced only once in
the ADD COLUMN, ALTER COLUMN, and DROP COLUMN clauses. That is, you
cannot add a column and then alter that column in the same ALTER TABLE
statement.
Adding a column
| You can add a column to a table using Operations Navigator. Or use the ADD
| COLUMN clause of the SQL ALTER TABLE statement.
When you add a new column to a table, the column is initialized with its default
value for all existing rows. If NOT NULL is specified, a default value must also be
specified.
| The altered table may consist of up to 8000 columns. The sum of the byte counts of
| the columns must not be greater than 32766 or, if a VARCHAR or VARGRAPHIC
| column is specified, 32740. If a LOB column is specified, the sum of record data
| byte counts of the columns must not be greater than 15 728 640.
Changing a column
| You can change a column in a table using Operations Navigator. Or, you can use
| the ALTER COLUMN clause of the ALTER TABLE statement. When you change the
| data type of an existing column, the old and new attributes must be compatible.
| “Allowable Conversions” shows the conversions with compatible attributes.
| When you convert to a data type with a longer length, data will be padded with the
| appropriate pad character. When you convert to a data type with a shorter length,
| data may be lost due to truncation. An inquiry message prompts you to confirm the
| request.
| If you have a column that does not allow the null value and you want to change it to
| now allow the null value, use the DROP NOT NULL clause. If you have a column
| that allows the null value and you want to prevent the use of null values, use the
| SET NOT NULL clause. If any of the existing values in that column are the null
| value, the ALTER TABLE will not be performed and an SQLCODE of -190 will
| result.
Allowable Conversions
Table 15. Allowable Conversions
FROM data type TO data type
Decimal Numeric
| When modifying an existing column, only the attributes that you specify will be
| changed. All other attributes will remain unchanged. For example, given the
| following table definition:
| CREATE TABLE EX1 (COL1 CHAR(10) DEFAULT 'COL1',
| COL2 VARCHAR(20) ALLOCATE(10) CCSID 937,
| COL3 VARGRAPHIC(20) ALLOCATE(10)
| NOT NULL WITH DEFAULT)
COL2 would still have an allocated length of 10 and CCSID 937, and COL3 would
still have an allocated length of 10.
Dropping a column deletes that column from the table definition. If CASCADE is
specified, any views, indexes, and constraints dependent on that column will also
be dropped. If RESTRICT is specified, and any views, indexes, or constraints are
dependent on the column, the column will not be dropped and SQLCODE of -196
will be issued.
| Within each of these steps, the order in which you specify the clauses is the order
in which they are performed, with one exception. If any columns are being dropped,
that operation is logically done before any column definitions are added or altered,
in case record length is increased as a result of the ALTER TABLE statement.
For example, to create a view that selects only the last name and the department of
all the managers, specify:
CREATE VIEW CORPDATA.EMP_MANAGERS AS
SELECT LASTNAME, WORKDEPT FROM CORPDATA.EMPLOYEE
WHERE JOB = 'MANAGER'
If the select list contains elements other than columns such as expressions,
functions, constants, or special registers, and the AS clause was not used to name
the columns, a column list must be specified for the view. In the following example,
the columns of the view are LASTNAME and YEARSOFSERVICE.
CREATE VIEW CORPDATA.EMP_YEARSOFSERVICE
(LASTNAME, YEARSOFSERVICE) AS
SELECT LASTNAME, YEARS (CURRENT DATE - HIREDATE)
FROM CORPDATA.EMPLOYEE
The previous view can also be defined by using the AS clause in the select list to
name the columns in the view. For example:
CREATE VIEW CORPDATA.EMP_YEARSOFSERVICE AS
SELECT LASTNAME,
YEARS (CURRENT_DATE - HIREDATE) AS YEARSOFSERVICE
FROM CORPDATA.EMPLOYEE