Sql For Ibm I A Database Modernization Guide None Rafael Victriapereira
Sql For Ibm I A Database Modernization Guide None Rafael Victriapereira
Sql For Ibm I A Database Modernization Guide None Rafael Victriapereira
Mathematics 5 - Time Measurement: Time Zonemenchreo
LAW OF CONTRACT ( 5 YEAR LLB & UNITARY LLB)- MODULE-3 - LEARN THROUGH PICTUREAPARNA T SHAIL KUMAR
Talk on Critical Theory, Part One, Philosophy of Social SciencesSoraj Hongladarom
2025 Winter SWAYAM NPTEL & A Student.pptxUtsav Yagnik
Ad
Sql For Ibm I A Database Modernization Guide None Rafael Victriapereira
1. Sql For Ibm I A Database Modernization Guide
None Rafael Victriapereira download
https://ebookbell.com/product/sql-for-ibm-i-a-database-
modernization-guide-none-rafael-victriapereira-49182832
Explore and download more ebooks at ebookbell.com
2. Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Db2 Sql Pl Deployment And Advanced Configuration Essential Guide For
Db2 Udb On Linux Unix Windows I5os Zos Second Edition Zamil Janmohamed
https://ebookbell.com/product/db2-sql-pl-deployment-and-advanced-
configuration-essential-guide-for-db2-udb-on-linux-unix-windows-i5os-
zos-second-edition-zamil-janmohamed-977794
Sql For Data Analytics Harness The Power Of Sql To Extract Insights
From Data 3rd Edition Jun Shan
https://ebookbell.com/product/sql-for-data-analytics-harness-the-
power-of-sql-to-extract-insights-from-data-3rd-edition-jun-
shan-44998404
Sql For Data Scientists A Beginners Guide For Building Datasets For
Analysis Renee M P Teate
https://ebookbell.com/product/sql-for-data-scientists-a-beginners-
guide-for-building-datasets-for-analysis-renee-m-p-teate-56645064
Sql For Mysql Djoni Darmawikarta Darmawikarta Djoni
https://ebookbell.com/product/sql-for-mysql-djoni-darmawikarta-
darmawikarta-djoni-23403128
3. Sql For Microsoft Access Cecelia L Allison
https://ebookbell.com/product/sql-for-microsoft-access-cecelia-l-
allison-2585258
Sql For Data Analysis Advanced Techniques For Transforming Data Into
Insights 1st Edition Cathy Tanimura
https://ebookbell.com/product/sql-for-data-analysis-advanced-
techniques-for-transforming-data-into-insights-1st-edition-cathy-
tanimura-34790482
Sql For Dummies 7th Edition 7th Edition Allen G Taylor
https://ebookbell.com/product/sql-for-dummies-7th-edition-7th-edition-
allen-g-taylor-36152706
Sql For Dummies 6th Edition Allen G Taylor
https://ebookbell.com/product/sql-for-dummies-6th-edition-allen-g-
taylor-4078526
Sql For Dummies 8th Edition Allen G Taylor
https://ebookbell.com/product/sql-for-dummies-8th-edition-allen-g-
taylor-4544196
8. Acknowledgments
Ex nihilo omnia—From a blank page, a book
First of all, I’d like to thank you, dear reader, for investing your time in this book.
I’d like to thank Victoria Mack, longtime editor of my TechTips, for believing in my
ability to write; Anne Grubb, editor of this work; and the rest of the dedicated staff of MC
Press who made it happen.
A big, big thanks to Mike Jones for being a fantastic technical sounding board and for
gracing me with his insightful suggestions and remarks. This book wouldn’t be the same
without his help.
My dear colleague Nuno Gama also helped to shape this book, by peppering me with
questions and tough challenges about SQL for i, often pushing it to its limits.
I’d also like to thank David Ford, Hassan Farooqi, Dan Lovell, Robert Pietrzykowski,
and Keith Hodges for sharing their “Christmas wish list for a proper SQL book.” Much of
what is discussed in this book came from their combined topic lists.
Finally, I’d like to thank the readers of the SQL 101 TechTip Series, who, with their
questions and comments, inspired and helped to shape this book.
If I forgot someone, which is highly likely, and you are that someone, please find it in
your heart to forgive my lapse!
www.allitebooks.com
10. Contents
Acknowledgments iii
Why You Need This Book 1
How Can You Get More Out of the Database? 1
1: Meet the UMADB: Our Example Database 3
The Students Table 4
The Courses Table 5
The Teachers Table 6
The Classes Table 8
The Grades Table 9
Just a Few Tables, and So Many Problems 9
In This Chapter, You’ve Learned ... 10
2: A Data Manipulation Language Basics Recap 11
Using the BETWEEN and IN Predicates 11
Joining Tables 14
The JOIN You’ve Been Using Without Realizing: INNER JOIN 14
Start Joining Tables Left and Right 17
“Just Get Me Everything”: FULL JOIN 19
A Join Summary 19
A Handful of Column Functions 20
The COUNT Function 21
Finding the Minimum and Maximum Values of a Column 21
Sums and Averages Made Easy 22
The Shape-shifting CAST Function 23
Aggregating Data with GROUP BY 24
11. vi • Contents
The Two Flavors of INSERT 25
Vanilla INSERT: Plain, Simple, and Kind of Boring 25
Strawberry (or Whatever Your Favorite Ice Cream
Flavor Is) INSERT 27
Data Adjustments with UPDATE 28
DELETE: A Blessing and a Curse 30
In This Chapter, You’ve Learned ... 32
3: A Data Definition Language Basics Recap 35
Converting UMADB’s Physical Files to SQL Tables 35
CREATE TABLE Fundamentals 39
Moving a Step Closer to a Real SQL Table 41
Adding a Unique, Self-Managed Key 41
Providing Proper Default Values for Optional and
Audit-Related Columns 43
Time for Some Practice 46
A First Step Toward Easier Data Access: Creating a Few Simple Views 47
Why Do You Need Views? 48
How Do You Create Views? 48
Repeat After Me: A View Is Not a Logical File 52
The Missing Piece: SQL Indexes 53
A Side Note: Why Is It So Important to Keep the Source Statements Safe? 54
Exploring a Few CREATE INDEX Options 55
In This Chapter, You’ve Learned … 57
4: Making the Database User-Friendly 59
Using Longer Table and Column Names 59
Time for Some Practice 64
Hiding Database Complexity 65
Using the Same Table Twice in a Query 66
Using Sub-queries 68
Using EXISTS to Omit Records on a SELECT Statement 70
Checking Database Consistency with the Exception Join 72
Time for Some (More) Practice 74
Using CASE to Return “Friendlier” Column Values 75
Using CASE in the ORDER BY Clause 78
12. Contents • vii
Using a Secondary Table to Produce Customizable
Sorting Sequences 79
In This Chapter, You’ve Learned ... 82
5: Tidying Up the Database 83
A Quick Refresher on Relational Databases 84
Relational Databases and Their Use of Keys 84
Primary Keys 85
Unique Keys 85
Foreign Keys 86
Table Relationship Types 86
Understanding Identifying and Non-Identifying Relationships 86
Referential Integrity 87
Entity Relationship Diagram Notation 87
Solving UMADB’s Database Problems Through Normalization 89
Data Anomalies 89
Some Boring, Yet Important, Math Jargon 90
Introducing the Normal Forms, Academic Version 92
Normalizing UMADB to 3NF 93
Data Modeling with Visual Paradigm 95
Introducing Visual Paradigm Community Edition 95
Time for Some Practice 101
Creating the New and Improved UMADB 102
Time for Some (More) Practice 111
Data Modeling Is Fun, but Where’s the Code? 111
Migrating the Data to the New, Improved UMADB 114
Populating the Teacher Ranks Table 114
Populating the Departments Table 116
Creating the Persons Data 116
Populating the Teachers Table 119
Populating the Students Table 120
Populating the Courses Table 121
Creating the Class Definitions Data 122
Creating the Classes per Year Data 124
Creating the Class Enrollment per Year Data 125
Populating the Sort Sequence Table 128
13. viii • Contents
Time for a Bit More Practice 129
Hiding the Database Complexity (Again) by
Recreating the Views 130
In This Chapter, You’ve Learned ... 137
6: Introducing Data-Centric Programming and SQL/PSM 139
A Call from the Dean’s Office 139
Introducing Data-Centric Programming 140
An SQL/PSM Crash Course 141
Variable Declaration 141
Variable Assignment 142
Flow Control 144
Loop Control 147
Calling Other SQL Routines, FOR Loops, and Cursors 149
Dynamic SQL 152
Compound Statements 161
Error Handling 162
In This Chapter, You’ve Learned ... 175
7: Creating and Using Stored Procedures 177
SPs, UDFs, and Triggers: When to Use Each 177
Analyzing the SP’s Structure 178
What’s in a Name? 179
Procedure Parameters 179
Procedure Properties 182
Procedure Options 185
Procedure Body 189
Creating Your First Stored Procedure 189
Time for Some Practice 195
Data-returning Stored Procedures 197
Creating Data-returning Stored Procedures 198
Creating More Complex Data-returning Stored Procedures 208
Time for Some (More) Practice 215
Using Data-returning Stored Procedures 218
How to Use the Result Sets Returned by a Stored Procedure 218
And There’s Still Time for a Little More Practice 224
In This Chapter, You’ve Learned ... 224
14. Contents • ix
8: Exploring User-Defined Functions 227
Function Versus Procedure: The RETURNS Property 227
Pick Your UDF Flavor 229
A Couple of Simple UDFs to Get You Started 230
Using Flow Control in a UDF 234
UDF Overloading 236
Testing the Get_Student_Id UDF 237
Time for Some Practice 239
A More Complex UDF: Calculating the Student GPA 239
Creating a Generic “Translation” Table ... 240
... And a Couple of Functions to Access It 240
Finding a Place for the Credit Hours per Class 243
Creating the Calculate_GPA UDF 245
Creating a Simple UDTF 250
Anatomy of a UDTF 250
Using a UDTF in a SELECT Statement 252
Writing More Complex UDTFs 253
Scheduled User Profile Review UDTF 253
Using a UDTF’s Data in Another UDTF: Introducing the User Review Report 260
In This Chapter, You’ve Learned ... 265
9: Making a Trigger-Happy Database 267
Introducing Database Triggers 267
What Triggers a Trigger? 268
Why Use Triggers? 269
SQL Triggers’Advantages 269
SQL Trigger Mechanics 270
A Simple Trigger Example 272
Testing Your First Trigger 273
Time for Some Practice 275
Exploring More Complex Trigger Scenarios 275
Using Triggers for Data Validation 276
Testing the Teacher Salary Update Check Trigger 278
Using Triggers for Auditing 279
Testing the Trigger 282
Using Triggers to Compose and Fill Columns 284
15. x • Contents
Using INSTEAD OF Triggers to Supercharge Views 287
Use Triggers with Care 295
Triggers Are Like Salt 295
In This Chapter, You’ve Learned ... 296
10: Moving Business Validations to the Database 299
Re-introducing DDL Constraints 299
Unique Constraints 300
Referential Constraints 302
Check Constraints 304
Enforcing More Complex Sets of Business Rules 306
Keeping the Teachers’Salaries in Check 306
Tidying Up the Personnel (Records) 311
Enforcing the “Informal” Integrity of the Courses Table 319
In This Chapter, You’ve Learned ... 322
11: Exploring the Database Catalog Information 323
Data About Data and the System Catalog 323
Where It All Starts: Tables 324
In This Chapter, You’ve Learned ... 336
12: Parting Gifts 339
The Personnel Contact Information Update Scenario 339
Creating a Table Based on a SELECT Statement 340
Anatomy of the MERGE Statement 341
A Quick-and-Dirty UPDATE-only Alternative to MERGE 346
Common Table Expressions 348
CTE Anatomy 348
A Simple CTE Example 349
Another CTE Example: Recreating the Student Grades Info View 351
Never Stop Learning! 355
Index 357
16. Why You Need This Book
At the core of the IBM i, beneath the ever-growing landscape of hardware features,
programming languages, and weird acronyms, lies its database: DB2 for i. This is the
machine’s most remarkable feature, a true differentiator that has kept the IBM i “modern”
and a step ahead of the competition for decades. Everything goes through the database,
from performance data to business data, in a uniquely integrated and seamless fashion.
It’s actually funny that the system’s most remarkable feature is often neglected by system
administrators, developers, and integrators. They simply ignore it or at least don’t take full
advantage of its power and versatility.
This book’s objective is to provide people with beyond-the-basics SQL knowledge and
the tools to get more out of the IBM i database. This means the book can be useful to
IBM i veterans who have RPG and COBOL roots, system administrators who are looking
to get more information out of the system, or even Java and .NET developers who need to
“talk” to the IBM i database.
How Can You Get More Out of the Database?
This journey begins with the very foundations of SQL, by recapping the data definition
and data manipulation SQL instructions, commonly referred to as DDL and DML.
However, SQL is not a theoretical “thing”: it’s used to manipulate real data. The
difference between this book and many SQL tomes is that every concept, example, and
technique will be applied to a close-to-reality database. The UMADB database serves an
application that is supposed to run a university. I say supposed to run because, as you’ll
see in a few pages, this database is poorly constructed and not very flexible. As the book
progresses, this database will be improved, chapter by chapter. Applying the techniques
17. 2 • SQL for IBM i: A Database Modernization Guide
explained in each chapter will result in a much better database that really takes advantage
of what DB2 for i has to offer.
The early chapters will recap DML and DDL, explore the system catalog, and help you
build a database that is friendlier to both users (for instance, through the use of longer and
descriptive column names) and programmers (with views, stored procedures, user-defined
functions, and triggers, to name just a few enhancements).
Since we’ve entered the database-design realm, there’s no harm in taking another step
and improving the database, by normalizing it. An entire chapter is devoted to the
database normal forms concept; here, again, the UMADB will be used as an example to
illustrate every concept and technique.
The next hot topic is making the database more business-aware, by moving as many
business rules and validations into it as possible. Why? Well, doing so solves a common
problem with IBM i installations: the database is dumb, simply a repository of data,
and the applications (usually “legacy” RPG or COBOL applications) handle all the
validations in often cryptic and huge blocks of monolithic code. The problem is that
more and more businesses are looking to integrate their core systems’ data (which sits
comfortably on an IBM i) with the rest of the business applications. These applications
are Web or mobile oriented and written using different, “modern” technologies that
connect directly to the database, not the “legacy” applications. If the database doesn’t
“know” the business rules, then the validations will have to be rewritten in new
technology—every single time. Naturally, moving business rules into a database requires
solid knowledge of a few concepts from the database-design realm, such as column-level
constraints, triggers, and referential integrity. Don’t worry, these concepts will all be
explained in depth and accompanied with plenty of examples, built over the UMADB.
After reading this book, I hope that you, dear reader, will also gain a more profound and
useful knowledge of SQL, particularly the “flavor” offered by the DB2 for i—whether
you’re a developer, system administrator, or an all-round “IT person.”
18. 1
Meet the UMADB: Our Example Database
This chapter introduces UMADB, a database for a university management
application. It’s important to have a notion of how this database is built—its flaws and
shortcomings—because I’ll be using it in almost every example in the book. UMADB
is in bad shape and will be improved throughout the book, by applying the concepts
discussed in each chapter.
Behind (almost) every application worthy of that name is a database. Some databases are
small, some are huge, some are simple, and some (I’d say most) are complex. In IBM i’s
world, they’re usually old, big, and confusing. Although our example database, UMADB,
is not very big (I downsized it for simplicity’s sake), it is also poorly built and can be
rather confusing to both programmers and users.
Let’s start with what this database should do. It supports a university management
application. This means it should manage student, teacher, class, course, classroom,
grade, and timetable records. In its current state, it kind of does, but with some room for
improvement. The UMA application, an “old-style” RPG application, should keep track
of the students’ academic lives: the classes they attended, the grades they received, and
so on. It should also keep track of classroom usage and timetables, for both students and
19. 4 • SQL for IBM i: A Database Modernization Guide
teachers. However, these last two tasks were deemed “too complex for the application”
by the application’s manager, and were left out of the database. In other words, these are
manual tasks, performed by the university administrative staff. This is one of the many
shortcomings of the application and its database.
There are plans to change the existing application, and we (you, dear reader, and I) are
part of them. We are going to improve the current database, which is basically a set of
DDS-defined physical files, by applying DB2 for i SQL techniques, tricks, and novel
features!
But first, you need to get to know the database in some depth. Let’s take a look at the
current database structure, table by table, starting with the Students table.
The Students Table
The Students table started with a simple student name column and grew to include other
pieces of data, as do many DB2 tables in real-life applications. However, the growth
was not planned properly (again, as in many real-life DB2 tables), and there are some
problems in this table, which might not be obvious at first. But we’ll get back to that later;
now let’s have a look at the actual table (Table 1.1).
Table 1.1: The Students table structure
Table Name Column Name Data Type Length Dec. Pos. Description
PFSTM STNM Char 60 Name
PFSTM STDB Decimal 8 0 Date of birth
PFSTM STAD Char 60 Home address
PFSTM STPN Char 15 Home phone number
PFSTM STMN Char 15 Mobile number
PFSTM STEM Char 60 Email address
PFSTM STDL Char 20 Driver’s license
PFSTM STSN Char 11 Social Security number
PFSTM STSC Char 1 Status
20. Chapter 1: Meet the UMADB: Our Example Database • 5
This looks just like most IBM i physical files I’ve seen: cryptically short file (or table)
and field (or column) names, concentrating a lot of information in a single row. The
columns are mostly unremarkable as well: the list includes student contacts (addresses
and phone numbers) and IDs (driver’s license and Social Security number).
There are a couple of eyebrow-raising features. First, the column that stores the date of
birth is a decimal with a length of 8,0, meaning that it’s a number, not a date. Note that
the database isn’t prepared to validate the content of the field—it’s just a number that
some convention says represents a date. Another noticeable “feature” is the absence of
the student’s record unique identifier. This identifier was deemed unimportant, because all
searches are done using the student’s name.
These flaws are just a couple of examples of textbook problems with IBM i tables: they
are, in a word, dumb. Even though it’s possible, for instance, to perform basic checks
like the validity of a date at database level, this and many other similar tasks are almost
always performed at application level, thus making the database a simple (and dumb)
repository of data. The same could be said about the absence of a record ID. The problem
occurs when there are other, non-native applications accessing and manipulating the data.
Without checks at the database level, it’s possible, and very likely, to insert rubbish into
the tables. Introducing those checks is actually very easy to do. Later in this book, you’ll
learn how to create validations that mimic (and can even go a step further and actually
replace) business rules that currently exist for RPG programs.
There’s something else wrong with this table, but it’s not obvious yet. We’ll need to go
over a couple more tables for you to see it. Let’s move on to the Courses table.
The Courses Table
Let me take a moment to explain the structure of the information in this database. The
students take classes, which are taught by teachers, and are part of courses. At the end of
each semester, the teachers grade the students in each of the classes they attended. This
may sound obvious and redundant, but it’s important to keep the structure in mind from
this point on. In a way, the Students and Courses tables are the center of the database,
because all the other tables are somehow linked to one (or both) of these tables.
21. 6 • SQL for IBM i: A Database Modernization Guide
Now let’s take a look at the Courses table structure, shown in Table 1.2.
Table 1.2: The Courses table structure
Table Name Column Name Data Type Length Dec. Pos. Description
PFCOM CONM Char 60 Course name
PFCOM CODS Char 100 Course description
PFCOM CODN Char 50 Department name
PFCOM CODE Char 60 Course director name
PFCOM COTA Char 60 Course teaching
assistant name
PFCOM COSC Char 1 Status
Again, the table is pretty typical: the same cryptic names and the lack of a unique record
identifier that characterized the Students table. By the way, I imagine that you’re curious
about the hidden flaw in the Students table, mentioned earlier. Don’t worry, it’s going to
become obvious in the next section, where we’ll look at the Teachers table.
Meanwhile, there’s something common to all the tables in this database: a status column.
As the name implies, it indicates the status of the record. The convention used here is the
following:
z
z 0—Created but not active record
z
z 1—Active record
z
z 9—Inactive (deleted) record
This is something that has to be taken into account when querying the database, and it
has been the source of many misunderstandings. Sometimes the users forget to include a
condition in their queries and end up mixing active and inactive records, which leads to
inconsistent or just plain wrong information.
The Teachers Table
The teachers are a very important part of any teaching system. They’re also a very
important part of the application our database supports, although the table that keeps their
records is not very “polished.” You’ll see what I mean when we analyze the Teachers
table, shown in Table 1.3.
22. Chapter 1: Meet the UMADB: Our Example Database • 7
Table 1.3: The Teachers table structure
Table Name Column Name Data Type Length Dec. Pos. Description
PFTEM TENM Char 60 Teacher name
PFTEM TETR Char 20 Teacher rank
PFTEM TEDB Decimal 8 0 Date of birth
PFTEM TEAD Char 60 Home address
PFTEM TEPN Char 15 Home phone number
PFTEM TEMN Char 15 Mobile number
PFTEM TEEM Char 60 Email address
PFTEM TEDL Char 20 Driver’s license
PFTEM TESN Char 11 Social Security number
PFTEM TEST Char 200 Subjects taught
PFTEM TESA Decimal 11 2 Salary
PFTEM TESC Char 1 Status
This table is similar to the previous ones, but it includes a sensitive piece of information:
the teacher’s salary. As things stand, anyone with access to the table can see how much
each teacher earns, which might not be a very good idea. I’ll get back to this later, when I
discuss how to hide a column’s data from prying eyes.
Notice the similarities between this and the Students table: the personal information
(addresses and IDs) is the same. Even though this makes sense—both teachers and
students are people and share the same type of information, it begs the question: what
if a student becomes a teacher, or vice versa? There will be duplicate and possibly
inconsistent information in the database. I’ll address this issue later, in the discussion
about database normalization and how that translates to SQL.
Having said that, let me take a moment to explain the other columns in the table. Besides
the obvious teacher name and the aforementioned personal information, this table also
includes a “teacher rank” (which can be something like Assistant Professor, Professor,
and so on) and a “subjects taught” column. The latter is supposed to link to the Classes
table, presented in the next section, but the connection is kept by humans, not the
database. Because the same person can teach multiple classes in the same school year,
the application’s manager thought it would be simpler to manually track the link between
teachers and classes—yet another shortcoming we’ll need to solve later.
23. 8 • SQL for IBM i: A Database Modernization Guide
It’s now time to move on to the next section and review the Classes table.
The Classes Table
Here’s where things start to get interesting: finally, a table with links to other tables.
The Classes table contains information about the students who form a class of a given
subject during a given year and the course to which the class belongs. As I said before,
the teacher is not part of the setup, at least not at database level. Table 1.4 shows the
complete Classes table structure.
Table 1.4: The Classes table structure
Table Name Column Name Data Type Length Dec. Pos. Description
PFCLM CLNM Char 60 0 Class name
PFCLM CLCY Decimal 4 0 Class year
PFCLM CLCN Char 60 0 Course name
PFCLM CLSN Char 60 Student name
PFCLM CLSA Char 60 Student home address
PFCLM CLSE Char 60 Student email address
PFCLM CLSC Char 1 Status
As you can see from this table, the links I mentioned before are based on the names
of the student and the course, which might cause some problems. The ideal situation
would be to have record identifiers in each of the tables and keep those IDs, instead of
the respective names, in the Classes table records. The next issue is the duplicate student
information. The application manager thinks this duplication makes sense, because
the student information might change from school year to school year, and keeping
the information here allows the teacher to contact the student using the most current
addresses. We’ll also have to deal with this situation later.
Finally, the last table of the downsized version of the UMADB database is the Grades
table. Let’s analyze it in the next section.
24. Chapter 1: Meet the UMADB: Our Example Database • 9
The Grades Table
After the end of the semester, the students are graded on their performance in each of
the classes they attended. The results are stored in the Grades table, shown in detail in
Table 1.5.
Table 1.5: The Grades table structure
Table Name Column Name Data Type Length Dec. Pos. Description
PFGRM GRSN Char 60 Student name
PFGRM GRCN Char 60 0 Class name
PFGRM GRCY Decimal 4 0 Class year
PFGRM GRGR Char 2 Grade
Just like the Classes table, this one also depends on another table’s information to form its
unique key. In this case, that key is formed by the student name, the class name, and class
year. Of these three, two are names stored in character strings. This makes them prone
to error (character fields usually make awful keys because of the possible mismatches
caused by different character cases—“John” is not the same as “john”, for example)
and slower to work with (because it takes longer to process a string of characters than
a numeric value). The other problem with this table is the Grade column: there’s no
validation in the database to prevent inconsistent values, such as invalid grades. It’s
assumed that the letters A, B, C, D, and F will be used, optionally followed by a plus/
minus sign, but there’s no actual check for a valid grade at the database level. Just like
the student’s date of birth validation, this one also exists at the application level, buried in
some RPG program.
Just a Few Tables, and So Many Problems
From what you’ve read so far, you probably concluded this (exaggerated) scenario has
some similarities with real-life issues in IBM i databases you’ve seen. Probably not all
at the same time, but you know what I mean. It’s true that some of the issues are very
basic and easy to solve, while others require some database redesign and ingenuity.
I’ll address all these issues and a few more, which are related to the non-implemented
functionalities that are currently handled outside the application’s scope, over the next
chapters of this book.
25. 10 • SQL for IBM i: A Database Modernization Guide
You can skip a chapter or two, but keep in mind that the database will evolve, and each
chapter will build upon the foundations laid by its predecessor. If you’re comfortable
with the topics discussed in a chapter, you can simply have a quick look at the SQL
code samples to keep track of the changes to the database. (You can download the code
samples and other supplementary book materials on the book’s page at https://www.mc-
store.com/products/sql-for-ibm-i-a-database-modernization-guide.)
Before starting in earnest, I’ll start by reviewing some SQL data manipulation language
(DML) statements and sharing a few tricks I’ve learned over the years that can, hopefully,
help you get more productive when it comes to manipulating data using SQL.
In This Chapter, You’ve Learned ...
The UMADB is a mess! Here’s why:
z
z The existing tables don’t have unique record identifiers, which makes the
connections between its tables weak, to say the least.
z
z There’s no data checking at database level, which can ... well, let me rephrase
that ... probably will cause inconsistencies in the data, such as invalid dates and
meaningless grades (yup, I’m talking receiving a G or a 24 as a final grade), just to
name a couple.
z
z The table and column names are short and cryptic, following the age-old IBM i
tradition, which makes querying the database rather user-unfriendly.
These issues will be addressed throughout the book, accompanied by the discussion of
the relevant underlying concepts.
26. 2
A Data Manipulation Language
Basics Recap
This chapter recaps the basic data manipulation language (DML) statements and
uses the sample UMADB database in all its examples. It will go over the SELECT,
INSERT, UPDATE, and DELETE statements. However, this chapter won’t discuss the
syntax of these statements. Here we will explain how you can write shorter and clearer
statements by resorting to a few keywords that you might not be aware of. If you want
to play around with the examples, be sure to restore the UMADB_CHP2 library from
the downloadable source code, at https://www.mc-store.com/products/sql-for-ibm-i-
a-database-modernization-guide.
I’m going to assume that you’re familiar with the most commonly used DML statements
and will not explain their syntax in depth. Instead, I’ll focus on some details that can
simplify the statements—for instance, shorter “implementations” of concepts.
Using the BETWEEN and IN Predicates
Let’s get started with a simple yet very powerful keyword. If you started querying the
IBM i’s database using Query/400 (as most of us did), one of the things you might miss
is the RANGE keyword. This simple-to-use tool allows you specify the lower and upper
limits of a range of values in a clear and concise way. What you might not know is that
27. 12 • SQL for IBM i: A Database Modernization Guide
SQL has a RANGE equivalent: BETWEEN. This keyword’s equally easy to use, but it has a
different syntax, which is closer to common English than the robot-speak of RANGE.
It’s easier to explain with an example, so let’s imagine that a user needs a list of all the
university students who were born in the 1990s. The knee-jerk reaction would be to write
something like this:
SELECT STNM
, STDB
FROM UMADB_CHP2.PFSTM
WHERE STDB >= 19900101
AND STDB <= 20000101
;
Even though this statement is correct (assuming that the student’s birth date, column STDB
of the PFSTM table, is in YYYYMMDD format), it can be made clearer with BETWEEN:
SELECT STNM
, STDB
FROM UMADB_CHP2.PFSTM
WHERE STDB BETWEEN 19900101 AND 20000101
;
Notice how using the BETWEEN predicate made the statement easier to read. By the way,
I’m a big fan of clear code, so you’ll see a lot of indentation in my code examples. It
makes the code easier to read and, more important, easier to maintain. For instance, if
I want to add a new column to the query, I simple add a new line wherever I need to
add it, and insert a comma followed by the column name. If all the columns are in the
same line, this might not be so simple, especially in queries with a lot of columns. The
only downside to this is that my queries tend to get a bit long. However, if you use IBM
Access Client Solutions’ Run SQL Scripts or any other non-native query tool (IBM
Rational Developer for i’s query tool, WinSQL, Toad, and so on), this is not a big issue.
All the examples shown here were written in Run SQL Scripts. You’ll notice the SQL
syntax with the period (.) separating the library (schema) and file (table) names, instead
28. Chapter 2: A Data Manipulation Language Basics Recap • 13
of the system’s native syntax with the slash character (/) acting as a separator between the
library (or schema) and the table, and the semicolon (;) terminating each statement.
Even if you knew BETWEEN, you might not know that you can invert the selection by
adding a simple keyword: NOT. Here’s an example to illustrate what I mean: the user
actually wanted a list of all the students who weren’t born in the 1990s. Well, let’s not
waste the statement we just wrote. Let’s modify it instead:
SELECT STNM
, STDB
FROM UMADB_CHP2.PFSTM
WHERE STDB NOT BETWEEN 19900101 AND 20000101
;
See how with a very simple change you can get the exact opposite result of the
original query? You can use NOT in all sorts of ways to easily negate a comparison. It’s
particularly useful when the opposite of a comparison is complex to write down. Instead,
you can simply write NOT (original comparison), and you’re done. I’ll provide additional
examples in a moment.
Another tedious and error-prone situation is when you want to find all the records that
have one of several values in a given column. For instance, let’s say that someone wants
a list of all the teachers with the rank of Dark Master, Maximus Praeceptor, or Praeceptor.
(Yes, the Teachers table is a bit quirky—actually, the entire database is! Take a moment
to query the tables, and you’ll see what I mean.) In Query/400 you’d use LIST, but I’ve
noticed many people still write the comparison statement using something like this:
SELECT TENM
, TETR
FROM UMADB_CHP2.PFTEM
WHERE TETR = 'Dark Master'
OR TETR = 'Maximus Praeceptor'
OR TETR = 'Praeceptor'
;
29. 14 • SQL for IBM i: A Database Modernization Guide
Instead of using LIST’s SQL equivalent IN keyword:
SELECT TENM
, TETR
FROM UMADB_CHP2.PFTEM
WHERE TETR IN ('Dark Master', 'Maximus Praeceptor', 'Praeceptor')
;
Naturally, you can also use NOT to quickly list all the teachers who don’t hold one of
these ranks:
SELECT TENM, TETR
FROM UMADB_CHP2.PFTEM
WHERE TETR NOT IN ('Dark Master', 'Maximus Praeceptor',
'Praeceptor')
;
I’ve shown examples of BETWEEN using numeric values and IN using character values,
mainly because this is their most common use. Keep in mind, though, that you can use
these SQL predicates with any types of values and in any SQL clause that requires the use
of a comparison, in addition to the WHERE clause.
Joining Tables
Listing the contents of a table, even with comparisons (or search conditions) that limit the
output, as shown in the previous section, is a bit limited in a real-life situation. Typically,
our queries are built using information from multiple tables. I’ll go through almost all the
ways you can join tables in SQL; I’ll leave a special type of join, called EXCEPTION JOIN,
for later. Let’s start with the simplest of them all: the INNER JOIN.
The JOIN You’ve Been Using Without Realizing: INNER JOIN
The INNER JOIN is arguably the most-used type of join. Actually, you’ve probably been
using it without realizing it, because it can be hidden in the WHERE clause, in what is
commonly called an implicit join.
30. Chapter 2: A Data Manipulation Language Basics Recap • 15
For instance, let’s say you want to list all the students who have enrolled in at least one
class. This is a complete intersection between the Students and Classes tables—a classic
INNER JOIN (even though it could be simply a SELECT over the Classes table because it
contains the student name—but let’s ignore that for the moment, because it will be useful
to illustrate another type of join). We know, from the previous chapter, that the link
between the PFSTM (Students table) and the PFCLM (Classes table) is the student name.
It’s true that it’s not a brilliant solution, but we’ll have to live with it—for now. An SQL
statement that lists all the students that have, at any given point, enrolled in a class is
often written using an implicit join, like this:
SELECT STNM
, CLNM
, CLCN
FROM UMADB_CHP2.PFSTM ST, UMADB_CHP2.PFCLM CL
WHERE CL.CLSN = ST.STNM
;
However, if there are more than two tables in the SELECT statement, things might get
a little hazy. That’s why I think it’s much clearer to write the same statement using an
INNER JOIN:
SELECT STNM
, CLNM
, CLCN
FROM UMADB_CHP2.PFSTM ST
INNER JOIN UMADB_CHP2.PFCLM CL ON CL.CLSN = ST.STNM
;
If you’re familiar with the INNER JOIN syntax, there’s really nothing new for you here—
perhaps the use of aliases for the tables (ST and CL), which make the statement slightly
more readable. However, if you’re used to the implicit join instead, there are a couple
of things worth mentioning. First, notice how the line following the FROM clause starts
with the join type: in this case it’s an INNER JOIN, but there are others, as you’ll see in a
moment. The type of join identifier is then followed by the table name (and optionally,
31. 16 • SQL for IBM i: A Database Modernization Guide
an alias), which in turn is followed by the ON keyword. This keyword is used to specify
how the connection between the tables is supposed to work. In this case, the link between
the Students and Classes tables is achieved via the student name, but it could be a more
complex condition, resorting to multiple columns.
Let me close this section with a more complete example that uses multiple INNER
JOINs to link all the tables of our sample database. The objective is to obtain a bit more
information about a student’s grades and the classes he or she attended. Here’s the
statement:
SELECT STNM AS STUDENT_NAME
, CONM AS COURSE_NAME
, CODE AS COURSE_DIRECTOR
, TETR AS TEACHER_RANK
, CLNM AS CLASS_NAME
, CLCY AS CLASS_YEAR
, GRGR AS GRADE
FROM UMADB_CHP2.PFSTM ST
INNER JOIN UMADB_CHP2.PFCLM CL ON ST.STNM = CL.CLSN
INNER JOIN UMADB_CHP2.PFGRM GR ON GR.GRCN = CL.CLNM
AND GR.GRCY= CL.CLCY
AND GR.GRSN= ST.STNM
INNER JOIN UMADB_CHP2.PFCOM CO ON CO.CONM = CL.CLCN
INNER JOIN UMADB_CHP2.PFTEM TE ON TE.TENM = CO.CODE
WHERE GRSN = 'Anthony, Mark'
;
Even though the statement is a bit longer than the previous examples, it’s a simple
SELECT. The difference is that it uses many more tables, which can make it confusing
really quickly. I’d like emphasize the importance of indentation to improve the
statement’s readability and the use of user-friendly column names. Also note that I’ve
used aliases for all the tables. At this time, the aliases are not critically important, because
the column names all identify the name of the table to which they belong. Later in the
book, I’ll show you how to “get the best of both worlds” by providing long, human-
32. Chapter 2: A Data Manipulation Language Basics Recap • 17
readable names and keeping the short “RPG-standard” cryptic names that currently exist.
Then you’ll see that making a habit of using aliases for the tables and using them when
referring to columns in your statements is of paramount importance to the readability and
maintainability of your code.
Start Joining Tables Left and Right
I bet you have already used INNER JOIN. Now imagine that the user asks you to modify the
query, so that all registered students, regardless of whether or not they have taken a class,
are listed. But the user still wants to know which classes the students took. Although it’s
very similar to the previous query, it is not simply an intersection between the tables.
Nope, this time you’ll have to include all the records from the first table (Students) and
the records from the second table (Classes) that have matching student names. Instead of
first and second tables, let’s call them left and right tables, respectively. You now need all
the records from the left table plus the ones that intersect with the right table, as depicted
in Figure 2.1.
Figure 2.1: A LEFT JOIN between the Students and Classes tables
Let’s see how this translates to SQL lingo:
SELECT STNM
, CLNM
, CLCN
FROM UMADB_CHP2.PFSTM ST
LEFT JOIN UMADB_CHP2.PFCLM CL ON CL.CLSN = ST.STNM
;
33. 18 • SQL for IBM i: A Database Modernization Guide
The only difference in the statement is the LEFT JOIN instead of INNER JOIN, but the result
set tells a slightly different story: a student record was omitted from the previous result
set because it doesn’t have a match in the Classes table, which now appears, even though
it has incomplete information. The class and course name columns (CLNM and CLCN,
respectively) display a “no data available” sign (a dash, or -) instead of the expected
contents. The - sign indicates NULL.
Similarly, if the request were to list all the records from the Classes table (the right table)
plus the matches on the Students table (the left table), you’d use a RIGHT JOIN. Visually, a
RIGHT JOIN looks very much like the previous figure, but with the table roles reversed, as
depicted in Figure 2.2.
Figure 2.2: A RIGHT JOIN between the Students and Classes tables
As you’d expect, the SQL statement is also very similar to the previous one:
SELECT STNM
, CLNM
, CLCN
FROM UMADB_CHP2.PFSTM ST
RIGHT JOIN UMADB_CHP2.PFCLM CL ON CL.CLSN = ST.STNM
;
The result will be the same as the INNER JOIN, but only because there are no records in the
classes table that don’t have a match in the students table.
34. Chapter 2: A Data Manipulation Language Basics Recap • 19
“Just Get Me Everything”: FULL JOIN
So far, I’ve shown you how to select the matching records between two tables, then add
to that all the records from the left table, and finally, add to that all the records from
the right table. As you’ve probably guessed, there’s also a type of join that includes
everything from both left and right tables: it’s the FULL OUTER JOIN, or FULL JOIN, for
short:
SELECT STNM
, CLNM
, CLCN
FROM UMADB_CHP2.PFSTM ST
FULL JOIN UMADB_CHP2.PFCLM CL ON CL.CLSN = ST.STNM
;
In this case, you’re selecting everything from both tables, which might not be a good
idea. But who knows, maybe it can be useful in a particular situation? This example
selects students with or without classes, plus classes with or without students.
A Join Summary
Even though this joining business is not complex with two tables, it’s important to fully
understand it. Database relations can get pretty complicated, and being able to join two or
more tables correctly might save you some time. Figure 2.3 offers a summary of the join
types discussed thus far:
35. 20 • SQL for IBM i: A Database Modernization Guide
Figure 2.3: A join summary
Later I’ll revisit this topic, to explain what happens when the value of columns used to
link the tables (also known as key columns) is null. The next section will return to single-
table queries to explore a few SQL functions. I’ll stick to the most commonly used ones,
but there are many more, with varying degrees of complexity.
My book, Evolve Your RPG Coding: Move from OPM to ILE … and Beyond (https://www
.mc-store.com/products/evolve-your-rpg-coding-move-from-opm-to-ile-and-beyond) has a
very comprehensive chapter about most of the SQL functions (and a lot more basic SQL
stuff).
A Handful of Column Functions
SQL’s many functions are incredibly useful and can save you a lot of time. However,
they can also be the cause of major headaches, so you need to understand and use them
correctly. I’ll go over a few of these functions now and explore a few more later in the
book. Let’s start with everybody’s favorite: the COUNT function.
36. Chapter 2: A Data Manipulation Language Basics Recap • 21
The COUNT Function
We’ve all used it, more times than we can count. It’s the simplest way to determine how
many records will be included in a query (unless you specify a FETCH FIRST clause).
If you aren’t familiar with FETCH FIRST, don’t worry, because I’ll cover it in several
chapters. Here is a textbook example of the use of COUNT: to count the number of rows in
the Students table:
SELECT COUNT(*)
FROM UMADB_CHP2.PFSTM;
COUNT(*) includes rows even if they contain NULL values. COUNT(expression) excludes
NULL values from the count.
The interesting thing about COUNT that you might not know is that you can use it in
conjunction with other functions. Next I’ll talk about finding the minimum and maximum
values of a column and then show you an example that includes all three functions.
Finding the Minimum and Maximum Values of a Column
In a high-level programming language, finding the minimum or maximum value of
a given column typically requires cycling through the whole table and storing the
minimum/maximum value in a temporary variable that gets updated whenever the last
record read contains a relevant column value. In SQL, it’s a column function that you can
use in a SELECT statement column list or, not as commonly done but also possible, in a
HAVING clause. By the way, I’ll also discuss the HAVING clause later, just in case you’re
not familiar with it. Here’s how to determine the minimum and maximum salaries of the
university’s teachers:
SELECT MIN(TESA) AS MIN_SALARY
, MAX(TESA) AS MAX_SALARY
FROM UMADB_CHP2.PFTEM
;
37. 22 • SQL for IBM i: A Database Modernization Guide
This example has two very interesting elements: it shows that you can use different
column functions together, and it also addresses a typical problem that derives from
the use of any column function: the name of the column. If you run the same statement
without the “AS xxxx” bits, you’re still going to get correct results, but unless you
remember which is which when you’re analyzing the data (OK, in this case it should be
obvious, but bear with me), they’re going to be pretty useless because the columns will
be named 00001 and 00002, respectively. What I’m getting at is that it’s important to
use aliases for your columns whenever you use a function or any other expression, such
as a string concatenation or an arithmetic expression, so that its contents are obvious to
whoever is looking at the output data. Speaking of arithmetic expressions, the functions
I’ve presented so far can work with numbers and characters alike, but the last two of my
examples only work on numbers.
Sums and Averages Made Easy
As in the minimum/maximum scenario, summing up a column of values or finding its
average in a high-level programming language requires some work, but in SQL there’s
a column function that does that for you. Let’s start with the one you’ve probably used
before:
SELECT SUM(TESA) AS TOTAL_SALARIES
FROM UMADB_CHP2.PFTEM
;
This statement returns the sum of the teachers’ salaries and can be used in conjunction
with other column functions without any problems. However, if you try to sum the
teachers’ ranks, a non-numeric column, the database engine will return the SQL0402 error
message, which explains that you can “only” use INTEGER, SMALLINT, BIGINT, DECIMAL,
ZONED, FLOAT, REAL, DOUBLE (or DOUBLE_PRECISION), and DECFLOAT data type values
as an argument to the SUM function. If you have a numeric value stored in a character
column, you can try to use the DIGITS function to convert it to a number and then
calculate the sum. Something like SUM(DIGITS(YOUR_CHARACTER_FIELD)) should work, as
long as the values of the character column are convertible to numeric format. Similarly,
you can calculate the average of numeric values, and the same rules apply.
38. Chapter 2: A Data Manipulation Language Basics Recap • 23
However, the AVG function can have an unpleasant side-effect that is also often
misleading for the end user: its precision. Let’s run a quick example to illustrate this
problem. You can calculate the average salary of the teachers, with the following
statement:
SELECT AVG(TESA) AS AVERAGE_SALARY
FROM UMADB_CHP2.PFTEM
;
If you run a full SELECT of the table and calculate the average yourself,
you’ll see that this output value is accurate and perhaps even too accurate
(138333.3333333333333333333333) for the end user. After all, the user is expecting an
amount, which usually means a number with two decimal places, not a huge train of 3s
that can be confusing. I chose this example because it allows me to introduce another
column function that is akin to the DIGITS function on steroids.
The Shape-shifting CAST Function
While DIGITS allows you to convert a character string into its numeric value, it doesn’t
allow you to be very specific about the number of decimal places of the number. It’s true
that there are other conversion functions that you can use, depending on your specific
need, such as BIGINT, BINARY, BLOB, CHAR, CLOB, and DATE, to name just a few. But the
beauty of the CAST function is that it can do the same as all the others and allow you to
specify the number of decimal places.
Let’s revisit the SQL statement that returns the average salary and modify it, in order to
return a user-friendly amount instead of that awful number:
SELECT CAST (AVG(TESA) AS DECIMAL (11, 2)) AS AVERAGE_SALARY
FROM UMADB_CHP2.PFTEM
;
What’s going on here? Well, it’s a function within another function: AVG(TESA) calculates
the average of the salaries, just like before, but then the CAST function that encloses it
39. 24 • SQL for IBM i: A Database Modernization Guide
converts the ugly numeric result returned by the AVG function into a DECIMAL(11, 2). I’ve
used CAST in many different scenarios—from “data beautification,” as in this case, to
situations in which different tables that share a key don’t have the key fields in the same
format or even data type. CAST is indeed a powerful tool, and I prefer its readability when
it comes to specifying the output data type over the aforementioned conversion functions.
Aggregating Data with GROUP BY
User requests often require little more than a regular SELECT statement, but standardized
reports usually include aggregated information obtained with some of the column
functions I’ve mentioned before. Let’s say the university’s board wants to know the
average salary by teacher rank and how many teachers are in each of these ranks. So far,
the column functions used included a single piece of data, like a count or an average, or
at most, two functions combined. To answer this question, we’ll need to list the teacher
rank, which is a column of the teachers table, and two functions (a count of the teachers
per rank and their average salary).
My guess is that you already figured out how to write this statement, based on what I’ve
shown before. However, if you try to run this statement without a GROUP BY clause, it
will end in error. Why? Well, because you’ll be trying to aggregate data (by using the
functions) and display all the records at once (the teachers’ ranks). That’s where the
GROUP BY clause comes into play: it allows you to, well, group information by a given
expression—typically a column of the select list. If you’re having trouble following my
train of thought, take a moment to analyze the following statement:
SELECT TETR AS TEACHER_RANK
, CAST (AVG(TESA) AS DECIMAL (11, 2)) AS AVERAGE_SALARY
, COUNT(TETR) AS NUMBER_OF_TEACHERS
FROM UMADB_CHP2.PFTEM
GROUP BY TETR
;
This is the magic of GROUP BY: you can use quite a few column functions and present
sectioned results. Even though I’m only using one column in the GROUP BY clause, it’s
possible to use as many as you want or even more complex grouping expressions, which
40. Chapter 2: A Data Manipulation Language Basics Recap • 25
can resemble a Microsoft Excel pivot table (presenting both the grouped rows and the
subtotals)—more about that later.
The Two Flavors of INSERT
Most programmers are familiar with the INSERT SQL statement, and some (including
myself) prefer it to Data File Utility (DFU), because it’s reproducible, controlled, and
most important, easy to track. It’s true that you can save all those spool files produced by
DFU somewhere, but it’s not easy to re-input or even reuse inputted data. With INSERT,
a simple copy-paste-adjust operation is all it takes to add a second or third record that
shares some similarities with the original statement.
Vanilla INSERT: Plain, Simple, and Kind of Boring
You’re certainly familiar with the “insert one record with these values” INSERT statement.
What you might not know is that there are some tweaks you can introduce into the most
basic form of the INSERT statement. Let’s say I want to add a course to the Courses table.
There are two ways to do this: you can either specify which columns you’ll be providing
values for and what those values are, or simply specify a list of values. Here’s an example
of creating a new course with the two alternatives, starting with the longer of the two:
INSERT INTO UMADB_CHP2.PFCOM
(CONM, CODS, CODN, CODE , COTA, COSC)
VALUES(
'Advanced Trickery'
, 'This course will help you take your trick-or-treat Halloween
tricks to the next level!'
, 'Manual Crafts'
, 'The Joker'
, 'Dennis the Menace'
, '1'
)
;
41. 26 • SQL for IBM i: A Database Modernization Guide
Note that I’m providing values for all the columns. If I hadn’t, then the default value
for the column (zero for numeric columns and '' for the character fields) would be used.
I’ll show you later how this can be customized via Data Definition Language (DDL).
However, because I’m providing all the necessary information, I can omit the column
names, like this:
INSERT INTO UMADB_CHP2.PFCOM
VALUES(
'Advanced Trickery'
, 'This course will help you take your trick-or-treat Halloween
tricks to the next level!'
, 'Manual Crafts'
, 'The Joker'
, 'Dennis the Menace'
, '1'
)
;
Even though this second option is shorter (which makes it rather tempting to use), I favor
the longer version, for two reasons:
z
z Clarity—the lists of column names and their matching values unambiguously
state “what goes where” when the record is inserted. Also, you’re not bound to
the order by which the columns appear in the table record. The columns might be
alphabetically ordered, but you want to start your statement with the columns that
form the record’s unique key and then fill in the rest of the data. With the shorter
version, this is simply not possible, because you have to stick to the order of
columns imposed by the table definition.
z
z Reusability—Even if new columns are added to the table, the longer INSERT
statement will still work as expected, regardless of the position of the new columns
in the table. With the shorter version, this might not be true, unless you always add
the new columns after the last existing column of the record. Note, however, that if
the values for the new columns are not specified, they’ll be filled with the default
value, which is not always a good option.
42. Chapter 2: A Data Manipulation Language Basics Recap • 27
Strawberry (or Whatever Your Favorite Ice Cream
Flavor Is) INSERT
My guess is that you’re used to the “vanilla” INSERT and use it regularly. However, there
are situations, such as copying a group of records from a table to another, in which you
fall back to the CPYF (Copy File) CL command. This command is nice and simple, but it
falls short when you don’t want all the records from the original table to be copied to the
destination table. Yes, you can use the FROMRCD/TORCD or FROMKEY/TOKEY keywords to
limit the records being copied, but it’s still a bit cumbersome.
This second flavor of INSERT (sorry about the lame section title; I’m a big fan of
strawberry ice cream) allows you to selectively copy records. The best part is that you
can list the records you’ll be copying easily: using a SELECT statement. Interested? Let me
explain how it works with an example.
The university managed to resurrect two reputed scholars—Max Planck and Albert
Einstein—to teach a summer course on physics. They need to be added to the Teachers
table, which would typically be a manual insertion operation performed by the
administrative staff. However, someone secured a copy of the relevant data and uploaded
it to a temporary table, named PFTEMP_TEM, which happens to have almost the exact same
format as the Teachers table. It’s missing only the status column. Let’s see how you could
copy its data to the Teachers table with an INSERT statement:
INSERT INTO UMADB_CHP2.PFTEM
SELECT TMP.*, '1'
FROM UMADB_CHP2.PFTEMP_TEM TMP
;
Notice the simplicity of the statement: with just a few lines, I copied all the data from
one table to another and added the missing information. An INSERT with a nested SELECT
statement is a powerful tool because the flexibility of the SELECT statement allows you
to tailor the original data to the destination table, by changing its format; translating
information (for instance, it’s possible to translate a percentage to the respective letter
grade, as you’ll see later); and surgically selecting which records to copy. For instance,
if PFTEMP_TEM had a different column arrangement (a different number of columns or
43. 28 • SQL for IBM i: A Database Modernization Guide
simply a different order), you’d just change the SELECT clause to match the destination
table’s column order.
Data Adjustments with UPDATE
“Data adjustments” is a nice euphemism for those times when you have to get your
hands dirty changing data at a very low level. A lot of programmers I know use DFU
exclusively for these tasks, but I prefer to use SQL. The UPDATE instruction allows
multiple, finely targeted, and reproducible changes to a group of records, while DFU can
only act upon a record at a time. This flexibility is often the reason why some people
don’t like to use UPDATE: if you aren’t careful, you might end up updating more than you
wanted (or the whole table) with one incorrect UPDATE statement. That’s why I always
follow a methodology for my updates:
z
z Run a SELECT with the UPDATE record selection conditions in the WHERE clause.
z
z Double check the SET clause, either visually, if it’s a simple change, or on the
SELECT column list of a SELECT statement.
z
z Run the UPDATE statement.
z
z Extra step: if there’s a risk of something going wrong with a large UPDATE, perform
it under commitment control.
Let’s see this in action with an example from our sample database. In the previous
section, I inserted two new teachers into the Teachers table: Max Planck and Albert
Einstein. However, the original data had a typo. The teacher rank was incorrect: the
teacher rank of these two records currently reads “Profesor Emeritus” instead of
“Professor Emeritus”. Oops. Let’s correct that mistake, following the steps mentioned
before:
SELECT TENM
, TETR
FROM UMADB_CHP2.PFTEM
WHERE TENM in ('Planck, Max', 'Einstein, Albert')
;
44. Chapter 2: A Data Manipulation Language Basics Recap • 29
In this case, the change is minimal, and a visual check suffices, so I’m ready to run the
UPDATE:
UPDATE UMADB_CHP2.PFTEM
SET TETR = 'Professor Emeritus'
WHERE TENM in ('Planck, Max', 'Einstein, Albert')
;
You can also use UPDATE in slightly more complex scenarios, such as updating multiple
columns at once or even using the current value of a column to calculate its new value.
For instance, let’s say the university wants to cut the teachers’ salaries by 10 percent.
With a single UPDATE statement, you can enforce this (probably unpopular) decision:
UPDATE UMADB_CHP2.PFTEM
SET TESA = TESA * 0.9
WHERE TESC = '1'
;
Note that in this case, I’m only updating the active records (TESC = '1').
As I said before, it’s possible to update multiple columns at once and even use the same
column as the updater and the updated. For instance, you can update column A with the
value of column B and, in the same statement, also update the value of column B with
something else. You just need to carefully pick the order of the changes in the SET clause,
as they’ll be executed by the order in which you write them. Here’s a generic example:
UPDATE TABLE_XX
SET COL_A = COL_B, COL_B = 0
WHERE COL_X = '123'
;
45. 30 • SQL for IBM i: A Database Modernization Guide
I’ll revisit the UPDATE instruction, to share a few tricks later in the book. Now it’s time to
discuss the last DML instruction of this chapter: DELETE.
DELETE: A Blessing and a Curse
I’m one of those programmers who doesn’t like to (permanently) get rid of information.
I’m not a hoarder, I just know that when someone asks me to delete something from a
database, there’s a good chance that, at some point in the future, they’ll want that piece
of data back. So, I’m a big fan of the soft delete: keeping the information exactly where
it was, but with a different status to indicate that it’s been “deleted” (or inactivated, if
you will), thus indicating that it shouldn’t be used by the application. However, there
are times when you really have to get rid of stuff. For those situations, I still prefer a
controlled way of deleting information. All of this to tell you a bit more about the DELETE
instruction.
I assume you know the basic syntax of DELETE, and you’ve used it before to clear a table
with the classic DELETE FROM <table_name>. However, I can’t stress enough that you
should be EXTREMELY careful when you use DELETE. There is no undo. And if you
forget the WHERE clause or make a mistake in it, you run the risk of clearing the entire
table, just like a CLRPFM (Clear Physical File Member) CL command would! That’s why
I consider the DELETE to be both a blessing and a curse: it can save you a lot of time—or
cost you a lot of time, depending on how you use it. Just as with an UPDATE statement, I
heartily recommend that you try a SELECT statement using the WHERE clause before you
do a DELETE, just to make sure it works like you expect it to. In other words, the same
methodology I mentioned before applies here:
1. Run a SELECT with the DELETE record selection conditions in the WHERE clause.
2. Double check everything before actually running the DELETE statement.
3. Run the DELETE statement (and pray you didn’t botch it because there’s no way
back—except for restoring a backup, if you have one).
4. Extra step: if there’s a risk of something going wrong with a large DELETE, perform
it under commitment control.
Here’s an example of a controlled DELETE, which will also use all the other SQL
instructions discussed in this chapter. Let’s say I want to reuse the temporary teacher
table mentioned before, PFTEMP_TEM, for enrolling additional teachers, and one of them
46. Chapter 2: A Data Manipulation Language Basics Recap • 31
will also teach Advanced Quantum Mechanics and is from Germany, like Professor
Max Planck. I could simply clear the table by using a CLRPFM CL command or a DELETE
statement without a WHERE clause and then insert the new data. However, because there
are no unique IDs in the table, I can reuse the good professor’s record and type a little
less. In other words, I can update an existing record and save some time. So, here’s what
I’m going to do:
1. I’ll delete everything from the PFTEMP_TEM table except Professor Max Planck’s
record:
DELETE
FROM UMADB_CHP2.PFTEMP_TEM
WHERE TENM <> 'Planck, Max'
;
2. Insert the new teachers’ records (I’ll just insert one, for brevity’s sake):
INSERT INTO UMADB_CHP2.PFTEMP_TEM
(TENM, TETR, TEDB, TEAD , TEPN, TEMN,
TEEM, TEDL, TESN, TEST, TESA)
VALUES(
'Feynman, Richard'
, 'Professor Emeritus'
, 19180511
, 'USA'
, 'N/A'
, 'N/A'
, 'N/A'
, 'N/A'
, 'N/A'
, 'Quantum Electrodynamics'
, 100000.0
)
;
47. 32 • SQL for IBM i: A Database Modernization Guide
3. Update Professor Max Planck’s record with the necessary changes:
UPDATE UMADB_CHP2.PFTEMP_TEM
SET TENM = 'Schrodinger, Erwin'
, TETR = 'Professor Emeritus'
, TEDB = 18870812
WHERE TENM = 'Planck, Max'
;
4. Finally, insert the new data into the Teachers table:
INSERT INTO UMADB_CHP2.PFTEM
SELECT TMP.*, '1'
FROM UMADB_CHP2.PFTEMP_TEM TMP
;
In This Chapter, You’ve Learned ...
z
z A few tricks you can use in WHERE clauses, like the BETWEEN and IN predicates.
These can help clarify and simplify future maintenance of complex SQL
instructions. I also mentioned how to use the NOT operator and provided a couple
of examples.
z
z How you can join tables and what the implications of those joins are in the output
data. Particularly relevant to this topic is Figure 2.3, which provides an overview of
the join types.
z
z There are a few handy functions to perform the most basic data aggregation
operations: COUNT, SUM, calculate the AVeraGe, and find the MINimum and
MAXimum values of a column (I’ve written the names of the functions in upper
case, for brevity’s sake).
z
z Some of these operations produce unexpected (let’s called them “over-precise”)
results that don’t sit well with the end user, and there’s a nice function to change
the data type of a piece of data into another type: the CAST function.
48. Chapter 2: A Data Manipulation Language Basics Recap • 33
z
z It’s possible to use the aggregation functions with non-aggregated data, as long as
you use the GROUP BY clause.
z
z There are two “flavors” of UPDATE, and how to use the “strawberry-flavored
UPDATE” to insert multiple records at once.
z
z How to update multiple columns with one statement and even use a column to
update another, while changing the first column’s contents on the same update.
z
z How to safely use the UPDATE statement, by using a simple methodology.
z
z Finally, how to apply that same methodology to the DELETE instruction and avoid
wasting time cleaning up messes that could have been avoided.
The next chapter will be the last “warm-up” chapter and will recap the basics of DDL,
while offering some insights, much as this chapter has done.
50. 3
A Data Definition Language Basics Recap
Just as the previous chapter recapped Data Manipulation Language (DML) basics, this
one does the same for Data Definition Language (DDL). The main DDL instructions
(CREATE, ALTER, and DROP) and objects (TABLE, VIEW, and INDEX) will be discussed.
However, the discussion won’t focus on their syntax but will instead cover how to
convert physical files to SQL tables and how to create self-managing unique keys.
Chapter 2 reviewed the main DML instructions and showed sample statements built over
the UMADB database. Well, calling it a database at this stage is stretching the truth a bit:
UMADB is just a set of physical files, not actually linked to each other at database level.
Instead, they share some common string fields that work as keys at the application level.
Converting UMADB’s Physical Files to SQL Tables
The first step in transforming UMADB from an amalgamation of files into a coherent,
organized database is to convert the physical files into proper SQL tables, with all the
bells and whistles. There are several ways to do this. For instance, you can type the
complete CREATE TABLE statements by hand—not very efficient, but it gives you practice
with the CREATE TABLE statement. But we’re not going to do that! We’re going to take a
shortcut and use a nifty feature of IBM Access Client Solutions’ (ACS) Run SQL Scripts:
the Generate SQL option. (In the examples here, I use System i Navigator, but the
instructions will also work with more recent versions of the product.)
51. 36 • SQL for IBM i: A Database Modernization Guide
In order to do that, let’s fire up System i Navigator (ACS), expand the My Connections
handle (it sits in the left sidebar of the window). Then we’ll expand the Databases handle
and its sub-handle with the system’s name on it. Finally, let’s click Schemas. Something
similar to what’s shown in Figure 3.1 should be displayed.
Figure 3.1: System i Navigator(ACS) database schemas
The list of schemas shown at the right side of the screen will vary, but there’s a high
probability that the one you want, UMADB_CHP2 (assuming you downloaded and restored
to your IBM i the save file containing this library from Chapter 2’s downloadable source
code), is not displayed. Let’s fix that. In the bottom right pane of the window, under
Database tasks, there are several options. The first one from the top is Select schemas to
display. If you click that option, you’ll see something resembling Figure 3.2.
52. Chapter 3: A Data Definition Language Basics Recap • 37
Figure 3.2: Adding the UMADB_CHP2 schema to the schemas to display
In order to add UMADB_CHP2 schema to the schemas to display panel, you have two
options: you either type the library (or schema) name in the box in the top left corner of
the window, or you click Search for schemas:. If you choose the latter, it’s possible to
refine your search by entering part of the schema’s name followed by the percent (%)
character and clicking the Search button. After any of these options, you simply click the
Add -> button, followed by OK.
This closes the window, and you’ll now see the UMADB_CHP2 schema in the schema’s
list in the left sidebar. Let’s expand the UMADB_CHP2 database folder and click Tables.
You’ll see something similar to Figure 3.3, without the context menu—I’ll get to that in a
second.
53. 38 • SQL for IBM i: A Database Modernization Guide
Figure 3.3: Expanded UMADB_CHP2 schema, showing the list of tables
To get exactly what’s shown in Figure 3.3, you’ll need to right-click a table. This opens a
context menu; I’ll explore a few of the options on this menu later. For the moment, let me
just focus on the Generate SQL… option. What does it do? Well, IBM can come up with
some very obscure names for things sometimes, but in this case, there’s no doubt: this
option generates the SQL code required to create the selected object.
Note that there are things that are possible in DDS that SQL can’t do, and vice-versa. As
you’ll find out in a moment, the output of this option will list the things it can’t convert
to SQL. But first, let’s generate the SQL statements for all the tables in the UMADB_CHP2
schema. Try selecting all the tables, pressing the right mouse button, and choosing the
Generate SQL… option. You should see something resembling Figure 3.4.
54. Chapter 3: A Data Definition Language Basics Recap • 39
Figure 3.4: Generating SQL for multiple tables
Here you can save the generated SQL statements to a source file or open a new Run SQL
Scripts window instead. I prefer this last option because it’s easier to inspect and change
the statements in a non-native SQL tool, so let’s leave the selection as it is (the default
should be Open in Run SQL Scripts) and click OK.
CREATE TABLE Fundamentals
If everything went according to plan, you should see a new Run SQL Scripts window
with the generated SQL code for the tables’ creation. Let’s analyze the PFSTM’s CREATE
TABLE statement:
CREATE TABLE UMADB_CHP2.PFSTM (
-- SQL150B 10 REUSEDLT(*NO) in table PFSTM in UMADB_CHP2 ignored.
STNM CHAR(60) CCSID 37 NOT NULL DEFAULT '' ,
STDB DECIMAL(8, 0) NOT NULL DEFAULT 0 ,
STAD CHAR(60) CCSID 37 NOT NULL DEFAULT '' ,
Continued
56. During his last visit to Boston, he had been introduced to a Mrs.
Webster, who resided in the vicinity of that city. Mrs. Webster had an
only son, who was heir to a property which had accumulated, during
his long minority, to a fortune unusually large; and she had long
resolved in her mind that the young heir should be the husband of
Mary Bryarly; and so adroitly had she manœuvered, that the parties
had been thrown constantly together previous to the appearance of
Mr. Thatcher. Even her son almost considered it a matter of course
that he was to marry her. Mary, not conscious of these machinations,
regarded young Webster as a youth of high promise, and treated
him as an especial favorite. Mrs. Webster soon discovered that the
presence of Harry threatened destruction to all her plans—so she
determined to destroy his power, even at the expense of shameful
falsehood. She was now in New Orleans, and had been two or three
times thrown into the society of our hero. On such occasions, she
had watched him closely, and smiled with delight if any thing
approximating toward intimacy was observable in his intercourse
with any of the fair sex. To apprise Mary of his delinquency was a
duty; and she was at no great loss to imagine how so desirable an
object could be accomplished without involving herself in any
difficulty.
——
57. CHAPTER VIII.
To follow still the changes of the moon
With fresh suspicions.
Othello.
A quiet happiness was now Mary’s—a happiness “which passeth
show.” Heaven had blessed her, she believed, beyond her dearest
hopes. But, alas! the joys of the heart are more fleeting than the
days of spring. Where is the mortal that can secure to himself the
cup of happiness without alloy? It dwells not under a regal canopy—
for a diadem often makes the head ache. Nor with the conqueror,
however great his glory in the battle-field—the mangled bodies—the
reeking blood—the groans of the dying would prevent it. The poet,
then—all his happiness consists in being very miserable. The learned
—nay, all they acquire makes them but the more dissatisfied with
themselves—and self-dissatisfaction, every one knows, tends not to
the promotion of happiness. Then the lover, with the draught in his
hand, cannot say it will reach his lips. A something may come
between him and his bliss, and the cup may pass away. The cup that
Mary had longed to drain to the bottom, was about to be dashed
away. The glory that brightened the sky of her being was beginning
to darken—and the storm threatened to crush the flower of her
affections, even in its happiest moment of existence.
One day she received a letter, written in an unknown hand; she
opened it carelessly, but soon became absorbed as she read the
following:
Miss Bryarly,—Believing you to be the affianced wife of
Mr. Thatcher, I take the liberty of writing to you to
admonish you of his conduct. If his engagement with you is
not broken off, he must either be a villain, or he is acting
like one. I have had a watchful eye on him for some time,
during which he has been paying the most constant and
58. devoted attention to Miss Morton; so far, indeed, has he
gone, as to induce her family to believe that he is about to
make proposals for her hand. One of her brothers so
expressed himself to me a few days since. I hope you will
inform your father of these facts, that he may use every
precaution against the duplicity of one who would have
deeply injured you.
A Friend.
“This letter I pronounce a base falsehood,” said she, handing it to
her father, “and its author a calumniator, who, like an assassin, seeks
darkness to cover his evil deeds, for he has not dared to sign his
name.”
Mr. Bryarly also regarded the letter as a vile calumny, not worthy
of notice. Confiding in the truth of her lover, Mary had ceased to
think of its contents, when an insinuation to his discredit was again
breathed in her ear; then came a report that he was a confirmed flirt
—a gay deceiver; and as bold slander loses nothing in its busy
progress, the rumor was magnified until the seeds of discontent
were sown in Mary’s heart—and she was now absolutely jealous.
That which she had once imagined so repulsive as to scoff at the
mere possibility of her own actions ever being ordered by such a
feeling, triumphed—and she was unable to conquer the “green-eyed
monster.” One evening she was evidently very melancholy. In vain
had she tried to elicit harmony from the keys of her piano, and
becoming weary of the fruitless effort, she threw herself languidly on
a sofa, and sighed deeply.
“Mercy on us! that was a terribly long and sentimental heigh-o! I
wonder which way it went! Ah! I see it now; it floats like a gossamer
on that glorious sunbeam, and goes in the direction of New Orleans,”
laughed Mr. Pluribusi.
“You are growing poetical, uncle; it is really charming to listen to
you—pray go on.”
“Mary,” said her father, who had been also observing her, “any
one would suppose all your perceptions were obscured by a thick,
59. ugly, green cloud.”
“Oh, father!” was all she could say.
“You know,” he continued, “there is nothing on earth so
disagreeable to me as a jealous woman—”
“Except, indeed, a prudish one,” chimed in Mr. Pluribusi.
“I have great cause, father, to be unhappy; for all the reports I
have heard, have been confirmed by Mrs. Webster since her return
home.”
“My opinion is, that you are wasting an immense amount of
sorrow, all for nothing,” answered her father; “for with the
characters of the truest and most upright slander will sometimes be
busy. Entertain not so mean an opinion of your betrothed husband,
as to believe he is capable of change. The brightest part of love is its
confidence. It is that perfect, that unhesitating reliance, that
interchange of every idea and every feeling; and that perfect
community binds two beings together as closely as the holiest of
human ties. It is only that confidence, that community of all the
heart’s secrets, and the mind’s thoughts, that can give us permanent
happiness.”
“Oh, father! could you but convince me that my doubts are
unfounded.”
“I think I can settle the matter to your entire satisfaction, Mary,”
quietly observed her uncle.
“How, uncle?” asked she, eagerly.
“You must consent to use a little stratagem,” replied he.
“If you think it right, and father sanctions it, I am willing to do
any thing you propose,” she said, looking at her parent.
“Do as you think proper,” answered Mr. Bryarly.
“Have you answered Harry’s last letter?” inquired Mr. Pluribusi.
“How could I?—I am three deep in his debt.”
“So much the better for my plan, which is to arouse the demon
of jealousy in his bosom. Write to him immediately, and give him but
the shadow of a cause for distrust, and if he is not at your feet as
60. soon as the power of steam can bring him, why, then I will no longer
believe in the constancy of man.”
“And then I should no longer doubt his affection. But, uncle,
what shall I say to him?”
“Write a glowing description of me; dwell on the pleasant time
we spend together; then, if he does not yield a most loyal and ready
obedience to the ‘green-eyed monster,’ I will say he cares for
another.”
——
61. CHAPTER IX.
“Why writes she so to me?”
The next mail bore Harry the following letter from his own Mary:
My Dearest Harry,—I have no excuse to offer for my
protracted silence, other than I have been so very much
engaged. But I know your kind heart will readily forgive my
remissness when you hear all I have to say to you;
therefore I must hasten to tell you, first premising that you
must not be jealous. Both father and Uncle Pluribusi say
that is a most detestable passion—and you know I so
dislike any thing that is ugly and disagreeable.
But to my confession. There is a friend of mine at
present sojourning here—a kind of relative; and a splendid
fellow he is, dear Harry. In both form and face he is
eminently handsome; then he is so merry—and polite to
the highest degree of refinement. His discourse is a
perpetual series of neat repartee, elegant compliment,
bright thoughts, and happy expression. He has a beaming
smile, and a pleasant word for every one; but he
anticipates my thoughts, knows the meaning of every
glance, and ministers to my every wish before it is formed.
Is he not a very paragon? I know you will like him so much,
when you become as well acquainted with him as I am. I
often tell him he is second in my heart’s best affections.
This seems to please him greatly; and he expresses his
delight by snatching a kiss. Now, Harry, don’t be shocked!
remember, he is a very old and dear friend. Although his
very soul seems to be the seat of joyousness, I verily
believe he possesses a tolerably large portion of sentiment;
and you must not be surprised if you hear I have made a
62. conquest of his heart. I assure you my manner toward him
has been free from any thing like coquetry, but I do enjoy
his society. The perpetual summer of his mind imparts a
corresponding glow and animation to his manner, a lively
and genial warmth to all his actions; and his very look
seems to say, “Come, let us laugh at a world that only
laughs at us.” Would you believe it, Harry? with him for my
partner, I often find myself whirling round at some gay
party, in the delicious delirium of the waltz. I know you will
be charmed to hear this; for you have so often expressed a
wish that I should become perfect in that delightful
accomplishment. My friend is somewhat in my confidence,
and knows that I am engaged to somebody; but this
knowledge has not in the least changed his attention to me.
He says matrimony is at best but a “divine comedy.” I
suppose I have thought of it too seriously. I have promised
to ride with him this afternoon, and—hark! I hear the
horses at the door now; dear me! he is always so early, he
will never give me time to write a letter even to you.
What delight there is in a wild gallop. I am an expert
equestrian now, and often execute some daring exploits. In
your absence these delightful excursions form the chief
pleasure of my life; and to me there is more melody in our
horses’ hoofs, as they “tramp, tramp along the land,” than I
could thump out of my piano this morning. Forgive the
brevity of this; I am sure you will, for this is the second
time I have been interrupted by “the horses are waiting,
Mary.”
You see how my time is occupied; I have scarcely an
hour that I can call my own.
Having every faith in your constancy and truth, I bid you
farewell.
Your ever faithful,
Mary.
63. An indescribable emotion racked the whirling brain of our hero,
as, word by word, this epistle seemed tearing the very fibres of his
heart. How like an endless night came down the shadows of despair,
as throwing it down he murmured, “Lost—lost to me forever, I fear!”
——
64. CHAPTER X.
But ties around this heart were spun,
That would not, could not, be undone.
Campbell.
One day Mary said to her father, “My head does really ache so
badly.”
“Go into the garden—a walk and the fresh air will revive you,”
replied he.
She followed his advice, and rambled about for a long time, but
neither her flowers nor the beauties of nature could fix her attention
—her thoughts ran on an absent one; she had suffered herself to be
persuaded that Harry would surely come, immediately after receiving
her letter—and she had been looking for him for some hours. If the
wind moved the branches—she started, or a bird flew rustling
through the leaves, as if their accustomed sounds were the
harbingers of coming footsteps. She was unwilling to acknowledge,
even to herself, the disappointment that weighed upon her spirits;
but not finding in her walk the exhilarating influence she anticipated,
she was turning her steps homeward, when a sudden crashing
among the boughs interrupted her progress, and the object of her
thoughts bounded into the path, his face glowing with the rapidity of
his motions; her eyes flashed with their wonted joy, and forgetting
every thing but the delight she felt in meeting him, with a sudden
impulse she rushed forward and threw herself into his out-stretched
arms.
“I feared that I might be forgotten,” exclaimed he, tenderly; “but
I see I have wronged you.”
“I could never forget you, Harry,” was the whispered reply.
“But why did you write that terrible letter, Mary? Anguish pierced
my heart when I read its contents. Oh! if you had ever felt the
torture of jealousy, you would have spared me that.”
65. A thrill of delight penetrated Mary’s heart; now she was
convinced that she was beloved as well as ever.
“Have I no cause to reproach you?” asked she, looking up into
his face as if she would read his very soul.
“If I deserve upbraiding from you, I am totally unconscious; but
tell me, dear Mary, how have I offended?”
“Rumor has been busy spreading reports that you have been
addressing another; and it says that you did not address her in vain.
But now, Harry, I do not believe one word of what I have been told.”
“But you have doubted me, Mary,” said he, mournfully. “There is
but one sun in heaven—there is but one Mary to my eyes on earth!”
“Forgive me, Harry? Mrs. Webster confirmed all these reports
when she returned.”
“Mrs. Webster is not my friend, Mary; and I suspect all those
reports have come from her. I have long known her disregard of
truth, as well as her design on you.”
“I now begin to penetrate a plot, and believe her to be the
inventor of all the base charges against you. Alas! the inborn
wickedness of the human heart.”
“Now, tell me of the letter, Mary, that aroused me, for a time,
from the sweetest and brightest dream that ever gladdened the
heart of man?”
“Oh!” said she, laughing, “my very dear friend was no other than
Uncle Pluribusi.”
“Then you have been romancing a little, to be revenged on me?”
inquired he, archly.
“I believe I must plead guilty.”
“I am impatient to meet my fascinating rival, that we may enjoy
together a hearty laugh over our ‘Comedy of Errors.’ ”
Gentle reader, this is but a plain, unvarnished tale. It is true, I
might have drawn upon my imagination for adorning it. I might have
presented you with hair-breadth escapes, and crushing reverses; but
I could not do so without detracting from its perfect truthfulness—
66. for the incidents on which the foregoing pages are founded, are
literally true.
I regret exceedingly that I am unable to wind-up with a
marriage; but for the gratification of my youthful readers, I must not
forget to add, that this event will take place immediately on the
return of Mr. Thatcher from Europe, whither he has been
unexpectedly called to transact some important business for the firm
of Thatcher & Co.
67. ODE TO TIME.
———
BY WM. GILMORE SIMMS, AUTHOR OF “YEMASSE,” “GUY RIVERS,” ETC.
———
I.
Gray monarch of the waste of years,
Mine eyes have told thy steps in tears,
Yet yield I not to feeble fears,
In watching now thy flight;
The neck, long used to weighty yoke,
The tree, long shivered by the stroke,
The heart, by frequent torture broke,
Need fear no second blight.
II.
Oh! mine has been a mournful song—
My neck has felt the burden long—
My tree was shivered—weak and strong,
Beneath the bolt went down:
My heart—enough—thou canst not prey
On many in this later day;
The old, the young, were torn away,
Ere manhood’s wing had flown;
I saw the noble sire, who stood,
Majestic, as in crowded wood
The pine—and after him the brood—
All perish in thy frown!
68. III.
So, count my hopes, and know my fears,
And ask what now this life endears,
To him who gave, with many tears,
Each blossom of his love;
Whose store in heaven, so precious grown,
He counts each earthly moment flown,
As loss of something from his own,
In treasures stored above!
Denied to seek—to see—his store,
Yet daily adding more and more,
Some precious plant, that, left before,
The spoiler rends at last.
Not hard the task to number now,
The few that live to feel the blow;
The perished—count them on my brow—
With white hairs overcast!
IV.
69. White hairs—while yet each limb is strong,
To hold the right and crush the wrong;
Ere youth, in manhood’s struggling throng,
Had half pursued his way:
Thought premature, that still denied
The boy’s exulting sports—the pride,
That, with the blood’s unconscious tide,
Knew but to shout and play!
Youth, that in love’s first gush was taught
To see his fresh affection brought
To tears, and wo, and death—
While yet the fire was in his eye,
That told of passion’s victory—
And, in his ear, the first sweet sigh,
From beauty’s laboring breath.
V.
And manhood now—and loneliness—
With, oh! how few to love and bless,
Save those, who, in their dear duresse,
Look down from heaven’s high towers:
The stately sire, the gentle dame,
The maid who first awoke the flame,
That gave to both a mutual claim,
As fresh and frail as flowers!—
And all those dearest buds of bloom,
That simply sought on earth a tomb,
From birth to death, with rapid doom,
A bird-flight winged for fate:
How thick the shafts, how sure the aim!
What other passion wouldst thou tame,
O! Time, within this heart of flame,
Elastic, not elate?
70. VI.
Is’t pride?—methinks ’tis joy to bend;
My foe—he can no more offend;
My friend is false—I love my friend;
I love my foeman, too.
’Tis man I love—nor him alone—
The brute, the bird—its joy or moan
Not heedless to my heart hath gone—
I feel with all I view.
Wouldst have me worthy?—make me so;
But spare on other hearts the blow;
Spare, from the cruel pang, the wo,
The innocent, the bright!
On me thy vengeance!—’Tis my crime
That needs the scourge, and, in my prime,
’Twere fruitful of improving time,
Thy hand should not be light.
VII.
71. I bend me willing to thy thrall,
Whate’er thy doom, will bear it all—
Drink of the bitter cup of gall,
Nor once complain of thee!
Will poverty avail to chide,
Or sickness bend the soul of pride,
Or social scorn, still evil-eyed—
Have, then, thy will of me!
But spare the woman and the child;
Let me not see their features mild,
Distorted—hear their accents wild,
In agonizing pain:
Too much of this! I thought me sure.
In frequent pang and loss before;
I still have something to endure—
And tremble, and—refrain!
VIII.
72. On every shore they watch thy wing—
To some the winter, some the spring,
Thou bring’st, or yet art doomed to bring.
In rapid—rolling years:
How many seek thee, smiling now,
Who soon shall look with clouded brow,
Heart filled with bitter doubt and wo,
And eyes with gathering tears!
But late, they fancied—life’s parade
Still moving on—that not a shade
Thou flung’st on bower and sunny glade,
In which they took delight:
Sharp satirist! methinks I see
Thy glance in sternest mockery—
They little think, not seeing thee,
How fatal is thy flight;
What feathers grow beneath thy wing—
What darts—how poisoned—from what spring
Of torture—and how swift the sting—
How swift and sure the blight!
IX.
73. Enough!—the feeling has its way,
As thou hast had;—’tis not the lay
Of vain complaint—no idle play
Of fancy, dreaming care:
A mocking bitter, like thine own,
Wells up from fountains, deep and lone,
From core and spirit, soul and bone—
I’ve felt thee every where!
Thou’st mocked my hope and dashed my joy,
With keen rebuke and cold alloy;
The father, son, the man, the boy,
All, all! have felt the rod!
Perchance not all thy work in vain,
In softening soul, subduing brain,
If suffering, I submit to pain—
That minister of God!
74. A WINTER’S NIGHT IN THE WILDERNESS.
———
BY THOMAS BUCHANAN READ.
———
’Twas night; and hoary Winter walked abroad,
Howling like hungry wolves amid the wild;
Moon there was none—and every star seemed awed,
And shrinking, trembled like a frighted child!
Through all the woods the dreary snow was piled,
Or like a shroud it lay, the ridgéd fold
Showing the shape beneath—above, beguiled
By Sorrow, swayed the pines; through wood and wold
The wild winds to and fro went sighing unconsoled.
A cabin stood upon the wooded slope—
From many a crevice fitful firelight streamed,
Making the blackness denser, like the hope
Which from the settler’s broken spirit gleamed,
Only to show the dark!—then, where it beamed,
Died, leaving all its ashes on his heart!
And now he gazed into the fire and dreamed
Of home, of native mountains wrapt apart,
The village and afar the large and steepled mart.
75. He saw the haze lay o’er the landscape green,
Where, like a happy thought, the streamlet flowed
The fields of waving grass and groves between.
Afar the white and winding turnpike glowed—
The peopled coach rolled down the dusty road.
The shining cattle through the pasture grazed;
And all the air seemed trembling with a load
Of melody, by birds and children raised:
But now, a voice—a groan—he started—stood amazed.
Hark! was’t the wind which eddied round the place,
Or mournful trees by wailing tempests tossed?
Or was’t a moan from that pale, wasted face
Which from the bed gleamed like a sleeping ghost?
Or Hunger worrying Slumber from his post
Amid the little ones? He only heard
The heave of breasts which unknown dreams had crossed,
Such dreams as stir the lips but make no word,
And heard his own heart beat like an o’er-wearied bird!
A noise—a tramp amid the crisping snow—
Startled his ear! A large, imploring eye
Gleamed at the window with unearthly glow!
Was’t the grim panther which had ventured nigh?
Or ghost condemned—or spirit of the sky?
To grasp the gun his hand contained no force—
His arm fell trembling and he knew not why!
He ope’d the door—there stood a shivering horse,
While clung upon his mane a stiff and muffled corse.
76. Oh Death! who calls thy aspect terrible?
Is’t he who gazes on the gentle maid
Wrapped in her careful shroud; for whom a knell
Steals o’er the village like a twilight shade;
And on whose breast and in whose hands are laid
White violets and lilies of the vale,
Gems which bloom downward? Or, like them arrayed,
Beholds the child as its own pillow pale,
And hears the father’s groan and mother’s piercing wail?
Who calls thy aspect terrible? Do they
Who gaze on brows the lightning stoops to scathe?
Or darker still, on those who fall a prey
To jealousy’s unsmotherable wrath?
Or they who walk in War’s ensanguined path
And hear the prayers and curses of distress?
These call thy aspect terrible! oh Death!
More terrible, by far, let those confess,
The frozen rider in that frozen wilderness!
77. THE MAN WITH THE BIG BOX.
———
BY G. G. FOSTER.
———
Mr. Robert Short—or, as he was called for shortness, Bob Short—
was a genius. He could write a passable poem, and on one occasion
—perhaps I should say two—had imprinted a sonnet upon each
virgin sole of a pair of stainless satin slippers, kindly loaned him by
the fair owner who was to trample upon his mounting aspirations.
But some, who accidentally read the verses in the evening—ladies’
slippers will come off and get passed round the room, you know—
asserted that Bob had put his foot into it more completely than the
lady. And then the pretty excuses he made for the minuteness of the
hand, or rather foot writing—“they were really so very small he could
scarcely crowd his rhymes upon them, in any character!” It was
quite charming and irresistible! Mr. Short rose cent. per cent. in
moral and social stature, and eventually swelled to the size of a lion.
Don’t be alarmed, ladies—we mean a New York lion—not a real king
of the forest, with yellow mane, eyes of fire, and a roar like Niagara
Falls; but that much more harmless and docile animal, a civil, social
lion—the lion of ladies in want of distinction, the lion of the bas bleu,
the lion of Waverley Place and other high latitudes.
But, with all his numerous and admirable qualifications, Mr. Short
had no genius for packing big boxes. Indeed, he had no genius for
packing at all; and when his wife sent him packing, during his first
courtship, he wouldn’t stay packed, but came back and plagued her
so with his attentions that at length she fairly married him to get rid
of him—and a very good way it is, too, to get rid of a man’s society,
as many wives have proved. Mr. Short turned out, as might have
been expected, any thing but an efficient housekeeper. He could cut
a pigeon-wing, but was incapable of carving a chicken; he could
wheedle the Muses, but was invariably cheated by the market-
78. women; he could make bon mots, after a fashion, but bargains not
at all. Although his verses were eminently mechanical, his manual
dexterity extended to no useful purpose. As for putting up a
bedstead, he could no more do it than he could have built a gallows
and hung himself with the bed-cord; and he was obliged to wear
gaiters all winter from lack of sufficient ingenuity to construct a
boot-jack.
But Bob loved his wife, and felt ashamed of his utter inefficiency
about the house. When his first child was born, therefore, he
determined to reform, and see if he could not acquire some of the
faculties in which he found himself so lamentably deficient. So he
quit sonneteering and conundrum-making and betook himself to his
study, where he passed day and night in profound meditation. His
wife thought he was only a little more crazy than usual; but the
neighbors contended that he was calculating the centre of gravity.
The result, however, upset every body’s gravity, and all their
calculations. Bob had invented a cradle! Such a cradle! If I had the
pencil of Darley or Martin I could show you something of an idea of
this wonderful cradle—but you must imagine. In form it was a happy
combination of Cleopatra’s barge and the tub of Diogenes; while in
convenience and “general utility” it was at least equal to the Chinese
junk at the Battery, or the walking gentleman at the —— theatre.
Proud of his baby—for which he was indebted to his wife—he was
still prouder of his cradle—which was entirely his own. No sooner
was the grand idea perfected than he rushed to the cabinet-maker,
who, after anxious reflection on the subject, informed him that it
would require a month to give form and mahogany to his
magnificent conception. Meanwhile, what was to be done with Baby?
He could not, of course, possibly think of sleeping and being rocked
in a common cradle—no, that would be rank sacrilege. The father
had an idea—Baby should sleep in a champagne-basket, until the
cradle was finished. It would be so cool and pleasant—champagne
was cool and pleasant—and so promotive of sleep, for were not its
contents originally of the pop-py variety? So it was settled that the
little Short should take the place of a whole dozen of champagne,
79. Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com