DB2 SQL Examples

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 283
At a glance
Powered by AI
The document discusses different SQL concepts like joins, subqueries, unions, case statements, window functions and recursion through examples. It also compares calculations done with floating point numbers vs decimals.

Examples of inner join, left outer join and subqueries are shown. Figures 1, 2 and 3 demonstrate these concepts.

Recursion is a technique where a query calls itself to traverse hierarchical or tree-like data. Figure 7 demonstrates recursion to list family members from grandparents to grandchildren.

Left=1,right=top=bottom=0.

5
***********************************************************************
EMP_NM
EMP_JB
+----------+ +--------+
|ID|NAME
| |ID|JOB |
|--|-------| |--|-----|
|10|Sanders| |10|Sales|
|20|Pernal | |20|Clerk|
|50|Hanes | +--------+
+----------+
Figure 1, Join example

SELECT

nm.id
,nm.name
,jb.job
FROM
emp_nm nm
,emp_jb jb
WHERE
nm.id = jb.id
ORDER BY 1;

ANSWER
================
ID NAME
JOB
-- ------- ----10 Sanders Sales
20 Pernal Clerk

***********************************************************************
EMP_NM
EMP_JB
SELECT
nm.id
+----------+ +--------+
,nm.name
|ID|NAME
| |ID|JOB |
,jb.job
|--|-------| |--|-----|
FROM
emp_nm nm
|10|Sanders| |10|Sales|
LEFT OUTER JOIN
|20|Pernal | |20|Clerk|
emp_jb jb
|50|Hanes | +--------+
ON
nm.id = jb.id
+----------+
ORDER BY nm.id;
Figure 2,Left-outer-join example

ANSWER
================
ID NAME
JOB
-- ------- ----10 Sanders Sales
20 Pernal Clerk
50 Hanes
-

***********************************************************************
EMP_NM
EMP_JB
SELECT
*
+----------+ +--------+
FROM
emp_nm nm
|ID|NAME
| |ID|JOB |
WHERE NOT EXISTS
|--|-------| |--|-----|
(SELECT *
|10|Sanders| |10|Sales|
FROM
emp_jb jb
|20|Pernal | |20|Clerk|
WHERE nm.id = jb.id)
|50|Hanes | +--------+
ORDER BY id;
+----------+
Figure 3, Sub-query example

ANSWER
========
ID NAME
== =====
50 Hanes

***********************************************************************
EMP_NM
EMP_JB
+----------+ +--------+
|ID|NAME
| |ID|JOB |
|--|-------| |--|-----|
|10|Sanders| |10|Sales|
|20|Pernal | |20|Clerk|
|50|Hanes | +--------+
+----------+
Figure 4, Union example

SELECT
FROM
WHERE
UNION
SELECT
FROM
ORDER BY

*
emp_nm
name < 'S'
*
emp_jb
1,2;

ANSWER
=========
ID 2
-- -----10 Sales
20 Clerk
20 Pernal
50 Hanes

***********************************************************************
EMP_JB
SELECT
id
+--------+
,job
|ID|JOB |
,ROW_NUMBER() OVER(ORDER BY job) AS R
|--|-----|
FROM
emp_jb
|10|Sales|
ORDER BY job;
|20|Clerk|
+--------+
Figure 5, Assign row-numbers example

ANSWER
==========
ID JOB
R
-- ----- 20 Clerk 1
10 Sales 2

***********************************************************************
EMP_JB
+--------+
|ID|JOB |
|--|-----|
|10|Sales|
|20|Clerk|
+--------+

SELECT

id
,job
,CASE
WHEN job = 'Sales'
THEN 'Fire'
ELSE 'Demote'
END AS STATUS
FROM
emp_jb;
Figure 6, Case stmt example

ANSWER
===============
ID JOB
STATUS
-- ----- -----10 Sales Fire
20 Clerk Demote

***********************************************************************
FAMILY
+-----------+
|PARNT|CHILD|
|-----|-----|
|GrDad|Dad |
|Dad |Dghtr|
|Dghtr|GrSon|
|Dghtr|GrDtr|
+-----------+

WITH temp (persn, lvl) AS


(SELECT parnt, 1
FROM
family
WHERE
parnt = 'Dad'
UNION ALL
SELECT child, Lvl + 1
FROM
temp,
family
WHERE
persn = parnt)
SELECT *
FROM
temp;
Figure 7, Recursion example

ANSWER
=========
PERSN LVL
----- --Dad
1
Dghtr
2
GrSon
3
GrDtr
3

***********************************************************************
INPUT DATA
=================
"Some silly text"

Recursive SQL
============>

ANSWER
===========
TEXT LINE#
----- ----Some
1
silly
2
text
3

Figure 8, Convert string to rows


***********************************************************************
INPUT DATA
Recursive SQL
===========
============>
TEXT LINE#
----- ----Some
1
silly
2
text
3
Figure 9, Convert rows to string

ANSWER
=================
"Some silly text"

***********************************************************************
EMP_NM
SELECT
*
+----------+
FROM
emp_nm
|ID|NAME
|
ORDER BY id DESC
|--|-------|
FETCH FIRST 2 ROWS ONLY;
|10|Sanders|
|20|Pernal |
|50|Hanes |
+----------+
Figure 10, Fetch first "n" rows example

ANSWER
=========
ID NAME
-- -----50 Hanes
20 Pernal

***********************************************************************
EMP_NM
SELECT
*
+----------+
FROM
emp_nm
|ID|NAME
|
WHERE
name like 'S%'
|--|-------|
WITH UR;
|10|Sanders|
|20|Pernal |
|50|Hanes |
+----------+
Figure 11, Fetch WITH UR example

ANSWER
==========
ID NAME
-- ------10 Sanders

***********************************************************************
EMP_NM
SELECT
AVG(id)
AS avg
+----------+
,MAX(name) AS maxn
|ID|NAME
|
,COUNT(*) AS #rows
|--|-------|
FROM
emp_nm;
|10|Sanders|
|20|Pernal |
|50|Hanes |
+----------+
Figure 12, Column Functions example

ANSWER
=================
AVG MAXN
#ROWS
--- ------- ----26 Sanders
3

***********************************************************************
SELECT

job
,dept
,SUM(salary) AS sum_sal
,COUNT(*)
AS #emps
FROM
staff
WHERE
dept
< 30
AND
salary < 20000
AND
job
< 'S'
GROUP BY ROLLUP(job, dept)
ORDER BY job
,dept;
Figure 13, Subtotal and Grand-total example

ANSWER
=======================
JOB
DEPT SUM_SAL #EMP
----- ---- -------- ---Clerk
15 24766.70
2
Clerk
20 27757.35
2
Clerk
- 52524.05
4
Mgr
10 19260.25
1
Mgr
20 18357.50
1
Mgr
- 37617.75
2
- 90141.80
6

***********************************************************************
--#SET
SELECT
--#SET
SELECT
Figure

DELIMITER !
name FROM staff WHERE id = 10!
DELIMITER ;
name FROM staff WHERE id = 20;
15, Set Delimiter example

***********************************************************************
CREATE TABLE employee
(empno
CHARACTER (00006)
,firstnme VARCHAR
(00012)
,midinit
CHARACTER (00001)
,lastname VARCHAR
(00015)
,workdept CHARACTER (00003)
,phoneno
CHARACTER (00004)
,hiredate DATE
,job
CHARACTER (00008)
,edlevel
SMALLINT
,SEX
CHARACTER (00001)
,birthdate DATE
,salary
DECIMAL
(00009,02)

NOT
NOT
NOT
NOT

NULL
NULL
NULL
NULL

NOT NULL

,bonus
DECIMAL
(00009,02)
,comm
DECIMAL
(00009,02)
)
DATA CAPTURE NONE;
Figure 16, DB2 sample table - EMPLOYEE
***********************************************************************
CREATE VIEW employee_view AS
SELECT
a.empno, a.firstnme, a.salary, a.workdept
FROM
employee a
WHERE
a.salary >=
(SELECT AVG(b.salary)
FROM
employee b
WHERE a.workdept = b.workdept);
Figure 17, DB2 sample view - EMPLOYEE_VIEW
***********************************************************************
CREATE VIEW silly (c1, c2, c3)
AS VALUES (11, 'AAA', SMALLINT(22))
,(12, 'BBB', SMALLINT(33))
,(13, 'CCC', NULL);
Figure 18, Define a view using a VALUES clause
***********************************************************************
SELECT
c1, c2, c3
FROM
silly
ORDER BY c1 aSC;

ANSWER
===========
C1 C2
C3
-- --- -11 AAA 22
12 BBB 33
13 CCC
-

Figure 19, SELECT from a view that has its own data
***********************************************************************
CREATE VIEW test_data AS
WITH temp1 (num1) AS
(VALUES (1)
UNION ALL
SELECT num1 + 1
FROM
temp1
WHERE
num1 < 10000)
SELECT *
FROM
temp1;
Figure 20, Define a view that creates data on the fly
***********************************************************************
CREATE ALIAS
COMMIT;

employee_al1 FOR employee;

CREATE ALIAS
COMMIT;

employee_al2 fOR employee_al1;

CREATE ALIAS employee_al3 FOR employee_al2;


COMMIT;
Figure 21, Define three aliases, the latter on the earlier

***********************************************************************
CREATE NICKNAME emp FOR unixserver.production.employee;
Figure 22, Define a nickname
***********************************************************************
SELECT
*
FROM
staff TABLESAMPLE BERNOULLI(10);
Figure 23, TABLESAMPLE example
***********************************************************************
CREATE TABLE sales_record
(sales#
INTEGER
NOT NULL
GENERATED ALWAYS AS IDENTITY
(START
WITH 1
,INCREMENT BY 1
,NO MAXVALUE
,NO CYCLE)
,sale_ts
TIMESTAMP
NOT NULL
,num_items
SMALLINT
NOT NULL
,payment_type
CHAR(2)
NOT NULL
,sale_value
DECIMAL(12,2)
NOT NULL
,sales_tax
DECIMAL(12,2)
,employee#
INTEGER
NOT NULL
,CONSTRAINT sales1
CHECK(payment_type IN ('CS','CR'))
,CONSTRAINT sales2
CHECK(sale_value
> 0)
,CONSTRAINT sales3
CHECK(num_items
> 0)
,CONSTRAINT sales4
FOREIGN KEY(employee#)
REFERENCES staff(id)
ON DELETE RESTRICT
,PRIMARY KEY(sales#));
Figure 24, Sample table definition
***********************************************************************
CREATE TABLE default_values
(c1
CHAR
NOT NULL
,d1
DECIMAL
NOT NULL);
Figure 25, Table with default column lengths
***********************************************************************
LABELED DURATIONS
ITEM
WORKS WITH DATE/TIME
<------------------------>
FIXED
<--------------------->
SINGULAR
PLURAL
SIZE
DATE
TIME
TIMESTAMP
===========
============
=====
====
====
=========
YEAR
YEARS
N
Y
Y
MONTH
MONTHS
N
Y
Y
DAY
DAYS
Y
Y
Y
HOUR
HOURS
Y
Y
Y
MINUTE
MINUTES
Y
Y
Y
SECOND
SECONDS
Y
Y
Y
MICROSECOND
MICROSECONDS
Y
Y
Y
Figure 26, Labeled Durations and Date/Time Types
***********************************************************************

SELECT

sales_date
,sales_date
,sales_date
,sales_date
,sales_date

- 10
DAY
AS d1
+ -1
MONTH AS d2
+ 99
YEARS AS d3
+ 55
DAYS
- 22
MONTHS AS d4
,sales_date + (4+6) DAYS
AS d5
FROM
sales
WHERE
sales_person = 'GOUNOT'
AND
sales_date
= '1995-12-31'
Figure 27, Example, Labeled Duration usage

<=
<=
<=
<=

ANSWER
==========
1995-12-31
1995-12-21
1995-11-30
2094-12-31

<=
<=

1994-04-24
1996-01-10

***********************************************************************
ANSWER
==========
SELECT
sales_date
<= 1995-12-31
,sales_date +
2 MONTH AS d1
<= 1996-02-29
,sales_date +
3 MONTHS AS d2
<= 1996-03-31
,sales_date +
2 MONTH
+
1 MONTH AS d3
<= 1996-03-29
,sales_date + (2+1) MONTHS AS d4
<= 1996-03-31
FROM
sales
WHERE
sales_person = 'GOUNOT'
AND
sales_date
= '1995-12-31';
Figure 28, Adding Months - Varying Results
***********************************************************************
DURATION-TYPE FORMAT
NUMBER-REPRESENTS
============= ============= =====================
DATE
DECIMAL(8,0)
yyyymmdd
TIME
DECIMAL(6,0)
hhmmss
TIMESTAMP
DECIMAL(20,6) yyyymmddhhmmss.zzzzzz
Figure 29, Date/Time Durations

USE-WITH-D-TYPE
===============
TIMESTAMP, DATE
TIMESTAMP, TIME
TIMESTAMP

***********************************************************************
SELECT

empno
ANSWER
,hiredate
====================================
,birthdate
EMPNO HIREDATE
BIRTHDATE
,hiredate - birthdate
------ ---------- ---------- ------FROM
employee
000150 1972-02-12 1947-05-17 240826.
WHERE
workdept = 'D11'
000200 1966-03-03 1941-05-29 240905.
AND
lastname < 'L'
000210 1979-04-11 1953-02-23 260116.
ORDER BY empno;
Figure 30, Date Duration Generation
***********************************************************************
ANSWER
==========
SELECT
hiredate
<= 1972-02-12
,hiredate - 12345678.
<= 0733-03-26
,hiredate - 1234 years
56 months
78 days
<= 0733-03-26
FROM
employee
WHERE
empno = '000150';
Figure 31, Subtracting a Date Duration

***********************************************************************
SPECIAL REGISTER
===============================================
CURRENT CLIENT_ACCTNG
CURRENT CLIENT_APPLNAME
CURRENT CLIENT_USERID
CURRENT CLIENT_WRKSTNNAME
CURRENT DATE
CURRENT DBPARTITIONNUM
CURRENT DEFAULT TRANSFORM GROUP
CURRENT DEGREE
CURRENT EXPLAIN MODE
CURRENT EXPLAIN SNAPSHOT
CURRENT ISOLATION
CURRENT LOCK TIMEOUT
CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION
CURRENT PACKAGE PATH
CURRENT PATH
CURRENT QUERY OPTIMIZATION
CURRENT REFRESH AGE
CURRENT SCHEMA
CURRENT SERVER
CURRENT TIME
CURRENT TIMESTAMP
CURRENT TIMEZONE
CURRENT USER
SESSION_USER
SYSTEM_USER
USER
Figure 32, DB2 Special Registers

UPDATE
======
no
no
no
no
no
no
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
no
no
no
no
yes
no
yes

DATA-TYPE
=============
VARCHAR(255)
VARCHAR(255)
VARCHAR(255)
VARCHAR(255)
DATE
INTEGER
VARCHAR(18)
CHAR(5)
VARCHAR(254)
CHAR(8)
CHAR(2)
INTEGER
VARCHAR(254)
VARCHAR(4096)
VARCHAR(254)
INTEGER
DECIMAL(20,6)
VARCHAR(128)
VARCHAR(18)
TIME
TIMESTAMP
DECIMAL(6,0)
VARCHAR(128)
VARCHAR(128)
VARCHAR(128)
VARCHAR(128)

***********************************************************************
SET CURRENT ISOLATION = RR;
SET CURRENT SCHEMA
= 'ABC';
SELECT

CURRENT TIME
AS cur_TIME
,CURRENT ISOLATION AS cur_ISO
,CURRENT SCHEMA
AS cur_ID
FROM
sysibm.sysdummy1;
Figure 33, Using Special Registers

ANSWER
=======================
CUR_TIME CUR_ISO CUR_ID
-------- ------- -----12:15:16 RR
ABC

***********************************************************************
CREATE DISTINCT TYPE JAP_YEN AS DECIMAL(15,2) WITH COMPARISONS;
DROP
DISTINCT TYPE JAP_YEN;
Figure 35, Create and drop distinct type
***********************************************************************
CREATE TABLE customer
(id
INTEGER
,fname
VARCHAR(00010)
,lname
VARCHAR(00015)
,date_of_birth
DATE
,citizenship
CHAR(03)
,usa_sales
DECIMAL(9,2)
,eur_sales
DECIMAL(9,2)
,sales_office#
SMALLINT
,last_updated
TIMESTAMP

NOT NULL
NOT NULL WITH DEFAULT ''
NOT NULL WITH DEFAULT ''

,PRIMARY KEY(id));
Figure 36, Sample table, without distinct types
***********************************************************************
SELECT

id
,usa_sales + eur_sales AS tot_sales
FROM
customer;
Figure 37, Silly query, but works
***********************************************************************
CREATE DISTINCT TYPE USA_DOLLARS AS DECIMAL(9,2) WITH COMPARISONS;
CREATE DISTINCT TYPE EUR_DOLLARS AS DECIMAL(9,2) WITH COMPARISONS;
Figure 38, Create Distinct Type examples
***********************************************************************
CREATE TABLE customer
(id
INTEGER
NOT NULL
,fname
VARCHAR(00010)
NOT NULL WITH DEFAULT ''
,lname
VARCHAR(00015)
NOT NULL WITH DEFAULT ''
,date_of_birth
DATE
,citizenship
CHAR(03)
,usa_sales
USA_DOLLARS
,eur_sales
EUR_DOLLARS
,sales_office#
SMALLINT
,last_updated
TIMESTAMP
,PRIMARY KEY(id));
Figure 39, Sample table, with distinct types
***********************************************************************
SELECT

id
,usa_sales + eur_sales AS tot_sales
FROM
customer;
Figure 40, Silly query, now fails
SELECT

id
,DECIMAL(usa_sales) +
DECIMAL(eur_sales) AS tot_sales
FROM
customer;
Figure 41, Silly query, works again
***********************************************************************
SELECT

deptno
,admrdept
,'ABC' AS abc
FROM
department
WHERE
deptname LIKE '%ING%'
ORDER BY 1;
Figure 44, Sample SELECT statement

ANSWER
===================
DEPTNO ADMRDEPT ABC
------ -------- --B01
A00
ABC
D11
D01
ABC

***********************************************************************
SELECT
*
ANSWER (part of)
FROM
department
================
WHERE
deptname LIKE '%ING%'
DEPTNO etc...
ORDER BY 1;
------ ------>>>
B01
PLANNING
D11
MANUFACTU
Figure 45, Use "*" to select all columns in table

***********************************************************************
SELECT

deptno
,department.*
FROM
department
WHERE
deptname LIKE '%ING%'
ORDER BY 1;

ANSWER (part of)


=======================
DEPTNO DEPTNO etc...
------ ------ ------>>>
B01
B01
PLANNING
D11
D11
MANUFACTU
Figure 46, Select an individual column, and all columns
***********************************************************************
SELECT

department.*
ANSWER (part of)
,department.*
================
FROM
department
DEPTNO etc...
WHERE
deptname LIKE '%NING%'
------ ------>>>
ORDER BY 1;
B01
PLANNING
Figure 47, Select all columns twice
***********************************************************************
SELECT

years
,name
,id
FROM
staff
FETCH FIRST 3 ROWS ONLY;

ANSWER
=====================
YEARS NAME
ID
------ --------- ---7 Sanders
10
8 Pernal
20
5 Marenghi
30
Figure 49, FETCH FIRST without ORDER BY, gets random rows
***********************************************************************
SELECT

years
,name
,id
FROM
staff
WHERE
years IS NOT NULL
ORDER BY years DESC
FETCH FIRST 3 ROWS ONLY;
Figure 50, FETCH FIRST with ORDER BY, gets wrong

ANSWER
=====================
YEARS NAME
ID
------ --------- ---13 Graham
310
12 Jones
260
10 Hanes
50
answer

***********************************************************************
SELECT

years
,name
,id
FROM
staff
WHERE
years IS NOT NULL
ORDER BY years DESC
,id
DESC
FETCH FIRST 3 ROWS ONLY;
Figure 51, FETCH FIRST with ORDER BY, gets right

ANSWER
=====================
YEARS NAME
ID
------ --------- ---13 Graham
310
12 Jones
260
10 Quill
290
answer

***********************************************************************
SELECT

a.empno
,a.lastname
FROM
employee a
,(SELECT MAX(empno)AS empno
FROM
employee) AS b
WHERE
a.empno = b.empno;
Figure 52, Correlation Name usage example

ANSWER
=================
EMPNO LASTNAME
------ ---------000340 GOUNOT

***********************************************************************
SELECT

a.empno
,a.lastname
,b.deptno AS dept
FROM
employee
a
,department b
WHERE
a.workdept = b.deptno
AND
a.job
<> 'SALESREP'
AND
b.deptname = 'OPERATIONS'
AND
a.sex
IN ('M','F')
AND
b.location IS NULL
ORDER BY 1;
Figure 53, Correlation name usage example

ANSWER
======================
EMPNO LASTNAME
DEPT
------ ---------- ---000090 HENDERSON E11
000280 SCHNEIDER E11
000290 PARKER
E11
000300 SMITH
E11
000310 SETRIGHT
E11

SELECT

ANSWER
===================
E_NUM
M INT ...
------ ----- ---000010 I
3978
000020 L
3476

empno
AS e_num
,midinit AS "m int"
,phoneno AS "..."
FROM
employee
WHERE
empno < '000030'
ORDER BY 1;
Figure 54, Renaming fields using AS

CREATE view emp2 AS


SELECT empno
AS e_num
,midinit AS "m int"
,phoneno AS "..."
FROM
employee;
SELECT *
FROM
emp2
WHERE "..." = '3978';
Figure 55, View field names defined using AS

SELECT
FROM
WHERE

AVG(comm)
AS a1
,SUM(comm) / COUNT(*) AS a2
staff
id < 100;

Figure 56, AVG of data containing null values

SELECT

COUNT(*)

AS num

ANSWER
===================
E_NUM
M INT ...
------ ----- ---000010 I
3978

ANSWER
===============
A1
A2
------- -----796.025 530.68

ANSWER

FROM
WHERE

,MAX(lastname) AS max
employee
firstnme = 'FRED';

========
NUM MAX
--- --0 -

Figure 57, Getting a NULL value from a field defined NOT NULL

SELECT

AVG(comm)
AS a1
,SUM(comm) / COUNT(*) AS a2
FROM
staff
WHERE
id < 100
AND
comm IS NOT NULL;
Figure 58, AVG of those rows that are not null

SELECT

'JOHN'
,'JOHN''S'
,'''JOHN''S'''
,'"JOHN''S"'
FROM
staff
WHERE
id = 10;
Figure 59, Quote usage

SELECT

AS
AS
AS
AS

J1
J2
J3
J4

id
AS "USER ID"
,dept
AS "D#"
,years
AS "#Y"
,'ABC'
AS "'TXT'"
,'"'
AS """quote"" fld"
FROM
staff s
WHERE
id < 40
ORDER BY "USER ID";
Figure 60, Double-quote usage

ANSWER
===============
A1
A2
------- -----796.025 796.02

ANSWER
=============================
J1
J2
J3
J4
---- ------ -------- -------JOHN JOHN'S 'JOHN'S' "JOHN'S"

ANSWER
===============================
USER ID D# #Y 'TXT' "quote" fld
------- -- -- ----- ----------10 20 7 ABC
"
20 20 8 ABC
"
30 38 5 ABC
"

Figure 61, Basic Predicate syntax, 1 of 2

SELECT
FROM
WHERE
AND NOT
AND NOT

id, job, dept


staff
job = 'Mgr'
job <> 'Mgr'
job = 'Sales'

ANSWER
===============
ID
JOB
DEPT
--- ---- ---10 Mgr
20

AND
id
<> 100
AND
id
>=
0
AND
id
<= 150
AND NOT dept =
50
ORDER BY id;
Figure 62, Basic Predicate examples

30
50
140

Mgr
Mgr
Mgr

38
15
51

Figure 63, Basic Predicate syntax, 2 of 2

SELECT
id, dept, job
FROM
staff
WHERE
(id,dept) = (30,28)
OR
(id,years) = (90, 7)
OR
(dept,job) = (38,'Mgr')
ORDER BY 1;
Figure 64, Basic Predicate example, multi-value check

ANSWER
===========
ID DEPT JOB
-- ---- --30
38 Mgr

SELECT
id, dept, job
FROM
staff
WHERE
(id
= 30 AND dept
OR
(id
= 90 AND years
OR
(dept = 38 AND job
ORDER BY 1;
Figure 65, Same query as prior,

ANSWER
===========
ID DEPT JOB
-- ---- --30
38 Mgr

=
28)
=
7)
= 'Mgr')
using individual predicates

Figure 66, Quantified Predicate syntax

SELECT
id, job
ANSWER
FROM
staff
========
WHERE
job = ANY (SELECT job FROM staff)
ID JOB
AND
id <= ALL (SELECT id FROM staff)
--- ---ORDER BY id;
10 Mgr
Figure 67, Quantified Predicate example, two single-value sub-queries

SELECT
FROM
WHERE

id, dept, job


ANSWER
staff
==============
(id,dept) = ANY
ID DEPT JOB
(SELECT dept, id
--- ---- ----FROM
staff)
20
20 Sales
ORDER BY 1;
Figure 68, Quantified Predicate example, multi-value sub-query

Figure 69, BETWEEN Predicate syntax

SELECT id, job


FROM
staff
WHERE
id
BETWEEN 10 AND 30
AND
id NOT BETWEEN 30 AND 10
AND NOT id NOT BETWEEN 10 AND 30
ORDER BY id;

ANSWER
=========
ID JOB
--- ----10 Mgr
20 Sales
30 Mgr

Figure 70, BETWEEN Predicate examples

Figure 71, EXISTS Predicate syntax

SELECT id, job


FROM
staff a
WHERE EXISTS
(SELECT *
FROM
staff b
WHERE b.id = a.id
AND b.id < 50)
ORDER BY id;
Figure 72, EXISTS Predicate example

Figure 73, IN Predicate syntax

ANSWER
=========
ID JOB
--- ----10 Mgr
20 Sales
30 Mgr
40 Sales

SELECT
FROM
WHERE
AND

id, job
staff a
id IN (10,20,30)
id IN (SELECT id
FROM
staff)
AND id NOT IN 99
ORDER BY id;
Figure 74, IN Predicate examples, single values

ANSWER
=========
ID JOB
--- ----10 Mgr
20 Sales
30 Mgr

SELECT
FROM
WHERE

ANSWER
===============
EMPNO LASTNAME
------ ------000260 JOHNSON
000270 PEREZ

empno, lastname
employee
(empno, 'AD3113') IN
(SELECT empno, projno
FROM
emp_act
WHERE emptime > 0.5)
ORDER BY 1;
Figure 75, IN Predicate example, multi-value

Figure 76, LIKE Predicate syntax

SELECT id, name


FROM
staff
WHERE name LIKE 'S%n'
OR name LIKE '_a_a%'
OR name LIKE '%r_%a'
ORDER BY id;
Figure 77, LIKE Predicate examples

LIKE STATEMENT TEXT


===========================
LIKE 'AB%'
LIKE 'AB%'
ESCAPE '+'
LIKE 'AB+%'
ESCAPE '+'
LIKE 'AB++'
ESCAPE '+'
LIKE 'AB+%%'
ESCAPE '+'
LIKE 'AB++%'
ESCAPE '+'
LIKE 'AB+++%'
ESCAPE '+'
LIKE 'AB+++%%'
ESCAPE '+'
LIKE 'AB+%+%%'
ESCAPE '+'
LIKE 'AB++++'
ESCAPE '+'
LIKE 'AB+++++%' ESCAPE '+'
LIKE 'AB++++%'
ESCAPE '+'

ANSWER
==============
ID
NAME
--- --------130 Yamaguchi
200 Scoutten

WHAT VALUES MATCH


======================
Finds AB, any string
Finds AB, any string
Finds AB%
Finds AB+
Finds AB%, any string
Finds AB+, any string
Finds AB+%
Finds AB+%, any string
Finds AB%%, any string
Finds AB++
Finds AB++%
Finds AB++, any string

LIKE 'AB+%++%'
ESCAPE '+'
Figure 78, LIKE and ESCAPE examples

SELECT
FROM
WHERE
AND
AND
AND
AND
Figure

Finds AB%+, any string

id
staff
id = 10
'ABC' LIKE 'AB%'
'A%C' LIKE 'A/%C' ESCAPE '/'
'A_C' LIKE 'A\_C' ESCAPE '\'
'A_$' LIKE 'A$_$$' ESCAPE '$';
79, LIKE and ESCAPE examples

ANSWER
======
ID
--10

Figure 80, NULL Predicate syntax

SELECT
id, comm
FROM
staff
WHERE
id
< 100
AND
id
IS NOT NULL
AND
comm IS
NULL
AND NOT comm IS NOT NULL
ORDER BY id;
Figure 81, NULL predicate examples

ANSWER
=========
ID
COMM
--- ---10 30 50 -

SELECT

id
,name
FROM
staff
WHERE
name LIKE '%a' || X'3B' || '%'
ORDER BY id;
Figure 82, Refer to semi-colon in SQL text

Example:

555 +

-22

(12 - 3) * 66

^
^
^
^
5th 2nd 3rd
1st
Figure 83, Precedence rules example

^
4th

ANSWER
======
423

SELECT

FROM

(12
,
-22 / (12
,
-22 / (12
,555 + -22 / (12
sysibm.sysdummy1;

3)
3)
3) * 66
3) * 66

AS
AS
AS
AS

int1
int2
int3
int4

ANSWER
===================
INT1 INT2 INT3 INT4
---- ---- ---- ---9
-2 -132 423

Figure 84, Precedence rules, integer example

SELECT

FROM

(12.0
,
-22 / (12.0
,
-22 / (12.0
,555 + -22 / (12.0
sysibm.sysdummy1;

3)
3)
3) * 66
3) * 66

AS
AS
AS
AS

dec1
dec2
dec3
dec4

ANSWER
===========================
DEC1
DEC2
DEC3
DEC4
------ ------ ------ -----9.0
-2.4 -161.3 393.6
Figure 85, Precedence rules, decimal example

SELECT
FROM
WHERE
AND
OR
ORDER BY

*
table1
col1 = 'C'
col1 >= 'A'
col2 >= 'AA'
col1;

ANSWER>>

COL1 COL2
---- ---A
AA
B
BB
C
CC

SELECT
*
FROM
table1
WHERE
(col1 = 'C'
AND
col1 >= 'A')
OR
col2 >= 'AA'
ORDER BY col1;

ANSWER>>

COL1
---A
B
C

SELECT
*
ANSWER>>
FROM
table1
WHERE
col1 = 'C'
AND
(col1 >= 'A'
OR
col2 >= 'AA')
ORDER BY col1;
Figure 86, Use of OR and parenthesis

Figure 87, CAST expression syntax

COL2
---AA
BB
CC

COL1 COL2
---- ---C
CC

TABLE1
+---------+
|COL1|COL2|
|----|----|
|A
|AA |
|B
|BB |
|C
|CC |
+---------+

SELECT

id
,salary
,CAST(salary AS INTEGER) AS sal2
FROM
staff
WHERE
id < 30
ORDER BY id;
Figure 88, Use CAST expression to convert Decimal to

ANSWER
=================
ID SALARY
SAL2
-- -------- ----10 18357.50 18357
20 18171.25 18171
Integer

SELECT

ANSWER
=============
ID JOB
JOB2
-- ----- ---10 Mgr
Mgr
20 Sales Sal

id
,job
,CAST(job AS CHAR(3)) AS job2
FROM
staff
WHERE
id < 30
ORDER BY id;
Figure 89, Use CAST expression to truncate Char field

SELECT

id
,CAST(NULL AS SMALLINT) AS junk
FROM
staff
WHERE
id < 30
ORDER BY id;

ANSWER
=======
ID JUNK
-- ---10
20
Figure 90, Use CAST expression to define SMALLINT field with null values

SELECT

stf.id
,emp.empno
FROM
staff
stf
LEFT OUTER JOIN
employee emp
ON
stf.id
= CAST(emp.empno AS SMALLINT)
AND
emp.job = 'MANAGER'
WHERE
stf.id
< 60
ORDER BY stf.id;
Figure 91, CAST expression in join

ANSWER
=========
ID EMPNO
-- -----10 20 000020
30 000030
40 50 000050

SELECT

ANSWER
=========

stf.id
,emp.empno

FROM
staff
stf
LEFT OUTER JOIN
employee emp
ON
stf.id
= SMALLINT(emp.empno)
AND
emp.job = 'MANAGER'
WHERE
stf.id
< 60
ORDER BY stf.id;
Figure 92, Function usage in join

ID
-10
20
30
40
50

EMPNO
-----000020
000030
000050

Figure 93, VALUES expression syntax

VALUES
6
VALUES (6)
VALUES
6, 7, 8
VALUES (6), (7), (8)
VALUES (6,66), (7,77), (8,NULL)
Figure 94, VALUES usage examples

<=
<=
<=
<=
<=

1
1
1
3
3

row,
row,
row,
rows,
rows,

1
1
3
1
2

column
column
columns
column
columns

WITH temp1 (col1, col2) AS


(VALUES
(
0, 'AA')
,(
1, 'BB')
,(
2, NULL)
)
SELECT *
FROM
temp1;
Figure 95, Use VALUES to define a temporary table (1 of 4)

ANSWER
=========
COL1 COL2
---- ---0 AA
1 BB
2 -

WITH temp1 (col1, col2) AS


(VALUES
(DECIMAL(0 ,3,1), 'AA')
,(DECIMAL(1 ,3,1), 'BB')
,(DECIMAL(2 ,3,1), NULL)
)
SELECT *
FROM
temp1;
Figure 96, Use VALUES to define a temporary table (2 of 4)

ANSWER
=========
COL1 COL2
---- ---0.0 AA
1.0 BB
2.0 -

WITH temp1 (col1, col2) AS


(VALUES
(
0, CAST('AA' AS CHAR(1)))

ANSWER
=========

,(
,(

1, CAST('BB' AS CHAR(1)))
2, CAST(NULL AS CHAR(1)))

)
SELECT *
FROM
temp1;
Figure 97, Use VALUES to define a temporary table (3 of 4)

WITH temp1 (col1, col2) AS


(VALUES
(
0, CHAR('AA',1))
,(
1, CHAR('BB',1))
,(
2, NULL)
)
SELECT *
FROM
temp1;
Figure 98, Use VALUES to define a temporary table (4 of 4)

WITH temp1 (col1, col2, col3) AS


(VALUES
(
0, 'AA', 0.00)
,(
1, 'BB', 1.11)
,(
2, 'CC', 2.22)
)
,temp2 (col1b, colx) AS
(SELECT col1
,col1 + col3
FROM
temp1
)
SELECT *
FROM
temp2;
Figure 99, Derive one temporary table from another

COL1
---0
1
2

COL2
---A
B
-

ANSWER
=========
COL1 COL2
---- ---0 A
1 B
2 -

ANSWER
==========
COL1B COLX
----- ---0 0.00
1 2.11
2 4.22

CREATE VIEW silly (c1, c2, c3)


AS VALUES (11, 'AAA', SMALLINT(22))
,(12, 'BBB', SMALLINT(33))
,(13, 'CCC', NULL);
COMMIT;
Figure 100, Define a view using a VALUES clause

WITH temp1 (col1) AS


(VALUES
0
UNION ALL
SELECT col1 + 1
FROM
temp1
WHERE col1 + 1 < 100

ANSWER
======
COL1
---0
1

)
2
SELECT *
3
FROM
temp1;
etc
Figure 101, Use VALUES defined data to seed a recursive SQL statement

SELECT
FROM

*
(VALUES (123,'ABC')
,(234,'DEF')
)AS ttt
ORDER BY 1 DESC;
Figure 102, Generate table with unnamed columns

ANSWER
======
--- --234 DEF
123 ABC

Figure 103, CASE expression syntax - 1st type

SELECT

Lastname
,sex
AS sx
,CASE sex
WHEN 'F' THEN 'FEMALE'
WHEN 'M' THEN 'MALE'
ELSE NULL
END AS sexx
FROM
employee
WHERE
lastname LIKE 'J%'
ORDER BY 1;
Figure 104, Use CASE (1st type) to expand a value

ANSWER
====================
LASTNAME
SX SEXX
---------- -- -----JEFFERSON M MALE
JOHNSON
F FEMALE
JONES
M MALE

Figure 105, CASE expression syntax - 2nd type

SELECT

lastname
,sex
AS sx
,CASE
WHEN sex = 'F' THEN 'FEMALE'
WHEN sex = 'M' THEN 'MALE'
ELSE NULL
END AS sexx
FROM
employee
WHERE
lastname LIKE 'J%'
ORDER BY 1;

ANSWER
====================
LASTNAME
SX SEXX
---------- -- -----JEFFERSON M MALE
JOHNSON
F FEMALE
JONES
M MALE

Figure 106, Use CASE (1st type) to expand a value

SELECT

lastname
ANSWER
,midinit AS mi
===================
,sex
AS sx
LASTNAME
MI SX MX
,CASE
---------- -- -- -WHEN midinit > SEX
JEFFERSON J M M
THEN midinit
JOHNSON
P F P
ELSE sex
JONES
T M T
END AS mx
FROM
employee
WHERE
lastname LIKE 'J%'
ORDER BY 1;
Figure 107, Use CASE to display the higher of two values

SELECT

COUNT(*)
,SUM(CASE sex WHEN 'F' THEN 1 ELSE 0 END)
,SUM(CASE sex WHEN 'M' THEN 1 ELSE 0 END)
FROM
employee
WHERE
lastname LIKE 'J%';
Figure 108, Use CASE to get multiple counts in one

SELECT

lastname
,LENGTH(RTRIM(lastname)) AS len
,SUBSTR(lastname,1,
CASE
WHEN LENGTH(RTRIM(lastname))
> 6 THEN 6
ELSE LENGTH(RTRIM(lastname))
END ) AS lastnm
FROM
employee
WHERE
lastname LIKE 'J%'
ORDER BY 1;
Figure 109, Use CASE inside a function

UPDATE staff
SET
comm = CASE dept
WHEN 15 THEN comm *
WHEN 20 THEN comm *
WHEN 38 THEN
CASE
WHEN years <
WHEN years >=

AS tot
AS #f
AS #m

ANSWER
=========
TOT #F #M
--- -- -3 1 2

pass

ANSWER
=====================
LASTNAME
LEN LASTNM
---------- --- -----JEFFERSON
9 JEFFER
JOHNSON
7 JOHNSO
JONES
5 JONES

1.1
1.2
5 THEN comm * 1.3
5 THEN comm * 1.4

ELSE NULL
END
ELSE comm

END
WHERE comm IS NOT NULL
AND dept < 50;
Figure 110, UPDATE statement with nested CASE expressions

WITH temp1 (c1,c2) AS


(VALUES
(88,9),(44,3),(22,0),(0,1))
SELECT c1
,c2
,CASE c2
WHEN 0 THEN NULL
ELSE c1/c2
END AS c3
FROM
temp1;
Figure 111, Use CASE to avoid divide by zero

ANSWER
========
C1 C2 C3
-- -- -88 9 9
44 3 14
22 0 0 1 0

SELECT

lastname
,sex
,CASE
WHEN sex >= 'M' THEN 'MAL'
WHEN sex >= 'F' THEN 'FEM'
END AS sxx
FROM
employee
WHERE
lastname LIKE 'J%'
ORDER BY 1;
Figure 112, Use CASE to derive a value (correct)

ANSWER
=================
LASTNAME
SX SXX
---------- -- --JEFFERSON M MAL
JOHNSON
F FEM
JONES
M MAL

SELECT

ANSWER
=================
LASTNAME
SX SXX
---------- -- --JEFFERSON M FEM
JOHNSON
F FEM
JONES
M FEM

lastname
,sex
,CASE
WHEN sex >= 'F' THEN 'FEM'
WHEN sex >= 'M' THEN 'MAL'
END AS sxx
FROM
employee
WHERE
lastname LIKE 'J%'
ORDER BY 1;
Figure 113, Use CASE to derive a value (incorrect)

SELECT

id
,dept

ANSWER
=======================

,salary
,comm
FROM
staff
WHERE
CASE
WHEN comm
<
70
WHEN name
LIKE 'W%'
WHEN salary
< 11000
WHEN salary
< 18500
AND dept
<>
33
WHEN salary
< 19000
END IN ('A','C','E')
ORDER BY id;
Figure 114, Use CASE in a predicate

SELECT

FROM
WHERE
OR
OR

id
,name
,salary
,comm
staff
(comm
< 70)
(salary < 11000
(salary < 19000

THEN 'A'
THEN 'B'
THEN 'C'

ID DEPT SALARY
COMM
--- ---- -------- ----130
42 10505.90 75.60
270
66 18555.50
330
66 10988.00 55.50

THEN 'D'
THEN 'E'

ANSWER
=======================
ID DEPT SALARY
COMM
--- ---- -------- ----130
42 10505.90 75.60
270
66 18555.50
330
66 10988.00 55.50
AND NOT name LIKE 'W%')
AND NOT (name LIKE 'W%'
OR (salary < 18500 AND dept <> 33)))

ORDER BY id;
Figure 115, Same stmt as prior, without CASE predicate

Figure 116, DECLARE CURSOR statement syntax

DECLARE fred CURSOR FOR


WITH RETURN TO CALLER
SELECT
id
,name
,salary
,comm
FROM
staff
WHERE
id
< :id-var
AND
salary
> 1000
ORDER BY id ASC
FETCH FIRST 10 ROWS ONLY
OPTIMIZE FOR 10 ROWS
FOR FETCH ONLY
WITH UR
Figure 117, Sample cursor

DECLARE fred CURSOR WITH HOLD FOR


SELECT
name
,salary
FROM
staff
WHERE
id > :id-var
FOR UPDDATE OF salary, comm
OPEN fred
DO UNTIL SQLCODE = 100
FETCH
INTO

fred
:name-var
,:salary-var

IF salary < 1000 THEN DO


UPDATE staff
SET
salary = :new-salary-var
WHERE CURRENT OF fred
END-IF
END-DO
CLOSE fred
Figure 118, Use cursor in program

SELECT

name
,salary
INTO
:name-var
,:salary-var
FROM
staff
WHERE
id = :id-var
Figure 119, Singleton select

Figure 120, PREPARE statement syntax

STATEMENT CAN BE USED BY


STATEMENT TYPE
========================
==============
DESCRIBE
Any statement
DECLARE CURSOR
Must be SELECT
EXECUTE
Must not be SELECT
Figure 121, What statements can use prepared statement

SET :host-var = CURRENT TIMESTAMP


Figure 122, SET single host-variable

SET :host-v1 = CURRENT TIME


,:host-v2 = CURRENT DEGREE
,:host-v3 = NULL
Figure 123, SET multiple host-variables

SET

(:hv1
,:hv2
,:hv3) =
(SELECT id
,name
,salary
FROM
staff
WHERE
id = :id-var)
Figure 124, SET using row-fullselect

SET CONNECTION
SET CURRENT DEFAULT TRANSFORM GROUP
SET CURRENT DEGREE
SET CURRENT EXPLAIN MODE
SET CURRENT EXPLAIN SNAPSHOT
SET CURRENT ISOLATION
SET CURRENT LOCK TIMEOUT
SET CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION
SET CURRENT PACKAGE PATH
SET CURRENT PACKAGESET
SET CURRENT QUERY OPTIMIZATION
SET CURRENT REFRESH AGE
SET ENCRYPTION PASSWORD
SET EVENT MONITOR STATE
SET INTEGRITY
SET PASSTHRU
SET PATH
SET SCHEMA
SET SERVER OPTION
SET SESSION AUTHORIZATION
Figure 125, Other SET statements

Figure 126, SAVEPOINT statement syntax

Figure 127, Example of savepoint usage

Figure 128, RELEASE SAVEPOINT statement syntax

Figure 129, ROLLBACK statement syntax

CREATE TABLE emp_act


(empno
CHARACTER (00006)
,projno
CHARACTER (00006)
,actno
SMALLINT
,emptime
DECIMAL
(05,02)
,emstdate
DATE
,emendate
DATE);
Figure 130, EMP_ACT sample table - DDL

NOT NULL
NOT NULL
NOT NULL

Figure 131, INSERT statement syntax

INSERT INTO emp_act VALUES


('100000' ,'ABC' ,10 ,1.4 ,'2003-10-22', '2003-11-24');
Figure 132, Single row insert

INSERT INTO emp_act VALUES


('200000' ,'ABC' ,10 ,1.4 ,'2003-10-22', '2003-11-24')

,('200000' ,'DEF' ,10 ,1.4 ,'2003-10-22', '2003-11-24')


,('200000' ,'IJK' ,10 ,1.4 ,'2003-10-22', '2003-11-24');
Figure 133, Multi row insert

INSERT INTO emp_act VALUES


('400000' ,'ABC' ,10 ,NULL ,DEFAULT, CURRENT DATE);
Figure 134,Using null and default values

INSERT INTO emp_act (projno, emendate, actno, empno) VALUES


('ABC' ,DATE(CURRENT TIMESTAMP) ,123 ,'500000');
Figure 135, Explicitly listing columns being populated during insert

INSERT INTO
(SELECT *
FROM
emp_act
WHERE empno < '1'
)
VALUES ('510000' ,'ABC' ,10 ,1.4 ,'2003-10-22', '2003-11-24');
Figure 136, Insert into a full-select

INSERT INTO emp_act


SELECT LTRIM(CHAR(id + 600000))
,SUBSTR(UCASE(name),1,6)
,salary / 229
,123
,CURRENT DATE
,'2003-11-11'
FROM
staff
WHERE id < 50;
Figure 137,Insert result of select statement

INSERT INTO emp_act (empno, actno, projno)


SELECT LTRIM(CHAR(id + 700000))
,MINUTE(CURRENT TIME)
,'DEF'
FROM
staff
WHERE id < 40;
Figure 138, Insert result of select - specified columns only

INSERT
SELECT
FROM
Figure

INTO emp_act
*
emp_act;
139, Stupid - insert - doubles rows

INSERT INTO emp_act (empno, actno, projno)


SELECT LTRIM(CHAR(id + 800000))
,77
,'XYZ'
FROM
staff
WHERE id < 40
UNION
SELECT LTRIM(CHAR(id + 900000))
,SALARY / 100
,'DEF'
FROM
staff
WHERE id < 50;
Figure 140, Inserting result of union

INSERT INTO emp_act (empno, actno, projno, emptime)


WITH temp1 (col1) AS
(VALUES (1),(2),(3),(4),(5),(6))
SELECT LTRIM(CHAR(col1 + 910000))
,col1
,CHAR(col1)
,col1 / 2
FROM
temp1;
Figure 141, Insert from common table expression

INSERT INTO emp_act (empno, actno, projno)


SELECT LTRIM(CHAR(id + 920000))
,id
,'ABC'
FROM
staff
WHERE id < 40
AND NOT EXISTS
(SELECT *
FROM
emp_act
WHERE empno LIKE '92%');
Figure 142, Insert with irrelevant sub-query

CREATE TABLE us_customer


CREATE TABLE intl_customer
(cust#
INTEGER
NOT NULL
(cust#
INTEGER
NOT NULL
,cname
CHAR(10) NOT NULL
,cname
CHAR(10) NOT NULL
,country CHAR(03) NOT NULL
,country CHAR(03) NOT NULL
,CHECK
(country = 'USA')
,CHECK
(country <> 'USA')
,PRIMARY KEY (cust#));
,PRIMARY KEY (cust#));
Figure 143, Customer tables - for insert usage

INSERT INTO
(SELECT
*
FROM
us_customer
UNION ALL
SELECT
*
FROM
intl_customer)
VALUES (111,'Fred','USA')
,(222,'Dave','USA')
,(333,'Juan','MEX');
Figure 144, Insert into multiple tables

UPDATE
SET

emp_act
emptime = NULL
,emendate = DEFAULT
,emstdate = CURRENT DATE + 2 DAYS
,actno
= ACTNO / 2
,projno
= 'ABC'
WHERE
empno
= '100000';
Figure 145, Single row update

Figure 146, UPDATE statement syntax

UPDATE emp_act
SET
actno = actno / 2;
Figure 147, Mass update

UPDATE
SET

emp_act ac1
actno
= actno * 2
,emptime
= actno * 2
WHERE
empno LIKE '910%';
Figure 148, Two columns get same value

UPDATE
SET

emp_act
actno

= (SELECT MAX(salary)
FROM
staff)
WHERE
empno
= '200000';
Figure 149, Update using select

UPDATE emp_act
SET
(actno
,emstdate
,projno) = (SELECT MAX(salary)
,CURRENT DATE + 2 DAYS
,MIN(CHAR(id))
FROM
staff
WHERE id <> 33)
WHERE
empno LIKE '600%';
Figure 150, Multi-row update using select

UPDATE emp_act ac1


SET
(actno
,emptime) = (SELECT ac2.actno
+ 1
,ac1.emptime / 2
FROM
emp_act ac2
WHERE ac2.empno
LIKE '60%'
AND SUBSTR(ac2.empno,3) = SUBSTR(ac1.empno,3))
WHERE
EMPNO LIKE '700%';
Figure 151, Multi-row update using correlated select

UPDATE emp_act
SET
emptime = 10
WHERE
empno
= '000010'
AND
projno = 'MA2100';
Figure 152, Direct update of table

UPDATE
(SELECT *
FROM
emp_act
WHERE
empno
= '000010'
AND
projno = 'MA2100'
)AS ea
SET emptime = 20;
Figure 153, Update of full-select

UPDATE
SET

emp_act ea1
emptime = (SELECT MAX(emptime)
FROM
emp_act ea2
WHERE ea1.empno = ea2.empno)
WHERE
empno
= '000010'
AND
projno = 'MA2100';
Figure 154, Set employee-time in row to MAX - for given employee

UPDATE
(SELECT

ea1.*
,MAX(emptime) OVER(PARTITION BY empno) AS maxtime
emp_act ea1

FROM
)AS ea2
SET
emptime
WHERE
empno
AND
projno
Figure 155, Use

= maxtime
= '000010'
= 'MA2100';
OLAP function to get max-time, then apply (correct)

UPDATE emp_act
SET
emptime
WHERE
empno
AND
projno
Figure 156, Use

= MAX(emptime) OVER(PARTITION BY empno)


= '000010'
= 'MA2100';
OLAP function to get max-time, then apply (wrong)

UPDATE emp_act ac1


SET
(actno
,emptime) = (SELECT ROW_NUMBER() OVER()
,ac1.emptime / 2
FROM
emp_act ac2
WHERE ac2.empno
LIKE '60%'
AND SUBSTR(ac2.empno,3) = SUBSTR(ac1.empno,3))
WHERE
EMPNO LIKE '800%';
Figure 157, Update with correlated query

UPDATE emp_act ac1


SET
(actno
,emptime) = (SELECT c1
,c2
FROM (SELECT ROW_NUMBER() OVER() AS c1
,actno / 100
AS c2
,empno
FROM
emp_act
WHERE empno LIKE '60%'
)AS ac2
WHERE SUBSTR(ac2.empno,3) = SUBSTR(ac1.empno,3))
WHERE
empno LIKE '900%';
Figure 158, Update with uncorrelated query

DELETE
FROM
emp_act
WHERE
empno
= '000010'
AND
projno
= 'MA2100'
AND
actno
= 10;
Figure 159, Single-row delete

Figure 160, DELETE statement syntax

DELETE
FROM
emp_act;
Figure 161, Mass delete

DELETE
FROM
emp_act
WHERE
empno
LIKE '00%'
AND
projno
>= 'MA';
Figure 162, Selective delete

DELETE
FROM
WHERE

staff s1
id NOT IN
(SELECT MAX(id)
FROM
staff s2
WHERE s1.dept = s2.dept);
Figure 163, Correlated delete (1 of 2)

DELETE
FROM
WHERE

staff s1
EXISTS
(SELECT *
FROM
staff s2
WHERE s2.dept = s1.dept
AND s2.id
> s1.id);
Figure 164, Correlated delete (2 of 2)

DELETE FROM
(SELECT id
,MAX(id) OVER(PARTITION BY dept) AS max_id
FROM
staff
)AS ss
WHERE id <> max_id;
Figure 165, Delete using full-select and OLAP function

DELETE
FROM
emp_act
WHERE (empno, projno, actno) IN
(SELECT empno
,projno
,actno
FROM
(SELECT eee.*
,ROW_NUMBER()
OVER(ORDER BY empno, projno, actno) AS r#
FROM
emp_act eee
)AS xxx
WHERE
r# <= 10);
Figure 166, Delete first "n" rows

Figure 167, Select DML statement syntax

SELECT

ANSWER
==============
EMPNO PRJ ACT
------ --- --200000 ABC 10
200000 DEF 10

empno
,projno AS prj
,actno AS act
FROM
FINAL TABLE
(INSERT INTO emp_act
VALUES ('200000','ABC',10 ,1,'2003-10-22','2003-11-24')
,('200000','DEF',10 ,1,'2003-10-22','2003-11-24'))
ORDER BY 1,2,3;
Figure 168, Select rows inserted

SELECT

empno
,projno AS prj
,actno AS act
,row#
AS r#
FROM
FINAL TABLE
(INSERT INTO emp_act (empno, projno, actno)
INCLUDE (row# SMALLINT)
VALUES ('300000','ZZZ',999,1)
,('300000','VVV',111,2))
ORDER BY row#;
Figure 169, Include column to get insert sequence

ANSWER
=================
EMPNO PRJ ACT R#
------ --- --- -300000 ZZZ 999 1
300000 VVV 111 2

SELECT

empno
,projno AS prj
,actno AS act
,ROW_NUMBER() OVER() AS r#
FROM
FINAL TABLE
(INSERT INTO emp_act (empno, projno, actno)
VALUES ('400000','ZZZ',999)
,('400000','VVV',111))
ORDER BY INPUT SEQUENCE;
Figure 170, Select rows in insert order

ANSWER
=================
EMPNO PRJ ACT R#
------ --- --- -400000 ZZZ 999 1
400000 VVV 111 2

SELECT

ANSWER
=================
EMPNO PRJ ACT R#
------ --- -- -600010 1
59 1
600020 563 59 2
600030 193 59 3

empno
,projno AS prj
,actno AS act
,ROW_NUMBER() OVER() AS r#
FROM
NEW TABLE
(INSERT INTO emp_act (empno, actno, projno)
SELECT LTRIM(CHAR(id + 600000))
,SECOND(CURRENT TIME)
,CHAR(SMALLINT(RAND(1) * 1000))

FROM
staff
WHERE
id < 40)
ORDER BY INPUT SEQUENCE;
Figure 171, Select from an insert that has unknown values

SELECT

empno
,projno AS prj
,emptime AS etime
FROM
OLD TABLE
(UPDATE emp_act
SET
emptime = emptime * 2
WHERE empno
= '200000')
ORDER BY projno;
Figure 172, Select values - from before update

ANSWER
================
EMPNO PRJ ETIME
------ --- ----200000 ABC 1.00
200000 DEF 1.00

SELECT

ANSWER
===============
PRJ OLD_T NEW_T
--- ----- ----ABC 2.00 0.02
DEF 2.00 11.27

SELECT

ANSWER
=======
PRJ ACT
--- --VVV 111
ZZZ 999

SELECT

ANSWER
====================
EMPNO PROJNO ACT R#
------ ------ --- -000260 AD3113 70 2
000260 AD3113 80 4
000260 AD3113 180 6

projno AS prj
,old_t
AS old_t
,emptime AS new_t
FROM
NEW TABLE
(UPDATE emp_act
INCLUDE (old_t DECIMAL(5,2))
SET
emptime = emptime * RAND(1) * 10
,old_t
= emptime
WHERE
empno
= '200000')
ORDER BY 1;
Figure 173, Select values - before and after update

projno AS prj
,actno AS act
FROM
OLD TABLE
(DELETE
FROM
emp_act
WHERE empno = '300000')
ORDER BY 1,2;
Figure 174, List deleted rows

empno
,projno
,actno AS act
,row#
AS r#
FROM
OLD TABLE
(DELETE
FROM
emp_act

INCLUDE (row# SMALLINT)


SET
row# = ROW_NUMBER() OVER()
WHERE
empno = '000260')
WHERE
row# = row# / 2 * 2
ORDER BY 1,2,3;
Figure 175, Assign row numbers to deleted rows

SELECT

empno
,(SELECT lastname
FROM
(SELECT empno AS e#
,lastname
FROM
employee
)AS xxx
WHERE
empno = e#)
,projno AS projno
,actno AS act
FROM
OLD TABLE
(DELETE
FROM
emp_act
WHERE
empno < '0001')
FETCH FIRST 5 ROWS ONLY;
Figure 176, Join result to another table

ANSWER
==========================
EMPNO LASTNAME PROJNO ACT
------ -------- ------ --000010 HAAS
AD3100 10
000010 HAAS
MA2100 10
000010 HAAS
MA2110 10
000020 THOMPSON PL2100 30
000030 KWAN
IF1000 10

Figure 177, MERGE statement syntax

CREATE TABLE old_staff AS


(SELECT id, job, salary
FROM
staff)
WITH NO DATA;
CREATE TABLE new_staff AS
(SELECT id, salary
FROM
staff)
WITH NO DATA;
INSERT
SELECT
FROM
WHERE
Figure

INTO old_staff
id, job, salary
staff
id BETWEEN 20 and 40;
178, Sample tables for merge

MERGE INTO old_staff oo


USING new_staff nn

OLD_STAFF
+-----------------+
|ID|JOB |SALARY |
|--|-----|--------|
|20|Sales|18171.25|
|30|Mgr |17506.75|
|40|Sales|18006.00|
+-----------------+
INSERT
SELECT
FROM
WHERE

NEW_STAFF
+----------+
|ID|SALARY |
|--|-------|
|30|1750.67|
|40|1800.60|
|50|2065.98|
+----------+

INTO new_staff
id, salary / 10
staff
id BETWEEN 30 and 50;

OLD_STAFF
+-----------------+

NEW_STAFF
+----------+

ON
oo.id = nn.id
WHEN MATCHED THEN
UPDATE
SET oo.salary = nn.salary
WHEN NOT MATCHED THEN
INSERT
VALUES (nn.id,'?',nn.salary);

|ID|JOB |SALARY |
|--|-----|--------|
|20|Sales|18171.25|
|30|Mgr |17506.75|
|40|Sales|18006.00|
+-----------------+

Figure 179, Merge - do update or insert

MERGE INTO old_staff oo


USING new_staff nn
ON
oo.id = nn.id
WHEN MATCHED THEN
DELETE;
Figure 180, Merge - delete if match

|ID|SALARY |
|--|-------|
|30|1750.67|
|40|1800.60|
|50|2065.98|
+----------+

AFTER-MERGE
=================
ID JOB
SALARY
-- ----- -------20 Sales 18171.25
30 Mgr
1750.67
40 Sales 1800.60
50 ?
2065.98

AFTER-MERGE
=================
ID JOB
SALARY
-- ----- -------20 Sales 18171.25

MERGE INTO old_staff oo


OLD_STAFF
NEW_STAFF
USING new_staff nn
+-----------------+ +----------+
ON
oo.id = nn.id
|ID|JOB |SALARY | |ID|SALARY |
WHEN MATCHED
|--|-----|--------| |--|-------|
AND oo.salary < 18000 THEN
|20|Sales|18171.25| |30|1750.67|
UPDATE
|30|Mgr |17506.75| |40|1800.60|
SET oo.salary = nn.salary
|40|Sales|18006.00| |50|2065.98|
WHEN MATCHED
+-----------------+ +----------+
AND oo.salary > 18000 THEN
DELETE
AFTER-MERGE
WHEN NOT MATCHED
=================
AND nn.id > 10 THEN
ID JOB
SALARY
INSERT
-- ----- -------VALUES (nn.id,'?',nn.salary)
20 Sales 18171.25
WHEN NOT MATCHED THEN
30 Mgr
1750.67
SIGNAL SQLSTATE '70001'
50 ?
2065.98
SET MESSAGE_TEXT = 'New ID <= 10';
Figure 181, Merge with multiple options

MERGE INTO old_staff


USING
(SELECT MAX(id) + 1 AS max_id
,MAX(job)
AS max_job
,MAX(salary) AS max_sal

AFTER-MERGE
=================
ID JOB
SALARY
-- ----- -------20 Sales 18171.25

FROM
old_staff
)AS mx
ON
id = max_id
WHEN NOT MATCHED THEN
INSERT
VALUES (max_id, max_job, max_sal);
Figure 182, Merge MAX row into table

30 Mgr
17506.75
40 Sales 18006.00
41 Sales 18171.25

INSERT INTO old_staff


SELECT MAX(id) + 1 AS max_id
,MAX(job)
AS max_job
,MAX(salary) AS max_sal
FROM
old_staff;
Figure 183, Merge logic - done using insert

MERGE INTO
OLD_STAFF
NEW_STAFF
(SELECT *
+-----------------+ +----------+
FROM
old_staff
|ID|JOB |SALARY | |ID|SALARY |
WHERE id < 40
|--|-----|--------| |--|-------|
)AS oo
|20|Sales|18171.25| |30|1750.67|
USING
|30|Mgr |17506.75| |40|1800.60|
(SELECT *
|40|Sales|18006.00| |50|2065.98|
FROM
new_staff
+-----------------+ +----------+
WHERE id < 50
)AS nn
AFTER-MERGE
ON
oo.id = nn.id
=================
WHEN MATCHED THEN
ID JOB
SALARY
DELETE
-- ----- -------WHEN NOT MATCHED THEN
20 Sales 18171.25
INSERT
40 ?
1800.60
VALUES (nn.id,'?',nn.salary);
40 Sales 18006.00
Figure 184, Merge using two full-selects

MERGE INTO old_staff oo


USING new_staff nn
ON
oo.id = nn.id
WHEN MATCHED THEN
UPDATE
SET (salary,job) = (1234,'?')
WHEN NOT MATCHED THEN
INSERT (id,salary,job)
VALUES (id,5678.9,'?');
Figure 185, Listing columns and values in insert

AFTER-MERGE
=================
ID JOB
SALARY
-- ----- -------20 Sales 18171.25
30 ?
1234.00
40 ?
1234.00
50 ?
5678.90

Figure 186, Compound SQL Statement syntax

BEGIN ATOMIC
DECLARE cntr SMALLINT DEFAULT 1;
FOR V1 AS
SELECT
id as idval
FROM
staff
WHERE
id < 80
ORDER BY id
DO
UPDATE
staff
SET
comm = cntr
WHERE
id
= idval;
SET cntr = cntr + 1;
END FOR;
END
Figure 187, Sample Compound SQL statement

--#SET DELIMITER !
SELECT NAME FROM STAFF WHERE ID = 10!
--#SET DELIMITER ;
SELECT NAME FROM STAFF WHERE ID = 20;
Figure 188, Set Delimiter example

BEGIN ATOMIC
DECLARE aaa, bbb, ccc SMALLINT DEFAULT 1;
DECLARE ddd
CHAR(10) DEFAULT NULL;
DECLARE eee
INTEGER;
SET eee = aaa + 1;
UPDATE
staff
SET
comm
= aaa
,salary = bbb
,years = eee
WHERE
id
= 10;
END
Figure 189, DECLARE examples

Figure 190, FOR statement syntax

BEGIN ATOMIC
FOR V1 AS
SELECT

DO

dept
AS dname
,max(id) AS max_id
FROM
staff
GROUP BY dept
HAVING
COUNT(*) > 1
ORDER BY dept

UPDATE
SET
WHERE
UPDATE
set
WHERE
AND
END FOR;

staff
id
=
id
=
staff
dept =
dept =
dept <

id * -1
max_id;
dept / 10
dname
30;

END
Figure 191, FOR statement example

Figure 192, GET DIAGNOSTICS statement syntax

BEGIN ATOMIC
DECLARE numrows INT DEFAULT 0;
UPDATE staff
SET
salary = 12345
WHERE ID < 100;
GET DIAGNOSTICS numrows = ROW_COUNT;
UPDATE staff
SET
salary = numrows
WHERE ID = 10;
END
Figure 193, GET DIAGNOSTICS statement example

Figure 194, IF statement syntax

BEGIN ATOMIC
DECLARE cur INT;

SET cur = MICROSECOND(CURRENT TIMESTAMP);


IF cur > 600000 THEN
UPDATE staff
SET
name = CHAR(cur)
WHERE id
= 10;
ELSEIF cur > 300000 THEN
UPDATE staff
SET
name = CHAR(cur)
WHERE id
= 20;
ELSE
UPDATE staff
SET
name = CHAR(cur)
WHERE id
= 30;
END IF;
END
Figure 195, IF statement example

Figure 196, ITERATE statement syntax

BEGIN ATOMIC
DECLARE cntr INT DEFAULT 0;
whileloop:
WHILE cntr < 60 DO
SET cntr = cntr + 10;
UPDATE staff
SET
salary = cntr
WHERE id
= cntr;
ITERATE whileloop;
UPDATE staff
SET
comm
= cntr + 1
WHERE id
= cntr;
END WHILE;
END
Figure 197, ITERATE statement example

Figure 198, LEAVE statement syntax

BEGIN ATOMIC
DECLARE cntr INT DEFAULT 1;
whileloop:
WHILE 1 <> 2 DO
SET cntr = cntr + 1;
IF RAND() > 0.99 THEN

LEAVE whileloop;
END IF;
END WHILE;
UPDATE staff
SET
salary = cntr
WHERE ID = 10;
END
Figure 199, LEAVE statement example

Figure 200, SIGNAL statement syntax

BEGIN ATOMIC
DECLARE cntr INT DEFAULT 1;
DECLARE emsg CHAR(20);
whileloop:
WHILE RAND() < .99 DO
SET cntr = cntr + 1;
END WHILE;
SET emsg = '#loops: ' || CHAR(cntr);
SIGNAL SQLSTATE '75001' SET MESSAGE_TEXT = emsg;
END
Figure 201, SIGNAL statement example

Figure 202, WHILE statement syntax

BEGIN ATOMIC
DECLARE c1, C2 INT DEFAULT 1;
WHILE c1 < 10 DO
WHILE c2 < 20 DO
SET c2 = c2 + 1;
END WHILE;
SET c1 = c1 + 1;
END WHILE;
UPDATE staff
SET
salary = c1
,comm
= c2
WHERE id
= 10;
END
Figure 203, WHILE statement example

SELECT

dept
,count(*) as #rows
FROM
staff
GROUP BY dept
ORDER BY dept;

ANSWER
==========
DEPT #ROWS
---- ----10
4
15
4
20
4
38
5
42
4
51
5
66
5
84
4

Figure 204, List departments in STAFF table

--#SET DELIMITER !
CREATE TABLE dpt
(dept
SMALLINT
,#names SMALLINT
,PRIMARY KEY(dept))!
COMMIT!

NOT NULL

CREATE TRIGGER dpt1 AFTER INSERT ON dpt


REFERENCING NEW AS NNN
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
DECLARE namecnt SMALLINT DEFAULT 0;
FOR getnames AS
SELECT
COUNT(*) AS #n
FROM
staff
WHERE
dept = nnn.dept
DO
SET namecnt = #n;
END FOR;
UPDATE dpt
SET
#names = namecnt
WHERE dept
= nnn.dept;
END!
COMMIT!
INSERT INTO dpt (dept)
SELECT DISTINCT dept
FROM
staff!
COMMIT!
SELECT
*
FROM
dpt
ORDER BY dept!
Figure 205, Trigger with compound SQL

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

ANSWER
===========
DEPT #NAMES
---- -----10
4
15
4
20
4
38
5
42
4
51
5
66
5
84
4

--#SET DELIMITER !
CREATE FUNCTION dpt1 (deptin SMALLINT)
RETURNS SMALLINT
BEGIN ATOMIC
DECLARE num_names SMALLINT;
FOR getnames AS
SELECT
COUNT(*) AS #n
FROM
staff
WHERE
dept = deptin
DO
SET num_names = #n;
END FOR;
RETURN num_names;
END!
COMMIT!
SELECT

XXX.*
,dpt1(dept) as #names
FROM
(SELECT
dept
FROM
staff
GROUP BY dept
)AS XXX
ORDER BY dept!
Figure 206, Scalar Function with compound SQL

--#SET DELIMITER !
CREATE FUNCTION dpt1 (deptin SMALLINT)
RETURNS SMALLINT
BEGIN ATOMIC
RETURN
SELECT COUNT(*)
FROM
staff
WHERE dept = deptin;
END!
COMMIT!

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

ANSWER
===========
DEPT #NAMES
---- -----10
4
15
4
20
4
38
5
42
4
51
5
66
5
84
4

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

SELECT

XXX.*
,dpt1(dept) as #names
FROM
(SELECT
dept
FROM
staff
GROUP BY dept
)AS XXX
ORDER BY dept!
Figure 207, Scalar Function with compound SQL

--#SET DELIMITER !
CREATE FUNCTION dpt2 ()
RETURNS TABLE (dept
SMALLINT
,#names SMALLINT)
BEGIN ATOMIC

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

RETURN
SELECT

dept
,count(*)
FROM
staff
GROUP BY dept
ORDER BY dept;
END!
COMMIT!
--#SET DELIMITER ;
SELECT
*
FROM
TABLE(dpt2()) T1
ORDER BY dept;
Figure 208, Table Function with compound SQL

ANSWER
===========
DEPT #NAMES
---- -----10
4
15
4
20
4
38
5
42
4
51
5
66
5
84
4

Figure 209, AVG function syntax

SELECT

AVG(dept)
AS a1
,AVG(ALL dept)
AS a2
,AVG(DISTINCT dept) AS a3
,AVG(dept/10)
AS a4
,AVG(dept)/10
AS a5
FROM
staff
HAVING
AVG(dept) > 40;
Figure 210, AVG function examples

ANSWER
==============
A1 A2 A3 A4 A5
-- -- -- -- -41 41 40 3 4

UPDATE staff
SET
comm = 0
WHERE comm IS NULL;
SELECT AVG(salary) AS salary
,AVG(comm)
AS comm1
,AVG(CASE comm
WHEN 0 THEN NULL
ELSE comm
END) AS comm2
FROM
staff;
UPDATE
SET
WHERE
Figure

staff
comm = NULL
comm = 0;
211, Convert zero to null before doing AVG

ANSWER
===================
SALARY COMM1 COMM2
------- ----- ----16675.6 351.9 513.3

SELECT

COUNT(*) AS c1
,AVG(salary) AS a1
,COALESCE(AVG(salary),0) AS a2
,CASE
WHEN AVG(salary) IS NULL THEN 0
ELSE AVG(salary)
END AS a3
FROM
staff
WHERE
id < 10;
Figure 212, Convert null output (from AVG) to zero

SELECT
FROM

AVG(DAYS(birthdate))
,DATE(AVG(DAYS(birthdate)))
employee;

ANSWER
===========
C1 A1 A2 A3
-- -- -- -0 - 0 0

ANSWER
=================
1
2
------ ---------709113 1942-06-27

Figure 213, AVG of date column

SELECT AVG(avg_sal) AS avg_avg


FROM
(SELECT
dept
,AVG(salary) AS avg_sal
FROM
staff
GROUP BY dept
)AS xxx;
Figure 214, Select average of average

ANSWER
================

Figure 215, CORRELATION function syntax

WITH temp1(col1, col2, col3, col4) AS


(VALUES
(0
, 0
, 0
, RAND(1))
UNION ALL
SELECT col1 + 1
,col2 - 1
,RAND()
,RAND()
FROM
temp1
WHERE col1 <= 1000
)
SELECT DEC(CORRELATION(col1,col1),5,3)
,DEC(CORRELATION(col1,col2),5,3)
,DEC(CORRELATION(col2,col3),5,3)
,DEC(CORRELATION(col3,col4),5,3)

ANSWER
===========================
COR11 COR12 COR23 COR34
------ ------ ------ -----1.000 -1.000 -0.017 -0.005

AS
AS
AS
AS

cor11
cor12
cor23
cor34

FROM
temp1;
Figure 216, CORRELATION function examples

Figure 217, COUNT function syntax

SELECT COUNT(*)
,COUNT(INT(comm/10))
,COUNT(ALL INT(comm/10))
,COUNT(DISTINCT INT(comm/10))
,COUNT(DISTINCT INT(comm))
,COUNT(DISTINCT INT(comm))/10
FROM
staff;
Figure 218, COUNT function examples

SELECT
FROM
WHERE
UNION
SELECT

'NO GP-BY'
,COUNT(*)
staff
id = -1

AS
AS
AS
AS
AS
AS

c1
c2
c3
c4
c5
c6

ANSWER
=================
C1 C2 C3 C4 C5 C6
-- -- -- -- -- -35 24 24 19 24 2

AS c1
AS c2

ANSWER
============
C1
C2
-------- -NO GP-BY
0

'GROUP-BY' AS c1
,COUNT(*)
AS c2
FROM
staff
WHERE
id = -1
GROUP BY dept;
Figure 219, COUNT function with and without GROUP BY

Figure 220, COUNT_BIG function syntax

SELECT

COUNT_BIG(*)
AS
,COUNT_BIG(dept)
AS
,COUNT_BIG(DISTINCT dept)
AS
,COUNT_BIG(DISTINCT dept/10) AS
,COUNT_BIG(DISTINCT dept)/10 AS
FROM
STAFF;
Figure 221, COUNT_BIG function examples

c1
c2
c3
c4
c5

ANSWER
===================
C1 C2 C3 C4 C5
--- --- --- --- --35. 35. 8. 7. 0.

Figure 222, COVARIANCE function syntax

WITH temp1(c1, c2, c3, c4) AS


ANSWER
(VALUES
(0 , 0 , 0 , RAND(1))
===============================
UNION ALL
COV11
COV12
COV23
COV34
SELECT c1 + 1
------- ------- ------- ------,c2 - 1
83666. -83666. -1.4689 -0.0004
,RAND()
,RAND()
FROM
temp1
WHERE c1 <= 1000
)
SELECT DEC(COVARIANCE(c1,c1),6,0) AS cov11
,DEC(COVARIANCE(c1,c2),6,0) AS cov12
,DEC(COVARIANCE(c2,c3),6,4) AS cov23
,DEC(COVARIANCE(c3,c4),6,4) AS cov34
FROM
temp1;
Figure 223, COVARIANCE function examples

Figure 224, GROUPING function syntax

SELECT

dept
,AVG(salary)
AS salary
,GROUPING(dept) AS df
FROM
staff
GROUP BY ROLLUP(dept)
ORDER BY dept;

Figure 225, GROUPING function example

Figure 226, MAX function syntax

ANSWER
================
DEPT SALARY
DF
---- -------- -10 20865.86 0
15 15482.33 0
20 16071.52 0
38 15457.11 0
42 14592.26 0
51 17218.16 0
66 17215.24 0
84 16536.75 0
- 16675.64 1

SELECT

MAX(dept)
,MAX(ALL dept)
,MAX(DISTINCT dept)
,MAX(DISTINCT dept/10)
FROM
staff;
Figure 227, MAX function examples

SELECT MAX(hiredate)
,CHAR(MAX(hiredate),USA)
,MAX(CHAR(hiredate,USA))
FROM
employee;

ANSWER
===============
1
2
3
4
--- --- --- --84 84 84
8

ANSWER
================================
1
2
3
---------- ---------- ---------1980-09-30 09/30/1980 12/15/1976

Figure 228, MAX function with dates

SELECT MAX(id)
AS id
,MAX(CHAR(id))
AS chr
,MAX(DIGITS(id)) AS dig
FROM
staff;

ANSWER
===================
ID
CHR
DIG
------ ------ ----350 90
00350

Figure 229, MAX function with numbers, 1 of 2

SELECT MAX(id - 250)


AS id
,MAX(CHAR(id - 250))
AS chr
,MAX(DIGITS(id - 250)) AS dig
FROM
staff;

ANSWER
=====================
ID
CHR DIG
----- ---- ---------100 90
0000000240

Figure 230, MAX function with numbers, 2 of 2

Figure 231, MIN function syntax

SELECT

FROM

MIN(dept)
,MIN(ALL dept)
,MIN(DISTINCT dept)
,MIN(DISTINCT dept/10)
staff;

ANSWER
===============
1
2
3
4
--- --- --- --10 10 10
1

Figure 232, MIN function examples

Figure 233, REGRESSION functions syntax

SELECT

DEC(REGR_SLOPE(bonus,salary)
,7,5)
,DEC(REGR_INTERCEPT(bonus,salary),7,3)
,INT(REGR_COUNT(bonus,salary)
)
,INT(REGR_AVGX(bonus,salary)
)
,INT(REGR_AVGY(bonus,salary)
)
,INT(REGR_SXX(bonus,salary)
)
,INT(REGR_SXY(bonus,salary)
)
,INT(REGR_SYY(bonus,salary)
)
FROM
employee
WHERE
workdept = 'A00';
Figure 234, REGRESSION functions examples

AS
AS
AS
AS
AS
AS
AS
AS

r_slope
r_icpt
r_count
r_avgx
r_avgy
r_sxx
r_sxy
r_syy

ANSWERS
==========
0.01710
100.871
3
42833
833
296291666
5066666
86666

Figure 235, STDDEV function syntax

ANSWER
===============================
A1 S1
S2
S3
S4
-- ------------- ---- ---- ---41 +2.3522355E+1 23.5 23.5 24.1

SELECT AVG(dept) AS a1
,STDDEV(dept) AS s1
,DEC(STDDEV(dept),3,1) AS s2
,DEC(STDDEV(ALL dept),3,1) AS s3
,DEC(STDDEV(DISTINCT dept),3,1) AS s4
FROM
staff;
Figure 236, STDDEV function examples

Figure 237, SUM function syntax

SELECT

SUM(dept)
AS s1
,SUM(ALL dept)
AS s2
,SUM(DISTINCT dept) AS s3
,SUM(dept/10)
AS s4
,SUM(dept)/10
AS s5
FROM
staff;
Figure 238, SUM function examples

ANSWER
========================
S1
S2
S3
S4
S5
---- ---- ---- ---- ---1459 1459 326 134 145

Figure 239, VARIANCE function syntax

ANSWER
==============================
A1 V1
V2 V3 V4
-- --------------- --- --- --41 +5.533012244E+2 553 553 582

SELECT AVG(dept) AS a1
,VARIANCE(dept) AS s1
,DEC(VARIANCE(dept),4,1) AS s2
,DEC(VARIANCE(ALL dept),4,1) AS s3
,DEC(VARIANCE(DISTINCT dept),4,1) AS s4
FROM
staff;
Figure 240, VARIANCE function examples

SELECT
FROM
WHERE
AND
ORDER BY

s1.job, s1.id, s1.salary


staff s1
s1.name LIKE '%s%'
s1.id
< 90
s1.job
,s1.id;

Figure 241, Select rows from STAFF table

ANSWER
=================
JOB
ID SALARY
----- -- -------Clerk 80 13504.60
Mgr
10 18357.50
Mgr
50 20659.80

SELECT

s1.job, s1.id, s1.salary


,SUM(salary) OVER(ORDER BY job, id) AS sumsal
,ROW_NUMBER() OVER(ORDER BY job, id) AS r
FROM
staff s1
WHERE
s1.name LIKE '%s%'
JOB
ID SALARY
AND
s1.id
< 90
----- -- -------ORDER BY s1.job
Clerk 80 13504.60
,s1.id;
Mgr
10 18357.50
Mgr
50 20659.80
Figure 242, Using OLAP functions to get additional fields

ANSWER
======
SUMSAL
R
-------- 13504.60 1
31862.10 2
52521.90 3

SELECT

s1.job, s1.id, s1.salary


,xx.sumsal, xx.r
FROM
staff s1
,TABLE
(SELECT SUM(s2.salary) AS sumsal
,COUNT(*)
AS r
FROM
staff s2
WHERE s2.name LIKE '%s%'
AND s2.id
< 90
AND (s2.job
< s1.job
OR (s2.job
= s1.job
AND s2.id
<= s1.id))
)AS xx
WHERE
s1.name LIKE '%s%'
AND
s1.id
< 90
ORDER BY s1.job
,s1.id;
Figure 243, Using Nested Table Expression

ANSWER
============================
JOB
ID SALARY
SUMSAL
R
----- -- -------- -------- Clerk 80 13504.60 13504.60 1
Mgr
10 18357.50 31862.10 2
Mgr
50 20659.80 52521.90 3
to get additional fields

SELECT

s1.job, s1.id, s1.salary


ANSWER
,SUM(s2.salary) AS sumsal
============================
,COUNT(*)
AS r
JOB
ID SALARY
SUMSAL
R
FROM
staff s1
----- -- -------- -------- ,staff s2
Clerk 80 13504.60 13504.60 1
WHERE
s1.name LIKE '%s%'
Mgr
10 18357.50 31862.10 2
AND
s1.id
< 90
Mgr
50 20659.80 52521.90 3
AND
s2.name LIKE '%s%'
AND
s2.id
< 90
AND
(s2.job
< s1.job
OR
(s2.job
= s1.job
AND
s2.id
<= s1.id))
GROUP BY s1.job
,s1.id
,s1.salary
ORDER BY s1.job
,s1.id;
Figure 244, Using Self-Join and Group By to get additional fields

SELECT

s1.job, s1.id, s1.salary


,(SELECT SUM(s2.salary)
FROM
staff s2
WHERE s2.name LIKE '%s%'
AND s2.id
< 90
AND (s2.job
< s1.job
OR (s2.job
= s1.job
AND s2.id
<= s1.id))) AS sumsal
,(SELECT COUNT(*)
FROM
staff s3

WHERE s3.name LIKE '%s%'


AND s3.id
< 90
AND (s3.job
< s1.job
OR (s3.job
= s1.job
AND s3.id
<= s1.id))) AS r
FROM
staff s1
WHERE
s1.name LIKE '%s%'
ANSWER
AND
s1.id
< 90
============================
ORDER BY s1.job
JOB
ID SALARY
SUMSAL
R
,s1.id;
----- -- -------- -------- Clerk 80 13504.60 13504.60 1
Mgr
10 18357.50 31862.10 2
Mgr
50 20659.80 52521.90 3
Figure 245, Using Nested Table Expressions in Select to get additional fields

SELECT

dpt.deptname
,emp.empno
,emp.lastname
,emp.salary
,SUM(salary) OVER(ORDER BY dpt.deptname ASC
,emp.salary
DESC
,emp.empno
ASC)
,ROW_NUMBER() OVER(ORDER BY dpt.deptname ASC
,emp.salary
DESC
,emp.empno
ASC)
FROM
employee
emp
,department dpt
WHERE
emp.firstnme LIKE '%S%'
AND
emp.workdept
= dpt.deptno
AND
dpt.admrdept LIKE 'A%'
AND
NOT EXISTS
(SELECT *
FROM
emp_act eat
WHERE
emp.empno
= eat.empno
AND
eat.emptime > 10)
ORDER BY dpt.deptname ASC
,emp.salary
DESC
,emp.empno
ASC;
Figure 246, Complicated query using OLAP functions

Figure 247, Ranking Functions syntax

SELECT

id
,years
,salary
,RANK()
OVER(ORDER BY years) AS rank#
,DENSE_RANK() OVER(ORDER BY years) AS dense#
,ROW_NUMBER() OVER(ORDER BY years) AS row#

AS sumsal
AS row#

FROM
WHERE
AND
ORDER BY

staff
id
< 100
years IS NOT NULL
years;

ANSWER
===================================
ID YEARS SALARY
RANK# DENSE# ROW#
-- ----- -------- ----- ------ ---30
5 17506.75
1
1
1
40
6 18006.00
2
2
2
90
6 18001.75
2
2
3
10
7 18357.50
4
3
4
70
7 16502.83
4
3
5
20
8 18171.25
6
4
6
50
10 20659.80
7
5
7
Figure 248, Ranking functions example

SELECT

job
,years
,id
,name
,SMALLINT(RANK() OVER(ORDER BY job
ASC)) AS asc1
,SMALLINT(RANK() OVER(ORDER BY job
ASC
,years ASC)) AS asc2
,SMALLINT(RANK() OVER(ORDER BY job
ASC
,years ASC
,id
ASC)) AS asc3
,SMALLINT(RANK() OVER(ORDER BY job
DESC)) AS dsc1
,SMALLINT(RANK() OVER(ORDER BY job
DESC
,years DESC)) AS dsc2
,SMALLINT(RANK() OVER(ORDER BY job
DESC
,years DESC
,id
DESC)) AS Dsc3
,SMALLINT(RANK() OVER(ORDER BY job
ASC
,years DESC
,id
ASC)) AS mix1
,SMALLINT(RANK() OVER(ORDER BY job
DESC
,years ASC
,id
DESC)) AS mix2
FROM
staff
WHERE
id
< 150
AND
years IN (6,7)
AND
job
> 'L'
ORDER BY job
,years
,id;
ANSWER
================================================================
JOB
YEARS ID NAME
ASC1 ASC2 ASC3 DSC1 DSC2 DSC3 MIX1 MIX2
----- ----- --- ------- ---- ---- ---- ---- ---- ---- ---- ---Mgr
6 140 Fraye
1
1
1
4
6
6
3
4
Mgr
7 10 Sanders
1
2
2
4
4
5
1
6
Mgr
7 100 Plotz
1
2
3
4
4
4
2
5
Sales
6 40 O'Brien
4
4
4
1
2
3
5
2
Sales
6 90 Koonitz
4
4
5
1
2
2
6
1
Sales
7 70 Rothman
4
6
6
1
1
1
4
3
Figure 249, ORDER BY usage

SELECT

id
,years
,salary
,DENSE_RANK()
,DENSE_RANK()
,DENSE_RANK()
,DENSE_RANK()
,DENSE_RANK()
,DENSE_RANK()
FROM
staff
WHERE
id
< 100
ORDER BY years
,salary;

AS yr
OVER(ORDER
OVER(ORDER
OVER(ORDER
OVER(ORDER
OVER(ORDER
OVER(ORDER

BY
BY
BY
BY
BY
BY

years
years
years
years
years
years

ASC)
ASC NULLS
ASC NULLS
DESC)
DESC NULLS
DESC NULLS

AS a
FIRST) AS af
LAST ) AS al
AS d
FIRST) AS df
LAST ) AS dl

ANSWER
==================================
ID YR SALARY
A AF AL D DF DL
-- -- -------- -- -- -- -- -- -30 5 17506.75
1 2 1
6 6 5
90 6 18001.75
2 3 2
5 5 4
40 6 18006.00
2 3 2
5 5 4
70 7 16502.83
3 4 3
4 4 3
10 7 18357.50
3 4 3
4 4 3
20 8 18171.25
4 5 4
3 3 2
50 10 20659.80
5 6 5
2 2 1
80 - 13504.60
6 1 6
1 1 6
60 - 16808.30
6 1 6
1 1 6
Figure 250, Overriding the default null ordering sequence

SELECT

COUNT(DISTINCT years) AS y#1


,MAX(y#)
AS y#2
FROM
(SELECT
years
,DENSE_RANK() OVER(ORDER BY years) AS y#
FROM
staff
WHERE
id
< 100
)AS xxx
ORDER BY 1;

Figure 251, Counting distinct values - comparison

SELECT

id
,years AS yr
,salary
,RANK() OVER(PARTITION BY years
ORDER
BY salary) AS r1
FROM
staff
WHERE
id
< 80
AND
years IS NOT NULL
ORDER BY years
,salary;
Figure 252, Values ranked by subset of rows

ANSWER
=======
Y#1 Y#2
--- --5
6

ANSWER
=================
ID YR SALARY
R1
-- -- -------- -30 5 17506.75 1
40 6 18006.00 1
70 7 16502.83 1
10 7 18357.50 2
20 8 18171.25 1
50 0 20659.80 1

SELECT

id
,years
,salary
,SMALLINT(RANK() OVER(ORDER BY years ASC)) AS rank_a
,SMALLINT(RANK() OVER(ORDER BY years DESC)) AS rank_d
,SMALLINT(RANK() OVER(ORDER BY id, years)) AS rank_iy
FROM
STAFF
WHERE
id
< 100
AND
years IS NOT NULL
ORDER BY years;
Figure 253, Multiple rankings in same query

SELECT

id
,years
,name
,salary
,SMALLINT(RANK() OVER(ORDER
,SMALLINT(RANK() OVER(ORDER
,SMALLINT(RANK() OVER(ORDER
,SMALLINT(RANK() OVER(ORDER
,SMALLINT(RANK() OVER(ORDER
FROM
staff
WHERE
id
< 40
AND
years IS NOT NULL
ORDER BY 1;
Figure 254, Dumb rankings, SQL

ID YEARS NAME
SALARY
DUMB1
-- ----- -------- -------- ----10
7 Sanders
18357.50
1
20
8 Pernal
18171.25
3
30
5 Marenghi 17506.75
2
Figure 255, Dumb ranking, Answer

BY
BY
BY
BY
BY

SELECT
FROM

SUBSTR(name,3,2)))
salary / 1000))
years * ID))
rand()))
1))

DUMB2
----3
2
1

DUMB3
----1
3
2

xxx.*
,RANK()OVER(ORDER BY id) AS r2
(SELECT
id
,name
,RANK() OVER(ORDER BY id) AS r1
FROM
staff
WHERE
id
< 100
AND
years IS NOT NULL

DUMB4
----1
3
2

AS
AS
AS
AS
AS

dumb1
dumb2
dumb3
dumb4
dumb5

DUMB5
----1
1
1

ANSWER
================
ID NAME
R1 R2
-- ------- -- -40 O'Brien 4 1
50 Hanes
5 2
70 Rothman 6 3
90 Koonitz 7 4

)AS xxx
WHERE
id > 30
ORDER BY id;
Figure 256, Subsequent processing of ranked data

SELECT

id
ANSWER
,RANK() OVER(PARTITION BY dept
=================
ORDER BY salary DESC) AS r1
ID R1 SALARY
DP
,salary
-- -- -------- -,dept AS dp
50 1 20659.80 15
FROM
staff
10 1 18357.50 20
WHERE
id
< 80
40 1 18006.00 38
AND
years IS NOT NULL
20 2 18171.25 20
ORDER BY r1
ASC
30 2 17506.75 38
,salary DESC;
70 2 16502.83 15
Figure 257, Ordering rows by rank, using RANK function

SELECT

id
,(SELECT COUNT(*)
FROM
staff s2
WHERE s2.id
< 80
AND S2.YEARS IS NOT NULL
AND s2.dept
= s1.dept
AND s2.salary
>= s1.salary) AS R1
,SALARY
,dept AS dp
FROM
staff s1
WHERE
id
< 80
AND
years IS NOT NULL
ORDER BY r1
ASC
,salary DESC;
Figure 258, Ordering rows by rank, using sub-query

SELECT

ANSWER
=================
ID R1 SALARY
DP
-- -- -------- -50 1 20659.80 15
10 1 18357.50 20
40 1 18006.00 38
20 2 18171.25 20
30 2 17506.75 38
70 2 16502.83 15

id
ANSWER
,salary
==============
,dept AS dp
ID SALARY
DP
FROM
(SELECT
s1.*
-- -------- -,RANK() OVER(PARTITION BY dept
50 20659.80 15
ORDER BY salary DESC) AS r1
10 18357.50 20
FROM
staff s1
40 18006.00 38
WHERE
id
< 80
AND
years IS NOT NULL
)AS xxx
WHERE
r1 = 1
ORDER BY dp;
Figure 259, Get highest salary in each department, use RANK function

SELECT

id
ANSWER
,salary
==============
,dept AS dp
ID SALARY
DP
FROM
staff s1
-- -------- -WHERE
id
< 80
50 20659.80 15
AND
years IS NOT NULL
10 18357.50 20
AND
NOT EXISTS
40 18006.00 38
(SELECT *
FROM
staff s2
WHERE s2.id
< 80
AND s2.years IS NOT NULL
AND s2.dept
= s1.dept
AND s2.salary
> s1.salary)
ORDER BY DP;
Figure 260, Get highest salary in each department, use correlated sub-query

SELECT

id
ANSWER
,salary
==============
,dept AS dp
ID SALARY
DP
FROM
staff
-- -------- -WHERE
id
< 80
50 20659.80 15
AND
years IS NOT NULL
10 18357.50 20
AND
(dept, salary) IN
40 18006.00 38
(SELECT
dept, MAX(salary)
FROM
staff
WHERE
id
< 80
AND
years IS NOT NULL
GROUP BY dept)
ORDER BY dp;
Figure 261, Get highest salary in each department, use uncorrelated sub-query

Figure 262, Numbering Function syntax

SELECT

id
,name
,ROW_NUMBER() OVER()
AS r1
,ROW_NUMBER() OVER(ORDER BY id) AS r2
FROM
staff
WHERE
id
< 50
AND
years IS NOT NULL
ORDER BY id;
Figure 263, ORDER BY example, 1 of 3

ANSWER
=================
ID NAME
R1 R2
-- -------- -- -10 Sanders
1 1
20 Pernal
2 2
30 Marenghi 3 3
40 O'Brien
4 4

SELECT

id
,name
,ROW_NUMBER() OVER()
AS r1
,ROW_NUMBER() OVER(ORDER BY name) AS r2
FROM
staff
WHERE
id
< 50
AND
years IS NOT NULL
ORDER BY id;
Figure 264, ORDER BY example, 2 of 3

ANSWER
=================
ID NAME
R1 R2
-- -------- -- -10 Sanders
4 4
20 Pernal
3 3
30 Marenghi 1 1
40 O'Brien
2 2

SELECT

ANSWER
====================
ID NAME
R1 R2 R3
-- -------- -- -- -10 Sanders
1 1 4
20 Pernal
2 2 3
30 Marenghi 3 3 1
40 O'Brien
4 4 2

id
,name
,ROW_NUMBER() OVER()
AS r1
,ROW_NUMBER() OVER(ORDER BY ID)
AS r2
,ROW_NUMBER() OVER(ORDER BY NAME) AS r3
FROM
staff
WHERE
id
< 50
AND
years IS NOT NULL
ORDER BY id;
Figure 265, ORDER BY example, 3 of 3

SELECT

job
,years
,id
,name
,ROW_NUMBER() OVER(PARTITION BY job
ORDER
BY years) AS row#
,RANK()
OVER(PARTITION BY job
ORDER
BY years) AS rn1#
,DENSE_RANK() OVER(PARTITION BY job
ORDER
BY years) AS rn2#
FROM
staff
WHERE
id
< 150
AND
years IN (6,7)
ANSWER
AND
job
> 'L'
======================================
ORDER BY job
JOB
YEARS ID NAME
ROW# RN1# RN2#
,years;
----- ----- --- ------- ---- ---- ---Mgr
6 140 Fraye
1
1
1
Mgr
7 10 Sanders
2
2
2
Mgr
7 100 Plotz
3
2
2
Sales
6 40 O'Brien
1
1
1
Sales
6 90 Koonitz
2
1
1
Sales
7 70 Rothman
3
3
2
Figure 266, Use of PARTITION phrase

SELECT
FROM

*
(SELECT

id
,name
,ROW_NUMBER() OVER(ORDER BY id) AS r
staff
id
< 100
years IS NOT NULL

ANSWER
=============
ID NAME
R
-- -------- 10 Sanders 1
20 Pernal
2
30 Marenghi 3

FROM
WHERE
AND
)AS xxx
WHERE
r <= 3
ORDER BY id;
Figure 267, Select first 3 rows, using ROW_NUMBER function

SELECT

id
ANSWER
,name
=============
,ROW_NUMBER() OVER(ORDER BY id) AS r
ID NAME
R
FROM
staff
-- -------- WHERE
id
< 100
10 Sanders 1
AND
years IS NOT NULL
20 Pernal
2
ORDER BY id
30 Marenghi 3
FETCH FIRST 3 ROWS ONLY;
Figure 268, Select first 3 rows, using FETCH FIRST notation

SELECT
FROM

*
(SELECT

id
,name
,ROW_NUMBER() OVER(ORDER BY id) AS r
staff
id
< 200
years IS NOT NULL

ANSWER
=============
ID NAME
R
-- -------- 30 Marenghi 3
40 O'Brien 4
50 Hanes
5
70 Rothman 6

id
,name
,ROW_NUMBER() OVER(ORDER BY id) AS r
staff
id
< 200
years IS NOT NULL

ANSWER
==============
ID NAME
R
--- ------- -10 Sanders 1
70 Rothman 6
140 Fraye
11
190 Sneider 16

FROM
WHERE
AND
)AS xxx
WHERE
r BETWEEN 3 AND 6
ORDER BY id;
Figure 269, Select 3rd through 6th rows

SELECT
FROM

*
(SELECT

FROM
WHERE
AND
)AS xxx
WHERE
(r - 1) = ((r - 1) / 5) * 5
ORDER BY id;
Figure 270, Select every 5th matching row

SELECT
FROM

*
(SELECT

id
,name
,ROW_NUMBER() OVER(ORDER BY id DESC) AS r
FROM
staff
WHERE
id
< 200
AND
years IS NOT NULL
ANSWER
)AS xxx
==============
WHERE
r <= 2
ID NAME
R
ORDER BY id;
--- -------- 180 Abrahams 2
190 Sneider 1
Figure 271, Select last two rows

WITH
temp1(years, id, name, rnk, row) AS
(SELECT years
,id
,name
,RANK()
OVER(ORDER BY years)
,ROW_NUMBER() OVER(ORDER BY years, id)
FROM
staff
WHERE
id
< 200
AND
years IS NOT NULL
),
temp2(rnk) AS
(SELECT rnk
FROM
temp1
WHERE
row = 3
ANSWER
)
==========================
SELECT
temp1.*
YEARS ID NAME
RNK ROW
FROM
temp1
----- --- -------- --- --,temp2
3 180 Abrahams
1
1
WHERE
temp1.rnk <= temp2.rnk
4 170 Kermisch
2
2
ORDER BY years
5 30 Marenghi
3
3
,id;
5 110 Ngan
3
4
Figure 272, Select first "n" rows, or more if needed

CREATE TABLE invoice


(inv#
INTEGER
NOT NULL
,customer#
INTEGER
NOT NULL
,sale_date
DATE
NOT NULL
,sale_value DECIMAL(9,2)
NOT NULL
,CONSTRAINT ctx1 PRIMARY KEY (inv#)
,CONSTRAINT ctx2 CHECK(inv# >= 0));
Figure 273, Performance test table - definition

INSERT INTO invoice


WITH temp (n,m) AS
(VALUES
(INTEGER(0),RAND(1))
UNION ALL
SELECT n+1, RAND()
FROM
temp
WHERE
n+1 < 500000
)
SELECT n
AS
,INT(m * 1000)
AS
,DATE('2000-11-01') + (m*40) DAYS AS
,DECIMAL((m * m * 100),8,2)
AS
FROM
temp;
Figure 274, Performance test table - insert

inv#
customer#
sale_date
sale_value
500,000 rows

SELECT
s.*
FROM
invoice s
ORDER BY inv#
FETCH FIRST 5 ROWS ONLY;
Figure 275, Fetch first 5 rows - 0.313 elapsed seconds

SELECT
s.*
FROM
invoice s
ORDER BY inv#
FETCH FIRST 5 ROWS ONLY
OPTIMIZE FOR 5 ROWS;
Figure 276, Fetch first 5 rows - 0.281 elapsed seconds

SELECT

s.*
,ROW_NUMBER() OVER() AS row#
FROM
invoice s
ORDER BY inv#
FETCH FIRST 5 ROWS ONLY;
Figure 277, Fetch first 5 rows+ number rows - 0.672 elapsed seconds

SELECT
FROM

*
(SELECT
FROM
)xxx

s.*
,ROW_NUMBER() OVER() AS row#
invoice s

WHERE
row# <= 5
ORDER BY inv#;
Figure 278, Process and number 5 rows only - 0.000 elapsed seconds

SELECT
FROM

*
(SELECT

s.*
,ROW_NUMBER() OVER(ORDER BY inv#) AS row#
invoice s

FROM
)xxx
WHERE
row# <= 5
ORDER BY inv#;
Figure 279, Process and number 5 rows only - 0.281 elapsed seconds

WITH temp (inv#, c#, sd, sv, n) AS


(SELECT inv.*
,1
FROM
invoice inv
WHERE
inv# =
(SELECT MIN(inv#)
FROM
invoice)
UNION
ALL
SELECT new.*, n + 1
FROM
temp
old
,invoice new
WHERE
old.inv# < new.inv#
AND
old.n
< 5
AND
new.inv# =
(SELECT MIN(xxx.inv#)
FROM
invoice xxx
WHERE xxx.inv# > old.inv#)
)
SELECT
*
FROM
temp;
Figure 280, Fetch first 5 rows - 0.000 elapsed seconds

Figure 281, Aggregation Function syntax

SELECT

id
,name
,salary
,SUM(salary) OVER() AS sum_sal
,AVG(salary) OVER() AS avg_sal
,MIN(salary) OVER() AS min_sal

,MAX(salary) OVER() AS max_sal


,COUNT(*)
OVER() AS #rows
FROM
staff
WHERE
id < 60
ORDER BY id;
Figure 282, Aggregation function, basic usage, SQL

ID NAME
SALARY
-- -------- -------10 Sanders
18357.50
20 Pernal
18171.25
30 Marenghi 17506.75
40 O'Brien
18006.00
50 Hanes
20659.80
Figure 283, Aggregation

SUM_SAL
-------92701.30
92701.30
92701.30
92701.30
92701.30
function,

AVG_SAL
MIN_SAL
-------- -------18540.26 17506.75
18540.26 17506.75
18540.26 17506.75
18540.26 17506.75
18540.26 17506.75
basic usage, Answer

MAX_SAL
-------20659.80
20659.80
20659.80
20659.80
20659.80

#ROWS
----5
5
5
5
5

WITH
temp1 (id, name, salary) AS
(SELECT
id, name, salary
FROM
staff
WHERE
id < 60
),
temp2 (sum_sal, avg_sal, min_sal, max_sal, #rows) AS
(SELECT
SUM(salary)
,AVG(salary)
,MIN(salary)
,MAX(salary)
,COUNT(*)
FROM
temp1
)
SELECT
*
FROM
temp1
,temp2
ORDER BY id;
Figure 284, Select detailed data, plus summary data

SELECT

id
,name
,salary
,SUM(salary)
,SUM(salary)
,SUM(salary)
,SUM(salary)

FROM
staff
WHERE
id < 60
ORDER BY id;

OVER()
OVER(ORDER
OVER(ORDER
OVER(ORDER
RANGE

AS sum1
BY id * 0)
AS sum2
BY 'ABC')
AS sum3
BY 'ABC'
BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING) AS sum4

Figure 285, Logically equivalent aggregation functions, SQL

ID NAME
SALARY
SUM1
SUM2
SUM3
SUM4
-- -------- -------- -------- -------- -------- -------10 Sanders
18357.50 92701.30 92701.30 92701.30 92701.30
20 Pernal
18171.25 92701.30 92701.30 92701.30 92701.30
30 Marenghi 17506.75 92701.30 92701.30 92701.30 92701.30
40 O'Brien
18006.00 92701.30 92701.30 92701.30 92701.30
50 Hanes
20659.80 92701.30 92701.30 92701.30 92701.30
Figure 286, Logically equivalent aggregation functions, Answer

SELECT

dept
,name
,salary
,SUM(salary) OVER(ORDER BY dept)
,SUM(salary) OVER(ORDER BY dept DESC)
,SUM(salary) OVER(ORDER BY dept, NAME)
,SUM(salary) OVER(ORDER BY dept DESC, name DESC)
,COUNT(*)
OVER(ORDER BY dept)
,COUNT(*)
OVER(ORDER BY dept, NAME)
FROM
staff
WHERE
id < 60
ORDER BY dept
,name;
Figure 287, Aggregation function, order by usage, SQL

DEPT NAME
SALARY
SUM1
SUM2
SUM3
---- -------- -------- -------- -------- -------15 Hanes
20659.80 20659.80 92701.30 20659.80
20 Pernal
18171.25 57188.55 72041.50 38831.05
20 Sanders 18357.50 57188.55 72041.50 57188.55
38 Marenghi 17506.75 92701.30 35512.75 74695.30
38 O'Brien 18006.00 92701.30 35512.75 92701.30
Figure 288, Aggregation function, order by usage,

SELECT

AS
AS
AS
AS
AS
AS

sum1
sum2
sum3
sum4
row1
row2

SUM4
ROW1 ROW2
-------- ---- ---92701.30
1
1
72041.50
3
2
53870.25
3
3
35512.75
5
4
18006.00
5
5
Answer

dept
,name
,years
,SMALLINT(SUM(years) OVER(ORDER BY dept))
AS d
,SMALLINT(SUM(years) OVER(ORDER BY dept, name))
AS dn
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS
UNBOUNDED PRECEDING))AS dnu
,SMALLINT(SUM(years) OVER(ORDER BY dept, name

ROWS
3 PRECEDING))
AS
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS
1 PRECEDING))
AS
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS
0 PRECEDING))
AS
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS
CURRENT ROW))
AS
,SMALLINT(SUM(years) OVER(ORDER BY dept DESC, name DESC
ROWS
1 PRECEDING))
AS
FROM
staff
WHERE
id
< 100
AND
years IS NOT NULL
ORDER BY dept
,name;
Figure 289, Starting ROWS usage. Implied end is current row, SQL

DEPT
---15
15
20
20
38
38
42
Figure

SELECT

NAME
YEARS
-----------Hanes
10
Rothman
7
Pernal
8
Sanders
7
Marenghi
5
O'Brien
6
Koonitz
6
290, Starting ROWS

dn3
dn1
dn0
dnc
dnx

D
DN
DNU
DN3
DN1
DN0
DNC
DNX
--------------17
10
10
10
10
10
10
17
17
17
17
17
17
7
7
15
32
25
25
25
15
8
8
15
32
32
32
32
15
7
7
12
43
37
37
27
12
5
5
11
43
43
43
26
11
6
6
12
49
49
49
24
12
6
6
6
usage. Implied end is current row, Answer

dept
,name
,years
,SMALLINT(SUM(years) OVER(ORDER BY dept, name))
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS
UNBOUNDED PRECEDING))
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW))
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS BETWEEN CURRENT ROW
AND CURRENT ROW))
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS BETWEEN 1 PRECEDING
AND 1 FOLLOWING))
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS BETWEEN 2 PRECEDING
AND 2 FOLLOWING))
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS BETWEEN 3 PRECEDING
AND 3 FOLLOWING))
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS BETWEEN CURRENT ROW
AND UNBOUNDED FOLLOWING))
,SMALLINT(SUM(years) OVER(ORDER BY dept, name
ROWS BETWEEN UNBOUNDED PRECEDING

AS uc1
AS uc2
AS uc3
AS cu1
AS pf1
AS pf2
AS pf3
AS cu1

AND UNBOUNDED FOLLOWING)) AS uu1


staff
id
< 100
years IS NOT NULL
dept
,name;
Figure 291, ROWS usage, with BETWEEN phrase, SQL
FROM
WHERE
AND
ORDER BY

DEPT NAME
YEARS UC1 UC2 UC3 CU1 PF1 PF2
---- -------- ----- --- --- --- --- --- --15 Hanes
10
10
10
10
10
17
25
15 Rothman
7
17
17
17
7
25
32
20 Pernal
8
25
25
25
8
22
37
20 Sanders
7
32
32
32
7
20
33
38 Marenghi
5
37
37
37
5
18
32
38 O'Brien
6
43
43
43
6
17
24
42 Koonitz
6
49
49
49
6
12
17
Figure 292, ROWS usage, with BETWEEN phrase, Answer

PF3
--32
37
43
49
39
32
24

CU1
--49
39
32
24
17
12
6

UU1
--49
49
49
49
49
49
49

SELECT

id
,name
,SMALLINT(SUM(id) OVER(ORDER BY id ASC
ROWS BETWEEN 1 PRECEDING
AND CURRENT ROW)) AS apc
,SMALLINT(SUM(id) OVER(ORDER BY id ASC
ROWS BETWEEN CURRENT ROW
AND 1 FOLLOWING)) AS acf
,SMALLINT(SUM(id) OVER(ORDER BY id DESC
ROWS BETWEEN 1 PRECEDING
AND CURRENT ROW)) AS dpc
,SMALLINT(SUM(id) OVER(ORDER BY id DESC
ROWS BETWEEN CURRENT ROW
AND 1 FOLLOWING)) AS dcf
FROM
staff
WHERE
id
< 50
AND
years IS NOT NULL
ANSWER
ORDER BY id;
===========================
ID NAME
APC ACF DPC DCF
-- -------- --- --- --- --10 Sanders
10 30 30 10
20 Pernal
30 50 50 30
30 Marenghi 50 70 70 50
40 O'Brien
70 40 40 70
Figure 293,BETWEEN and ORDER BY usage

ASC id (10,20,30,40)
READ ROWS, LEFT to RIGHT
==========================

1ST-ROW
========

2ND-ROW
========

3RD-ROW
========

4TH-ROW
========

1 PRECEDING to CURRENT ROW


CURRENT ROW to 1 FOLLOWING

10=10
10+20=30

10+20=30
20+30=50

20+30=40
30+40=70

30+40=70
40
=40

DESC id (40,30,20,10)
READ ROWS, RIGHT to LEFT
==========================
1 PRECEDING to CURRENT ROW
CURRENT ROW to 1 FOLLOWING

1ST-ROW
========
20+10=30
10
=10

2ND-ROW
========
30+20=50
20+10=30

3RD-ROW
========
40+30=70
30+20=50

4TH-ROW
========
40
=40
40+30=70

NOTE: Preceding row is always on LEFT of current row.


Following row is always on RIGHT of current row.
Figure 294, Explanation of query

SELECT

dept
,name
,years
,SMALLINT(SUM(years) OVER(ORDER BY
ROWS BETWEEN
AND
,SMALLINT(SUM(years) OVER(ORDER BY
ROWS BETWEEN
AND
,SMALLINT(SUM(years) OVER(ORDER BY
RANGE BETWEEN
AND
,SMALLINT(SUM(years) OVER(ORDER BY
RANGE BETWEEN
AND
,SMALLINT(SUM(years) OVER(ORDER BY
RANGE BETWEEN
AND
,SMALLINT(SUM(years) OVER(ORDER BY
RANGE BETWEEN
AND
,SMALLINT(SUM(years) OVER(ORDER BY
RANGE BETWEEN
AND
FROM
staff
WHERE
id
< 100
AND
years IS NOT NULL
ORDER BY dept
,name;
Figure 295, RANGE usage, SQL

DEPT
-----15
15
20
20
38

NAME
------Hanes
Rothman
Pernal
Sanders
Marengh

YEARS
----10
7
8
7
5

ROW1
---10
17
15
15
12

ROW2
---10
17
25
22
20

RG01
---17
17
15
15
11

dept
1 PRECEDING
CURRENT ROW))
dept
2 PRECEDING
CURRENT ROW))
dept
1 PRECEDING
CURRENT ROW))
dept
10 PRECEDING
CURRENT ROW))
dept
20 PRECEDING
CURRENT ROW))
dept
10 PRECEDING
20 FOLLOWING))
dept
CURRENT ROW
20 FOLLOWING))

RG10
---17
17
32
32
11

RG20
---17
17
32
32
26

AS row1
AS row2
AS rg01
AS rg10
AS rg20
AS rg11
AS rg99

RG11
---32
32
43
43
17

RG99
---32
32
26
26
17

38 O'Brien
6
11
42 Koonitz
6
12
Figure 296, RANGE usage, Answer

18
17

11
6

11
17

26
17

17
17

dept
,name
,years
,SMALLINT(SUM(years) OVER(ORDER
BY dept))
,SMALLINT(SUM(years) OVER(ORDER
BY dept
ROWS 3 PRECEDING))
,SMALLINT(SUM(years) OVER(ORDER
BY dept
ROWS BETWEEN 1 PRECEDING
AND 1 FOLLOWING))
,SMALLINT(SUM(years) OVER(PARTITION BY dept))
,SMALLINT(SUM(years) OVER(PARTITION BY dept
ORDER
BY dept))
,SMALLINT(SUM(years) OVER(PARTITION BY dept
ORDER
BY dept
ROWS 1 PRECEDING))
,SMALLINT(SUM(years) OVER(PARTITION BY dept
ORDER
BY dept
ROWS 3 PRECEDING))
,SMALLINT(SUM(years) OVER(PARTITION BY dept
ORDER
BY dept
ROWS BETWEEN 1 PRECEDING
AND 1 FOLLOWING))
FROM
staff
WHERE
id BETWEEN 40 AND 120
AND
years IS NOT NULL
ORDER BY dept
,name;
Figure 297, PARTITION usage, SQL

17
6

SELECT

DEPT
----15
15
15
38
42
42
Figure

SELECT

FROM

NAME
YEARS
X
XO3 XO11
------- ----- ---- ---- ---Hanes
10
22
10
15
Ngan
5
22
15
22
Rothman
7
22
22
18
O'Brien
6
28
28
19
Koonitz
6
41
24
19
Plotz
7
41
26
13
298, PARTITION usage, Answer

dept
,SUM(years) AS sum
,AVG(years) AS avg
,COUNT(*)
AS row
staff

P
---22
22
22
6
13
13

PO
---22
22
22
6
13
13

PO1
---10
15
12
6
6
13

AS x
AS xo3
AS xo11
AS p
AS po
AS po1
AS po3

AS po11

PO3
---10
15
22
6
6
13

PO11
---15
22
12
6
13
13

ANSWER
================
DEPT SUM AVG ROW
---- --- --- --15 22
7
3

WHERE
id BETWEEN 40 AND 120
AND
years IS NOT NULL
GROUP BY dept;
Figure 299, Sample query using GROUP BY

SELECT

dept
,SUM(years) OVER(PARTITION BY dept) AS sum
,AVG(years) OVER(PARTITION BY dept) AS avg
,COUNT(*)
OVER(PARTITION BY dept) AS row
FROM
staff
WHERE
id BETWEEN 40 AND 120
AND
years IS NOT NULL
ORDER BY dept;

38
42

6
13

6
6

1
2

ANSWER
=================
DEPT SUM AVG ROW
----- --- --- --15 22
7
3
15 22
7
3
15 22
7
3
38
6
6
1
42 13
6
2
42 13
6
2

Figure 300, Sample query using PARTITION

SELECT

DISTINCT dept
ANSWER
,SUM(years) OVER(PARTITION BY dept) AS sum
=================
,AVG(years) OVER(PARTITION BY dept) AS avg
DEPT SUM AVG ROW
,COUNT(*)
OVER(PARTITION BY dept) AS row
----- --- --- --FROM
staff
15 22
7
3
WHERE
id BETWEEN 40 AND 120
38
6
6
1
AND
years IS NOT NULL
42 13
6
2
ORDER BY dept;
Figure 301, Sample query using PARTITION and DISTINCT

CREATE VIEW scalar (d1,f1,s1,c1,v1,ts1,dt1,tm1,tc1) AS


WITH temp1 (n1, c1, t1) AS
(VALUES (-2.4,'ABCDEF','1996-04-22-23.58.58.123456')
,(+0.0,'ABCD ','1996-08-15-15.15.15.151515')
,(+1.8,'AB
','0001-01-01-00.00.00.000000'))
SELECT DECIMAL(n1,3,1)
,DOUBLE(n1)
,SMALLINT(n1)
,CHAR(c1,6)
,VARCHAR(RTRIM(c1),6)
,TIMESTAMP(t1)
,DATE(t1)
,TIME(t1)
,CHAR(t1)
FROM
temp1;
Figure 302, Sample View DDL - Scalar functions

D1
------2.4
0.0
1.8

F1
---------2.4e+000
0.0e+000
1.8e+000

S1
--2
0
1

C1
-----ABCDEF
ABCD
AB

V1
-----ABCDEF
ABCD
AB

TS1
-------------------------1996-04-22-23.58.58.123456
1996-08-15-15.15.15.151515
0001-01-01-00.00.00.000000

DT1
TM1
TC1
-----------------------------------------1996-04-22
23:58:58
1996-04-22-23.58.58.123456
1996-08-15
15:15:15
1996-08-15-15.15.15.151515
0001-01-01
00:00:00
0001-01-01-00.00.00.000000
Figure 303, SCALAR view, contents (3 rows)

SELECT d1
,ABS(D1)
,f1
,ABS(f1)
FROM
scalar;

AS
AS
AS
AS

d1
d2
f1
f2

Figure 304, ABS function examples

SELECT c1
,ASCII(c1)
AS ac1
,ASCII(SUBSTR(c1,2)) AS ac2
FROM
scalar
WHERE c1 = 'ABCDEF';
Figure 305, ASCII function examples

WITH temp (big) AS


(VALUES BIGINT(1)
UNION ALL
SELECT big * 256
FROM
temp
WHERE big < 1E16
)
SELECT big
FROM
temp;

Figure 306, BIGINT function example

ANSWER (float output shortened)


================================
D1
D2
F1
F2
---- --- ---------- ---------2.4 2.4
-2.400e+0 2.400e+00
0.0 0.0
0.000e+0 0.000e+00
1.8 1.8
1.800e+0 1.800e+00

ANSWER
================
C1
AC1 AC2
------ --- --ABCDEF
65
66

ANSWER
====================
BIG
-------------------1
256
65536
16777216
4294967296
1099511627776
281474976710656
72057594037927936

WITH temp (f1) AS


(VALUES FLOAT(1.23456789)
UNION ALL
SELECT f1 * 100
FROM
temp
WHERE f1 < 1E18
)
SELECT f1
AS float1
,DEC(f1,19) AS decimal1
,BIGINT(f1) AS bigint1
FROM
temp;
Figure 307, Convert FLOAT to DECIMAL and BIGINT, SQL

FLOAT1
DECIMAL1
BIGINT1
---------------------- ------------------- -------------------+1.23456789000000E+000
1.
1
+1.23456789000000E+002
123.
123
+1.23456789000000E+004
12345.
12345
+1.23456789000000E+006
1234567.
1234567
+1.23456789000000E+008
123456789.
123456788
+1.23456789000000E+010
12345678900.
12345678899
+1.23456789000000E+012
1234567890000.
1234567889999
+1.23456789000000E+014
123456789000000.
123456788999999
+1.23456789000000E+016
12345678900000000.
12345678899999996
+1.23456789000000E+018 1234567890000000000. 1234567889999999488
Figure 308, Convert FLOAT to DECIMAL and BIGINT, answer

Figure 309, BLOB function syntax

Figure 310, CEILING function syntax

SELECT d1
,CEIL(d1) AS d2
,f1
,CEIL(f1) AS f2
FROM
scalar;
Figure 311, CEIL function examples

ANSWER (float output shortened)


==================================
D1
D2
F1
F2
---- ---- ---------- ----------2.4
-2.
-2.400E+0
-2.000E+0
0.0
0.
+0.000E+0
+0.000E+0
1.8
2.
+1.800E+0
+2.000E+0

Figure 312, CHAR function syntax

SELECT

name
ANSWER
,CHAR(name,3)
=====================================
,comm
NAME
2
COMM
4
5
,CHAR(comm)
------- --- ------- -------- -------,CHAR(comm,'@')
James
Jam 128.20 00128.20 00128@20
FROM
staff
Koonitz Koo 1386.70 01386.70 01386@70
WHERE
id BETWEEN 80
Plotz
Plo
- AND 100
ORDER BY id;
Figure 313, CHAR function examples - characters and numbers

ANSWER
==========================================
INT
CHAR_INT CHAR_FLT
CHAR_DEC
-------- -------- ----------- -----------3 3
3.0E0
00000000003.
9 9
9.0E0
00000000009.
81 81
8.1E1
00000000081.
6561 6561
6.561E3
00000006561.
43046721 43046721 4.3046721E7 00043046721.

WITH temp1 (n) AS


(VALUES (3)
UNION ALL
SELECT n * n
FROM
temp1
WHERE
n < 9000
)
SELECT n
AS int
,CHAR(INT(n))
AS char_int
,CHAR(FLOAT(n)) AS char_flt
,CHAR(DEC(n))
AS char_dec
FROM
temp1;
Figure 314, CHAR function examples - positive numbers

WITH temp1 (n1, n2) AS


ANSWER
(VALUES (SMALLINT(+3)
===================================
,SMALLINT(-7))
N1
I1
I2
D1
D2
UNION ALL
------ ----- ------ ------- ------SELECT n1 * n2
3 3
+3
00003. +00003.
,n2
-21 -21
-21
-00021. -00021.
FROM
temp1
147 147
+147
00147. +00147.
WHERE
n1 < 300
-1029 -1029 -1029 -01029. -01029.
)
7203 7203 +7203 07203. +07203.
SELECT n1
,CHAR(n1) AS i1
,CASE
WHEN n1 < 0 THEN CHAR(n1)

ELSE '+' CONCAT CHAR(n1)


END AS i2
,CHAR(DEC(n1)) AS d1
,CASE
WHEN n1 < 0 THEN CHAR(DEC(n1))
ELSE '+' CONCAT CHAR(DEC(n1))
END AS d2
FROM
temp1;
Figure 315, Align CHAR function output - numbers

SELECT

CHAR(CURRENT DATE,ISO) AS iso


,CHAR(CURRENT DATE,EUR) AS eur
,CHAR(CURRENT DATE,JIS) AS jis
,CHAR(CURRENT DATE,USA) AS usa
FROM
sysibm.sysdummy1;
Figure 316, CHAR function examples - date value

SELECT

CHAR(CURRENT TIME,ISO) AS iso


,CHAR(CURRENT TIME,EUR) AS eur
,CHAR(CURRENT TIME,JIS) AS jis
,CHAR(CURRENT TIME,USA) AS usa
FROM
sysibm.sysdummy1;
Figure 317, CHAR function examples - time value

SELECT
FROM

==>
==>
==>
==>

ANSWER
==========
2005-11-30
30.11.2005
2005-11-30
11/30/2005

==>
==>
==>
==>

ANSWER
========
19.42.21
19.42.21
19:42:21
07:42 PM

ANSWER
==========================
2005-11-30-19.42.21.873002
Figure 318, CHAR function example - timestamp value

SELECT

CHAR(CURRENT TIMESTAMP)
sysibm.sysdummy1;

d2
,CHAR(d2)
AS cd2
,DIGITS(d2) AS dd2
FROM
(SELECT DEC(d1,4,1) AS d2
FROM
scalar
)AS xxx
ORDER BY 1;
Figure 319, DIGITS vs. CHAR

ANSWER
================
D2
CD2
DD2
---- ------ ----2.4 -002.4 0024
0.0 000.0 0000
1.8 001.8 0018

SELECT 'A'
AS "c"
,ASCII('A')
AS "c>n"
,CHR(ASCII('A')) AS "c>n>c"
,CHR(333)
AS "nl"
FROM
staff
WHERE id = 10;
Figure 320, CHR function examples

SELECT c1
,CLOB(c1)
AS cc1
,CLOB(c1,3) AS cc2
FROM
scalar;

ANSWER
=================
C C>N C>N>C NL
- --- ----- -A
65 A

ANSWER
===================
C1
CC1
CC2
------ ------ --ABCDEF ABCDEF ABC
ABCD
ABCD
ABC
AB
AB
AB

Figure 321, CLOB function examples

SELECT

id
,comm
,COALESCE(comm,0)
FROM
staff
WHERE
id < 30
ORDER BY id;
Figure 322, COALESCE function example

ANSWER
==================
ID COMM
3
-- ------ -----10
0.00
20 612.45 612.45

WITH temp1(c1,c2,c3) AS
(VALUES (CAST(NULL AS SMALLINT)
,CAST(NULL AS SMALLINT)
,CAST(10
AS SMALLINT)))
SELECT COALESCE(c1,c2,c3) AS cc1
,CASE
WHEN c1 IS NOT NULL THEN c1
WHEN c2 IS NOT NULL THEN c2
WHEN c3 IS NOT NULL THEN c3
END AS cc2
FROM
TEMP1;
Figure 323, COALESCE and equivalent CASE expression

SELECT COUNT(*)

AS #rows

ANSWER
========
CC1 CC2
--- --10
10

ANSWER

,MIN(id)
AS min_id
,COALESCE(MIN(id),-1) AS ccc_id
FROM
staff
WHERE id < 5;
Figure 324, NOT NULL field returning null value

===================
#ROWS MIN_ID CCC_ID
----- ------ -----0
-1

SELECT

ANSWER
===================
1
2
3
4
5
--- --- --- --- --AB AB AB ABC ABC

'A' || 'B'
,'A' CONCAT 'B'
,CONCAT('A','B')
,'A' || 'B' || 'C'
,CONCAT(CONCAT('A','B'),'C')
FROM
staff
WHERE
id = 10;
Figure 325, CONCAT function examples

WITH temp1 (col1, col2) AS


ANSWER
(VALUES
('A' , 'YYY')
===============
,('AE', 'OOO')
COL1 COL2 COL3
,('AE', 'YYY')
---- ---- ----)
AE
OOO AEOOO
SELECT
col1
AE
YYY AEYYY
,col2
A
YYY AYYY
,col1 CONCAT col2 AS col3
FROM
temp1
ORDER BY col3;
Figure 326, CONCAT used with ORDER BY - wrong output sequence

WITH temp1 (col1, col2) AS


(VALUES
('A' , 'YYY')
,('AE', 'OOO')
,('AE', 'YYY')
)
SELECT
col1
,col2
,CHAR(col1,2) CONCAT
CHAR(col2,3) AS col3
FROM
temp1
ORDER BY col3;
Figure 327, CONCAT used with ORDER BY - correct output

WITH temp1(n1) AS
(VALUES (0)
UNION ALL

ANSWER
===============
COL1 COL2 COL3
---- ---- ----A
YYY A YYY
AE
OOO AEOOO
AE
YYY AEYYY

sequence

ANSWER
=======================
N1 RAN
COS
SIN

SELECT n1 + 10
FROM
temp1
WHERE
n1 < 90)
SELECT n1
,DEC(RADIANS(n1),4,3)
AS ran
,DEC(COS(RADIANS(n1)),4,3) AS cos
,DEC(SIN(RADIANS(n1)),4,3) AS sin
FROM
temp1;

-0
10
20
30
40
50
60
70
80
90
Figure 328, RADIAN, COS, and SIN functions example

----0.000
0.174
0.349
0.523
0.698
0.872
1.047
1.221
1.396
1.570

----1.000
0.984
0.939
0.866
0.766
0.642
0.500
0.342
0.173
0.000

----0.000
0.173
0.342
0.500
0.642
0.766
0.866
0.939
0.984
1.000

Figure 329, DATE function syntax

SELECT ts1
,DATE(ts1) AS dt1
FROM
scalar;

ANSWER
======================================
TS1
DT1
-------------------------- ---------1996-04-22-23.58.58.123456 1996-04-22
1996-08-15-15.15.15.151515 1996-08-15
0001-01-01-00.00.00.000000 0001-01-01
Figure 330, DATE function example - timestamp input

WITH temp1(n1) AS
(VALUES
(000001)
,(728000)
,(730120))
SELECT n1
,DATE(n1) AS d1
FROM
temp1;
Figure 331, DATE function example - numeric input

SELECT dt1
,DAY(dt1) AS day1
FROM
scalar
WHERE DAY(dt1) > 10;
Figure 332, DAY function examples

ANSWER
===================
N1
D1
------- ---------1 0001-01-01
728000 1994-03-13
730120 2000-01-01

ANSWER
================
DT1
DAY1
---------- ---1996-04-22
22
1996-08-15
15

SELECT

dt1
,DAY(dt1)
,dt1 -'1996-04-30'
,DAY(dt1 -'1996-04-30')
FROM
scalar
WHERE
DAY(dt1) > 10
ORDER BY dt1;
Figure 333, DAY function, using

AS day1
AS dur2
AS day2

ANSWER
=========================
DT1
DAY1 DUR2 DAY2
---------- ---- ---- ---1996-04-22
22 -8.
-8
1996-08-15
15 315.
15

date-duration input

SELECT dt1
,DAYNAME(dt1)
AS dy1
,LENGTH(DAYNAME(dt1)) AS dy2
FROM
scalar
WHERE DAYNAME(dt1) LIKE '%a%y'
ORDER BY dt1;

ANSWER
========================
DT1
DY1
DY2
---------- ------- --0001-01-01 Monday
6
1996-04-22 Monday
6
1996-08-15 Thursday
8

Figure 334, DAYNAME function example

SELECT

dt1
,DAYOFWEEK(dt1) AS dwk
,DAYNAME(dt1)
AS dnm
FROM
scalar
ORDER BY dwk
,dnm;

ANSWER
=========================
DT1
DWK DNM
---------- --- -------0001-01-01
2 Monday
1996-04-22
2 Monday
1996-08-15
5 Thursday

Figure 335, DAYOFWEEK function example

WITH
temp1 (n) AS
(VALUES (0)
UNION ALL
SELECT n+1
FROM
temp1
WHERE n < 9),
temp2 (dt1) AS
(VALUES(DATE('1999-12-25'))
,(DATE('2000-12-24'))),
temp3 (dt2) AS
(SELECT dt1 + n DAYS
FROM
temp1
,temp2)
SELECT
CHAR(dt2,ISO)
,SUBSTR(DAYNAME(dt2),1,3)
,WEEK(dt2)
,DAYOFWEEK(dt2)

AS
AS
AS
AS

date
day
w
d

ANSWER
========================
DATE
DAY W D WI I
---------- --- -- - -- 1999-12-25 Sat 52 7 51 6
1999-12-26 Sun 53 1 51 7
1999-12-27 Mon 53 2 52 1
1999-12-28 Tue 53 3 52 2
1999-12-29 Wed 53 4 52 3
1999-12-30 Thu 53 5 52 4
1999-12-31 Fri 53 6 52 5
2000-01-01 Sat 1 7 52 6
2000-01-02 Sun 2 1 52 7
2000-01-03 Mon 2 2 1 1
2000-12-24 Sun 53 1 51 7
2000-12-25 Mon 53 2 52 1
2000-12-26 Tue 53 3 52 2
2000-12-27 Wed 53 4 52 3

,WEEK_ISO(dt2)
,DAYOFWEEK_ISO(dt2)
FROM
temp3
ORDER BY 1;

AS wi
AS i

2000-12-28
2000-12-29
2000-12-30
2000-12-31
2001-01-01
2001-01-02

Thu
Fri
Sat
Sun
Mon
Tue

53
53
53
54
1
1

5
6
7
1
2
3

52
52
52
52
1
1

4
5
6
7
1
2

Figure 336, DAYOFWEEK_ISO function example

SELECT

dt1
,DAYOFYEAR(dt1) AS dyr
FROM
scalar
ORDER BY dyr;

ANSWER
===============
DT1
DYR
---------- --0001-01-01
1
1996-04-22 113
1996-08-15 228

Figure 337, DAYOFYEAR function example

SELECT

dt1
,DAYS(dt1) AS dy1
FROM
scalar
ORDER BY dy1
,dt1;

ANSWER
==================
DT1
DY1
---------- -----0001-01-01
1
1996-04-22 728771
1996-08-15 728886

Figure 338, DAYS function example

Figure 339, DBPARTITIONNUM function syntax

SELECT
FROM
WHERE

DBPARTITIONNUM(id) AS dbnum
staff
id = 10;

Figure 340, DBPARTITIONNUM function example

Figure 341, DECIMAL function syntax

ANSWER
======
DBNUM
----0

WITH temp1(n1,n2,c1,c2) AS
(VALUES
(123
,1E2
,'123.4'
,'567$8'))
SELECT DEC(n1,3)
AS dec1
,DEC(n2,4,1)
AS dec2
,DEC(c1,4,1)
AS dec3
,DEC(c2,4,1,'$') AS dec4
FROM
temp1;
Figure 342, DECIMAL function examples

ANSWER
==========================
DEC1 DEC2
DEC3
DEC4
----- ------ ------ -----123. 100.0 123.4 567.8

Figure 343, DECRYPT function syntax

SELECT

id
,name
,DECRYPT_CHAR(name2,'CLUELESS')
AS name3
,GETHINT(name2)
AS hint
,name2
FROM
(SELECT id
,name
,ENCRYPT(name,'CLUELESS','MY BOSS') AS name2
FROM
staff
WHERE id < 30
)AS xxx
ORDER BY id;
Figure 344, DECRYPT_CHAR function example

SELECT

a.name
AS n1
,SOUNDEX(a.name) AS s1
,b.name
AS n2
,SOUNDEX(b.name) AS s2
,DIFFERENCE
(a.name,b.name) AS df
FROM
staff a
,staff b
WHERE
a.id = 10
AND
b.id > 150
AND
b.id < 250
ORDER BY df DESC
,n2 ASC;
Figure 345, DIFFERENCE function example

ANSWER
==============================
N1
S1
N2
S2
DF
------- ---- --------- ---- -Sanders S536 Sneider
S536 4
Sanders S536 Smith
S530 3
Sanders S536 Lundquist L532 2
Sanders S536 Daniels
D542 1
Sanders S536 Molinare M456 1
Sanders S536 Scoutten S350 1
Sanders S536 Abrahams A165 0
Sanders S536 Kermisch K652 0
Sanders S536 Lu
L000 0

SELECT s1
,DIGITS(s1) AS ds1
,d1
,DIGITS(d1) AS dd1
FROM
scalar;
Figure 346, DIGITS function examples

ANSWER
=========================
S1
DS1
D1
DD1
------ ----- ----- ---2 00002
-2.4 024
0 00000
0.0 000
1 00001
1.8 018

WITH temp1(c1,d1) AS
ANSWER (output shortened)
(VALUES ('12345',12.4)
==================================
,('-23.5',1234)
C1D
D1D
,('1E+45',-234)
---------------- ---------------,('-2e05',+2.4))
+1.23450000E+004 +1.24000000E+001
SELECT DOUBLE(c1) AS c1d
-2.35000000E+001 +1.23400000E+003
,DOUBLE(d1) AS d1d
+1.00000000E+045 -2.34000000E+002
FROM
temp1;
-2.00000000E+005 +2.40000000E+000
Figure 347, DOUBLE function examples

Figure 348, DECRYPT function syntax

SELECT

id
,name
,ENCRYPT(name,'THAT IDIOT','MY BROTHER') AS name2
FROM
staff
WHERE ID < 30
ORDER BY id;
Figure 349, ENCRYPT function example

WITH temp1(n1) AS
(VALUES (0)
UNION ALL
SELECT n1 + 1
FROM
temp1
WHERE
n1 < 10)
SELECT n1
,EXP(n1)
AS e1
,SMALLINT(EXP(n1)) AS e2
FROM
temp1;

ANSWER
==============================
N1 E1
E2
-- --------------------- ----0 +1.00000000000000E+0
1
1 +2.71828182845904E+0
2
2 +7.38905609893065E+0
7
3 +2.00855369231876E+1
20
4 +5.45981500331442E+1
54
5 +1.48413159102576E+2
148

Figure 350, EXP function examples

6
7
8
9
10

SELECT d1
,FLOOR(d1) AS d2
,f1
,FLOOR(f1) AS f2
FROM
scalar;

+4.03428793492735E+2
403
+1.09663315842845E+3 1096
+2.98095798704172E+3 2980
+8.10308392757538E+3 8103
+2.20264657948067E+4 22026

ANSWER (float output shortened)


===================================
D1
D2
F1
F2
----- ---- ---------- ----------2.4
-3.
-2.400E+0
-3.000E+0
0.0
+0.
+0.000E+0
+0.000E+0
1.8
+1.
+1.800E+0
+1.000E+0

Figure 351, FLOOR function examples

SELECT

id
,GENERATE_UNIQUE()
AS unique_val#1
,DEC(HEX(GENERATE_UNIQUE()),26) AS unique_val#2
FROM
staff
WHERE
id < 50
ORDER BY id;
ANSWER
================= ===========================
ID UNIQUE_VAL#1
UNIQUE_VAL#2
-- -------------- --------------------------NOTE: 2ND FIELD =>
10
20011017191648990521000000.
IS UNPRINTABLE. =>
20
20011017191648990615000000.
30
20011017191648990642000000.
40
20011017191648990669000000.
Figure 352, GENERATE_UNIQUE function examples

SELECT

u1
,SUBSTR(u1,20,1) CONCAT SUBSTR(u1,19,1)
SUBSTR(u1,18,1) CONCAT SUBSTR(u1,17,1)
SUBSTR(u1,16,1) CONCAT SUBSTR(u1,15,1)
SUBSTR(u1,14,1) CONCAT SUBSTR(u1,13,1)
SUBSTR(u1,12,1) CONCAT SUBSTR(u1,11,1)
SUBSTR(u1,10,1) CONCAT SUBSTR(u1,09,1)
SUBSTR(u1,08,1) CONCAT SUBSTR(u1,07,1)
SUBSTR(u1,06,1) CONCAT SUBSTR(u1,05,1)
SUBSTR(u1,04,1) CONCAT SUBSTR(u1,03,1)
SUBSTR(u1,02,1) CONCAT SUBSTR(u1,01,1)
FROM
(SELECT HEX(GENERATE_UNIQUE()) AS u1
FROM
staff
WHERE id < 50) AS xxx
ORDER BY u2;

CONCAT
CONCAT
CONCAT
CONCAT
CONCAT
CONCAT
CONCAT
CONCAT
CONCAT
AS U2

ANSWER
================================================
U1
U2
-------------------------- -------------------20000901131649119940000000 04991194613110900002
20000901131649119793000000 39791194613110900002
20000901131649119907000000 70991194613110900002
20000901131649119969000000 96991194613110900002
Figure 353, GENERATE_UNIQUE output, characters reversed to make pseudo-random

SELECT

u1
,SUBSTR(reverse(CHAR(u1)),7,20) AS u2
FROM
(SELECT HEX(GENERATE_UNIQUE()) AS u1
FROM
STAFF
WHERE ID < 50) AS xxx
ORDER BY U2;
Figure 354, GENERATE_UNIQUE output, characters reversed using function

SELECT

id
,name
,GETHINT(name2) AS hint
FROM
(SELECT id
,name
,ENCRYPT(name,'THAT IDIOT','MY BROTHER') AS name2
FROM
staff
WHERE id < 30
ANSWER
)AS xxx
=====================
ORDER BY id;
ID NAME
HINT
-- ------- ---------10 Sanders MY BROTHER
20 Pernal MY BROTHER
Figure 355, GETHINT function example

SELECT
FROM
WHERE

HASHEDVALUE(id) AS hvalue
staff
id = 10;

Figure 356, HASHEDVALUE function example

WITH temp1(n1) AS
(VALUES (-3)
UNION ALL

ANSWER
======
HVALUE
-----0

ANSWER
===============================
S SHX DHX
FHX

SELECT n1 + 1
FROM
temp1
WHERE
n1 < 3)
SELECT SMALLINT(n1)
,HEX(SMALLINT(n1))
,HEX(DEC(n1,4,0))
,HEX(DOUBLE(n1))
FROM
temp1;
Figure 357, HEX function

-- ---- ------3 FDFF 00003D


-2 FEFF 00002D
AS s
-1 FFFF 00001D
AS shx
0 0000 00000C
AS dhx
1 0100 00001C
AS fhx
2 0200 00002C
3 0300 00003C
examples, numeric data

---------------00000000000008C0
00000000000000C0
000000000000F0BF
0000000000000000
000000000000F03F
0000000000000040
0000000000000840

SELECT c1
,HEX(c1) AS chx
,v1
,HEX(v1) AS vhx
FROM
scalar;

ANSWER
=======================================
C1
CHX
V1
VHX
------ ------------ ------ -----------ABCDEF 414243444546 ABCDEF 414243444546
ABCD
414243442020 ABCD
41424344
AB
414220202020 AB
4142
Figure 358, HEX function examples, character & varchar

SELECT dt1
,HEX(dt1) AS dthx
,tm1
,HEX(tm1) AS tmhx
FROM
scalar;

ANSWER
===================================
DT1
DTHX
TM1
TMHX
---------- -------- -------- -----1996-04-22 19960422 23:58:58 235858
1996-08-15 19960815 15:15:15 151515
0001-01-01 00010101 00:00:00 000000
Figure 359, HEX function examples, date & time

SELECT

tm1
,HOUR(tm1) AS hr
FROM
scalar
ORDER BY tm1;

ANSWER
============
TM1
HR
-------- -00:00:00
0
15:15:15 15
23:58:58 23

Figure 360, HOUR function example

CREATE TABLE seq#


(ident_val
INTEGER
NOT NULL GENERATED ALWAYS AS IDENTITY
,cur_ts
TIMESTAMP NOT NULL
,PRIMARY KEY (ident_val));
COMMIT;

INSERT INTO seq# VALUES(DEFAULT,CURRENT TIMESTAMP);


WITH temp (idval) AS
(VALUES (IDENTITY_VAL_LOCAL()))
SELECT *
FROM
temp;
Figure 361, IDENTITY_VAL_LOCAL function usage

ANSWER
======
IDVAL
----1.

Figure 362, INSERT function syntax

SELECT name
,INSERT(name,3,2,'A')
,INSERT(name,3,2,'AB')
,INSERT(name,3,2,'ABC')
FROM
staff
WHERE id < 40;

ANSWER (4K output fields shortened)


===================================
NAME
2
3
4
-------- ------- -------- --------Sanders SaAers SaABers SaABCers
Pernal
PeAal
PeABal
PeABCal
Marenghi MaAnghi MaABnghi MaABCnghi
Figure 363, INSERT function examples

SELECT d1
,INTEGER(d1)
,INT('+123')
,INT('-123')
,INT(' 123 ')
FROM
scalar;

ANSWER
====================================
D1
2
3
4
5
----- ----- ------ ------ ------2.4
-2
123
-123
123
0.0
0
123
-123
123
1.8
1
123
-123
123
Figure 364, INTEGER function examples

WITH temp1(dt1) AS
(VALUES ('0001-01-01-00.00.00')
,('1752-09-10-00.00.00')
,('1993-01-03-00.00.00')
,('1993-01-03-23.59.59'))
SELECT DATE(dt1)
AS dt
,DAYS(dt1)
AS dy
,JULIAN_DAY(dt1) AS dj
FROM
temp1;
Figure 365, JULIAN_DAY function example

ANSWER
=========================
DT
DY
DJ
---------- ------ ------0001-01-01
1 1721426
1752-09-10 639793 2361218
1993-01-03 727566 2448991
1993-01-03 727566 2448991

SELECT

bd
,JULIAN_DAY(bd)
,(1461 * (YEAR(bd) + 4800 +
(MONTH(bd)-14)/12))/4
+( 367 * (MONTH(bd)- 2
- 12*((MONTH(bd)-14)/12)))/12
-(
3 * ((YEAR(bd) + 4900 +
(MONTH(bd)-14)/12)/100))/4
+DAY(bd) - 32075
FROM
(SELECT birthdate AS bd
FROM
employee
WHERE midinit = 'R'
ANSWER
) AS xxx
==========================
ORDER BY bd;
BD
2
3
---------- ------- ------1926-05-17 2424653 2424653
1936-03-28 2428256 2428256
1946-07-09 2432011 2432011
1955-04-12 2435210 2435210
Figure 366, JULIAN_DAY function examples

ANSWER
=============================
DT
DJ1
DJ2
---------- ---------- ------1997-01-01 1996-12-17 1997001
1997-01-02 1996-12-18 1997002
1997-12-31 1997-12-16 1997365

WITH temp1(dt1) AS
(VALUES ('1997-01-01')
,('1997-01-02')
,('1997-12-31'))
SELECT DATE(dt1) AS dt
,DATE(dt1) - 15 DAYS AS dj1
,YEAR(dt1) * 1000 + DAYOFYEAR(dt1) AS dj2
FROM
temp1;
Figure 367, Julian Date outputs

SELECT name
,LCASE(name) AS lname
,UCASE(name) AS uname
FROM
staff
WHERE id < 30;
Figure 368, LCASE function example

WITH temp1(c1) AS
(VALUES (' ABC')
,(' ABC ')
,('ABC '))
SELECT c1
,LEFT(c1,4)
AS c2
,LENGTH(LEFT(c1,4)) AS l2

ANSWER
=========================
NAME
LNAME
UNAME
------- ------- ------Sanders sanders SANDERS
Pernal
pernal
PERNAL

ANSWER
================
C1
C2
L2
----- ----- -ABC
AB
4
ABC
ABC
4
ABC
ABC
4

FROM
temp1;
Figure 369, LEFT function examples

SELECT LENGTH(d1)
,LENGTH(f1)
,LENGTH(s1)
,LENGTH(c1)
,LENGTH(RTRIM(c1))
FROM
scalar;
Figure 370, LENGTH function examples

WITH temp1(n1) AS
(VALUES (1),(123),(1234)
,(12345),(123456))
SELECT n1
,LOG(n1) AS l1
FROM
temp1;

Figure 371, LOG function example

ANSWER
=======================
1
2
3
4
5
--- --- --- --- --2
8
2
6
6
2
8
2
6
4
2
8
2
6
2

ANSWER
===============================
N1
L1
------ ----------------------1
+0.00000000000000E+000
123
+4.81218435537241E+000
1234
+7.11801620446533E+000
12345
+9.42100640177928E+000
123456
+1.17236400962654E+001

Figure 372, LOCATE function syntax

SELECT c1
,LOCATE('D', c1)
,LOCATE('D', c1,2)
,LOCATE('EF',c1)
,LOCATE('A', c1,2)
FROM
scalar;

ANSWER
==========================
C1
2
3
4
5
------ --- --- --- --ABCDEF
4
4
5
0
ABCD
4
4
0
0
AB
0
0
0
0

Figure 373, LOCATE function examples

WITH temp1(n1) AS
(VALUES (1),(123),(1234)
,(12345),(123456))
SELECT n1

ANSWER
===============================
N1
L1
------ -----------------------

,LOG10(n1) AS l1
temp1;

FROM

Figure 374, LOG10 function example

WITH temp1(c1) AS
(VALUES (' ABC')
,(' ABC ')
,('ABC '))
SELECT c1
,LTRIM(c1)
AS c2
,LENGTH(LTRIM(c1)) AS l2
FROM
temp1;
Figure 375, LTRIM function example

1
123
1234
12345
123456

+0.00000000000000E+000
+2.08990511143939E+000
+3.09131515969722E+000
+4.09149109426795E+000
+5.09151220162777E+000

ANSWER
================
C1
C2
L2
----- ----- -ABC ABC
3
ABC
ABC
4
ABC
ABC
5

SELECT

ts1
,MICROSECOND(ts1)
FROM
scalar
ORDER BY ts1;

ANSWER
======================================
TS1
2
-------------------------- ----------0001-01-01-00.00.00.000000
0
1996-04-22-23.58.58.123456
123456
1996-08-15-15.15.15.151515
151515
Figure 376, MICROSECOND function example

SELECT ts1
ANSWER
,MIDNIGHT_SECONDS(ts1)
======================================
,HOUR(ts1)*3600 +
TS1
2
3
MINUTE(ts1)*60 +
-------------------------- ----- ----SECOND(ts1)
0001-01-01-00.00.00.000000
0
0
FROM
scalar
1996-04-22-23.58.58.123456 86338 86338
ORDER BY ts1;
1996-08-15-15.15.15.151515 54915 54915
Figure 377, MIDNIGHT_SECONDS function example

WITH temp1 (ms) AS


(SELECT MIDNIGHT_SECONDS(ts1)
FROM
scalar
)

ANSWER
==============
MS
TM
----- -------0 00:00:00
54915 15:15:15
86338 23:58:58

SELECT ms
,SUBSTR(DIGITS(ms/3600
),9) ||
SUBSTR(DIGITS((ms-((MS/3600)*3600))/60 ),9) ||
SUBSTR(DIGITS(ms-((MS/60)*60)
),9) AS
FROM
temp1
ORDER BY 1;
Figure 378, Convert MIDNIGHT_SECONDS output back to a

':' ||
':' ||
tm
time value

SELECT

ts1
,MINUTE(ts1)
FROM
scalar
ORDER BY ts1;

ANSWER
======================================
TS1
2
-------------------------- ----------0001-01-01-00.00.00.000000
0
1996-04-22-23.58.58.123456
58
1996-08-15-15.15.15.151515
15
Figure 379, MINUTE function example

WITH temp1(n1,n2) AS
(VALUES (-31,+11)
UNION ALL
SELECT n1 + 13
,n2 - 4
FROM
temp1
WHERE
n1 < 60
)
SELECT
n1
,n2
,n1/n2
,n1-((n1/n2)*n2)
,MOD(n1,n2)
FROM
temp1
ORDER BY 1;
Figure 380, MOD function

SELECT

dt1
,MONTH(dt1)
,MONTHNAME(dt1)
FROM
scalar
ORDER BY dt1;

AS div
AS md1
AS md2

ANSWER
=======================
N1
N2
DIV MD1 MD2
--- --- --- --- ---31
11
-2
-9
-9
-18
7
-2
-4
-4
-5
3
-1
-2
-2
8
-1
-8
0
0
21
-5
-4
1
1
34
-9
-3
7
7
47 -13
-3
8
8
60 -17
-3
9
9

example

ANSWER
=======================
DT1
2
3
---------- -- ------0001-01-01
1 January
1996-04-22
4 April
1996-08-15
8 August
Figure 381, MONTH and MONTHNAME functions example

WITH temp1 (n1,n2) AS


(VALUES (DECIMAL(1234,10)
,DECIMAL(1234,10)))
SELECT n1
,n2
,n1 * n2
AS p1
,"*"(n1,n2)
AS p2
,MULTIPLY_ALT(n1,n2) AS p3
FROM
temp1;
Figure 382, Multiplying numbers - examples

>>
>>
>>
>>
>>

ANSWER
========
1234.
1234.
1522756.
1522756.
1522756.

<--MULTIPLY_ALT->
RESULT
RESULT
SCALE
PRECSION
INPUT#1
INPUT#2
"*" OPERATOR MULTIPLY_ALT
TRUNCATD TRUNCATD
========== ========== ============ ============
======== =======
DEC(05,00) DEC(05,00) DEC(10,00)
DEC(10,00)
NO
NO
DEC(10,05) DEC(11,03) DEC(21,08)
DEC(21,08)
NO
NO
DEC(20,15) DEC(21,13) DEC(31,28)
DEC(31,18)
YES
NO
DEC(26,23) DEC(10,01) DEC(31,24)
DEC(31,19)
YES
NO
DEC(31,03) DEC(15,08) DEC(31,11)
DEC(31,03)
YES
YES
Figure 383, Decimal multiplication - same output lengths

SELECT s1
,NULLIF(s1,0)
,c1
,NULLIF(c1,'AB')
FROM
scalar
WHERE NULLIF(0,0) IS NULL;
Figure 384, NULLIF function examples

SELECT
FROM
WHERE

PARTITION(id) AS pp
staff
id = 10;

SELECT

c1
,POSSTR(c1,' ') AS p1
,POSSTR(c1,'CD') AS p2
,POSSTR(c1,'cd') AS p3
FROM
scalar
ORDER BY 1;
Figure 385, POSSTR function examples

ANSWER
=====================
S1 2
C1
4
--- --- ------ ------2 -2 ABCDEF ABCDEF
0
- ABCD
ABCD
1
1 AB
-

ANSWER
======
PP
-0

ANSWER
==================
C1
P1 P2 P3
------ -- -- -AB
3
0
0
ABCD
5
3
0
ABCDEF
0
3
0

SELECT c1
,POSSTR(c1,' ')
AS p1
,LOCATE(' ',c1)
AS l1
,POSSTR(c1,'CD') AS p2
,LOCATE('CD',c1) AS l2
,POSSTR(c1,'cd') AS p3
,LOCATE('cd',c1) AS l3
,LOCATE('D',c1,2) AS l4
FROM
scalar
ORDER BY 1;
Figure 386, POSSTR vs. LOCATE functions

WITH temp1(n1) AS
(VALUES (1),(10),(100))
SELECT n1
,POWER(n1,1) AS p1
,POWER(n1,2) AS p2
,POWER(n1,3) AS p3
FROM
temp1;
Figure 387, POWER function examples

ANSWER
===========================
C1
P1 L1 P2 L2 P3 L3 L4
------ -- -- -- -- -- -- -AB
3 3 0 0 0 0 0
ABCD
5 5 3 3 0 0 4
ABCDEF 0 0 3 3 0 0 4

ANSWER
===============================
N1
P1
P2
P3
------- ------- ------- ------1
1
1
1
10
10
100
1000
100
100
10000 1000000

Figure 388, RAISE_ERROR function syntax

SELECT s1
,CASE
WHEN s1 < 1 THEN s1
ELSE RAISE_ERROR('80001',c1)
END AS s2
FROM
scalar;
Figure 389, RAISE_ERROR function example

WITH temp (num, ran) AS


(VALUES (INT(1)
,RAND(2))
UNION ALL
SELECT num + 1
,RAND()
FROM
temp
WHERE
num < 100000
)

ANSWER
==============
S1
S2
------ ------2
-2
0
0
SQLSTATE=80001

ANSWER
=============

SELECT

COUNT(*)
,COUNT(DISTINCT ran)
,DEC(AVG(ran),7,6)
,DEC(STDDEV(ran),7,6)
,DEC(MIN(ran),7,6)
,DEC(MAX(ran),7,6)
,DEC(MAX(ran),7,6) DEC(MIN(ran),7,6)
,DEC(VAR(ran),7,6)
FROM
temp;
Figure 390, Sample output from

AS
AS
AS
AS
AS
AS

#rows
#values
avg_ran
std_dev
min_ran
max_ran

AS range
AS variance

==>
==>
==>

100000
31242
0.499838
0.288706
0.000000
1.000000
1.000000
0.083351

RAND function

SELECT

deptno AS dno
,RAND(0) AS ran
FROM
department
WHERE
deptno < 'E'
ORDER BY 1;

ANSWER
===========================
DNO RAN
--- ---------------------A00 +1.15970336008789E-003
B01 +2.35572374645222E-001
C01 +6.48152104251228E-001
D01 +7.43736075930052E-002
D11 +2.70241401409955E-001
D21 +3.60026856288339E-001
Figure 391, Make reproducible random numbers (use seed)

SELECT

deptno AS dno
,RAND() AS ran
FROM
department
WHERE
deptno < 'D'
ORDER BY 1;

ANSWER
===========================
DNO RAN
--- ---------------------A00 +2.55287331766717E-001
B01 +9.85290078432569E-001
C01 +3.18918424024171E-001
Figure 392, Make non-reproducible random numbers (no seed)

WITH Temp1 (col1, col2, col3) AS


(VALUES (0
,SMALLINT(RAND(2)*35)*10
,DECIMAL(RAND()*10000,7,2))
UNION ALL
SELECT col1 + 1
,SMALLINT(RAND()*35)*10
,DECIMAL(RAND()*10000,7,2)
FROM
temp1
WHERE col1 + 1 < 10
)
SELECT *
FROM
temp1;
Figure 393, Use RAND to make sample data

ANSWER
===================
COL1 COL2 COL3
---- ---- ------0
0 9342.32
1
250 8916.28
2
310 5430.76
3
150 5996.88
4
110 8066.34
5
50 5589.77
6
130 8602.86
7
340
184.94
8
310 5441.14
9
70 9267.55

WITH temp1 (col1,ran1,ran2) AS


ANSWER
(VALUES (0
===================
,RAND(2)
COL#1 RAN#1 RAN#2
,RAND()+(RAND()/1E5) )
----- ----- ----UNION ALL
30000 19698 29998
SELECT col1 + 1
,RAND()
,RAND() +(RAND()/1E5)
FROM
temp1
WHERE col1 + 1 < 30000
)
SELECT COUNT(*)
AS col#1
,COUNT(DISTINCT ran1) AS ran#1
,COUNT(DISTINCT ran2) AS ran#2
FROM
temp1;
Figure 394, Use RAND to make many distinct random values

SELECT

id
,name
FROM
staff
WHERE
RAND() < 0.1
ORDER BY id;
Figure 395, Randomly select 10% of matching rows

SELECT

id
,name
FROM
(SELECT s.*
,ROW_NUMBER() OVER(ORDER BY RAND()) AS r
FROM
staff s
)AS xxx
WHERE
r <= 5
ORDER BY id;
Figure 396, Select five random rows

UPDATE staff
SET
salary = RAND()*10000
WHERE
id < 50;
Figure 397, Use RAND to assign random salaries

ANSWER
============
ID NAME
--- -------140 Fraye
190 Sneider
290 Quill

ANSWER
============
ID NAME
--- -------10 Sanders
30 Marenghi
190 Sneider
270 Lea
280 Wilson

ANSWERS
================================
SELECT n1
AS dec
=> 1234567890.123456789012345678901
,DOUBLE(n1) AS dbl
=>
1.23456789012346e+009
,REAL(n1)
AS rel
=>
1.234568e+009
,INTEGER(n1) AS int
=>
1234567890
,BIGINT(n1) AS big
=>
1234567890
FROM
(SELECT 1234567890.123456789012345678901 AS n1
FROM
staff
WHERE id = 10) AS xxx;
Figure 398, REAL and other numeric function examples

Figure 399, REPEAT function syntax

SELECT

id
,CHAR(REPEAT(name,3),40)
FROM
staff
WHERE
id < 40
ORDER BY id;

ANSWER
===========================
ID 2
-- -----------------------10 SandersSandersSanders
20 PernalPernalPernal
30 MarenghiMarenghiMarenghi

Figure 400, REPEAT function example

Figure 401, REPLACE function syntax

SELECT c1
,REPLACE(c1,'AB','XY') AS r1
,REPLACE(c1,'BA','XY') AS r2
FROM
scalar;

Figure 402, REPLACE function examples

ANSWER
======================
C1
R1
R2
------ ------ -----ABCDEF XYCDEF ABCDEF
ABCD
XYCD
ABCD
AB
XY
AB

SELECT c1
,REPLACE(REPLACE(
REPLACE(REPLACE(c1,
'AB','XY'),'ab','XY'),
'Ab','XY'),'aB','XY')
FROM
scalar;

ANSWER
==============
C1
R1
------ -----ABCDEF XYCDEF
ABCD
XYCD
AB
XY

Figure 403, Nested REPLACE functions

WITH temp1(c1) AS
(VALUES (' ABC')
,(' ABC ')
,('ABC '))
SELECT c1
,RIGHT(c1,4)
AS c2
,LENGTH(RIGHT(c1,4)) as l2
FROM
temp1;
Figure 404, RIGHT function examples

ANSWER
================
C1
C2
L2
----- ----- -ABC
ABC
4
ABC
ABC
4
ABC
BC
4

ANSWER
===============================================
D1
P2
P1
P0
N1
N2
------- ------- ------- ------- ------- ------123.400 123.400 123.400 123.000 120.000 100.000
23.450 23.450 23.400 23.000 20.000
0.000
3.456
3.460
3.500
3.000
0.000
0.000
0.056
0.060
0.100
0.000
0.000
0.000

WITH temp1(d1) AS
(VALUES (123.400)
,( 23.450)
,( 3.456)
,(
.056))
SELECT d1
,DEC(ROUND(d1,+2),6,3) AS p2
,DEC(ROUND(d1,+1),6,3) AS p1
,DEC(ROUND(d1,+0),6,3) AS p0
,DEC(ROUND(d1,-1),6,3) AS n1
,DEC(ROUND(d1,-2),6,3) AS n2
FROM
temp1;
Figure 405, ROUND function examples

SELECT c1
,RTRIM(c1)
AS r1
,LENGTH(c1)
AS r2
,LENGTH(RTRIM(c1)) AS r3
FROM
scalar;
Figure 406, RTRIM function example

ANSWER
======================
C1
R1
R2 R3
------ ------ -- -ABCDEF ABCDEF
6
6
ABCD
ABCD
6
4
AB
AB
6
2

SELECT d1
,SIGN(d1)
,f1
,SIGN(f1)
FROM
scalar;

ANSWER (float output shortened)


=========================================
D1
2
F1
4
----- ---------- ---------- ----------2.4
-1.000E+0
-2.400E+0
-1.000E+0
0.0
+0.000E+0
+0.000E+0
+0.000E+0
1.8
+1.000E+0
+1.800E+0
+1.000E+0
Figure 407, SIGN function examples

WITH temp1(n1) AS
(VALUES (0)
UNION ALL
SELECT n1 + 10
FROM
temp1
WHERE
n1 < 80)
SELECT n1
,DEC(RADIANS(n1),4,3)
AS ran
,DEC(SIN(RADIANS(n1)),4,3) AS sin
,DEC(TAN(RADIANS(n1)),4,3) AS tan
FROM
temp1;
Figure 408, SIN function example

ANSWER
=======================
N1 RAN
SIN
TAN
-- ----- ----- ----0 0.000 0.000 0.000
10 0.174 0.173 0.176
20 0.349 0.342 0.363
30 0.523 0.500 0.577
40 0.698 0.642 0.839
50 0.872 0.766 1.191
60 1.047 0.866 1.732
70 1.221 0.939 2.747
80 1.396 0.984 5.671

SELECT d1
,SMALLINT(d1)
,SMALLINT('+123')
,SMALLINT('-123')
,SMALLINT(' 123 ')
FROM
scalar;

ANSWER
==================================
D1
2
3
4
5
----- ------ ------ ------ ------2.4
-2
123
-123
123
0.0
0
123
-123
123
1.8
1
123
-123
123
Figure 409, SMALLINT function examples

SELECT

FROM
WHERE
AND
AND

a.name
,SOUNDEX(a.name)
,b.name
,SOUNDEX(b.name)
,DIFFERENCE
(a.name,b.name)
staff a
,staff b
a.id = 10
b.id > 150
b.id < 250

AS
AS
AS
AS

n1
s1
n2
s2

AS df

ANSWER
==============================
N1
S1
N2
S2
DF
------- ---- --------- ---- -Sanders S536 Sneider
S536 4
Sanders S536 Smith
S530 3
Sanders S536 Lundquist L532 2
Sanders S536 Daniels
D542 1
Sanders S536 Molinare M456 1
Sanders S536 Scoutten S350 1
Sanders S536 Abrahams A165 0

ORDER BY df DESC
,n2 ASC;
Figure 410, SOUNDEX function example

Sanders S536 Kermisch


Sanders S536 Lu

WITH temp1(n1) AS
(VALUES (1),(2),(3))
SELECT n1
,SPACE(n1)
AS s1
,LENGTH(SPACE(n1)) AS s2
,SPACE(n1) || 'X' AS s3
FROM
temp1;
Figure 411, SPACE function examples

K652
L000

0
0

ANSWER
==================
N1 S1
S2 S3
-- ---- -- ---1
1
X
2
2
X
3
3
X

DB2 GET SNAPSHOT FOR DYNAMIC SQL ON SAMPLE WRITE TO FILE


ANSWER - PART OF (ONE OF THE STATEMENTS IN THE SQL CACHE)
=============================================================
Number of executions
= 8
Number of compilations
= 1
Worst preparation time (ms)
= 3
Best preparation time (ms)
= 3
Rows deleted
= Not Collected
Rows inserted
= Not Collected
Rows read
= Not Collected
Rows updated
= Not Collected
Rows written
= Not Collected
Statement sorts
= Not Collected
Total execution time (sec.ms)
= Not Collected
Total user cpu time (sec.ms)
= Not Collected
Total system cpu time (sec.ms) = Not Collected
Statement text
= select min(dept) from staff
Figure 412, GET SNAPSHOT command

SELECT
*
FROM
TABLE(SQLCACHE_SNAPSHOT()) SS
WHERE
SS.NUM_EXECUTIONS <> 0;
Figure 413, SQLCACHE_SNAPSHOT function example

SELECT

ORDINAL
,CHAR(PARMNAME,18)
,TYPENAME
,LENGTH

AS COLNO
AS COLNAME
AS COLTYPE

,SCALE
FROM
SYSCAT.FUNCPARMS
WHERE
FUNCSCHEMA = 'SYSFUN'
AND
FUNCNAME
= 'SQLCACHE_SNAPSHOT'
ORDER BY COLNO;
Figure 414, List columns returned by SQLCACHE_SNAPSHOT

WITH temp1(n1) AS
(VALUES (0.5),(0.0)
,(1.0),(2.0))
SELECT DEC(n1,4,3)
AS n1
,DEC(SQRT(n1),4,3) AS s1
FROM
temp1;

ANSWER
============
N1
S1
----- ----0.500 0.707
0.000 0.000
1.000 1.000
2.000 1.414

Figure 415, SQRT function example

Figure 416, SUBSTR function syntax

WITH temp1 (len, dat1) AS


ANSWER
(VALUES
( 6,'123456789')
=========================
,( 4,'12345'
)
LEN DAT1
LDAT SUBDAT
,( 16,'123'
)
--- --------- ---- -----)
6 123456789
9 123456
SELECT
len
4 12345
5 1234
,dat1
,LENGTH(dat1)
AS ldat
,SUBSTR(dat1,1,len) AS subdat
FROM
temp1;
Figure 417, SUBSTR function - error because length parm too long

WITH temp1 (len, dat1) AS


ANSWER
(VALUES
( 6,'123456789')
=========================
,( 4,'12345'
)
LEN DAT1
LDAT SUBDAT
,( 16,'123'
)
--- --------- ---- -----)
6 123456789
9 123456
SELECT
len
4 12345
5 1234
,dat1
16 123
3 123
,LENGTH(dat1) AS ldat
,SUBSTR(dat1,1,CASE
WHEN len < LENGTH(dat1) THEN len
ELSE LENGTH(dat1)
END ) AS subdat

FROM
temp1;
Figure 418, SUBSTR function - avoid error using CASE (see previous)

SELECT name
,LENGTH(name)
,SUBSTR(name,5)
,LENGTH(SUBSTR(name,5))
,SUBSTR(name,5,3)
,LENGTH(SUBSTR(name,5,3))
FROM
staff
WHERE id < 60;

ANSWER
===========================
NAME
LEN S1
L1 S2 L2
-------- --- ---- -- --- -Sanders
7 ers
3 ers 3
Pernal
6 al
2 al
3
Marenghi
8 nghi 4 ngh 3
O'Brien
7 ien
3 ien 3
Hanes
5 s
1 s
3
Figure 419, SUBSTR function - fixed length output if third parm. used
AS
AS
AS
AS
AS

len
s1
l1
s2
l2

SELECT

a.id
ANSWER
,a.dept
=========================
,a.salary
ID DEPT SALARY
DEPTSAL
,b.deptsal
-- ---- -------- -------FROM
staff a
10 20
18357.50 64286.10
,TABLE
20 20
18171.25 64286.10
(SELECT
b.dept
30 38
17506.75 77285.55
,SUM(b.salary) AS deptsal
FROM
staff b
WHERE
b.dept = a.dept
GROUP BY b.dept
)AS b
WHERE
a.id
< 40
ORDER BY a.id;
Figure 420, Full-select with external table reference

CREATE ALIAS emp1 FOR employee;


CREATE ALIAS emp2 FOR emp1;

ANSWER
=======================
TABSCHEMA TABNAME CARD
--------- -------- ---graeme
employee
-1

SELECT tabschema
,tabname
,card
FROM
syscat.tables
WHERE tabname
= TABLE_NAME('emp2','graeme');
Figure 421, TABLE_NAME function example

CREATE VIEW fred1 (c1, c2, c3)


AS VALUES (11, 'AAA', 'BBB');

ANSWER
===========================
TAB_SCH TAB_NME

CREATE ALIAS fred2 FOR fred1;


CREATE ALIAS fred3 FOR fred2;
DROP VIEW fred1;

-------- -----------------graeme
fred1
graeme
xxxxx

WITH temp1 (tab_sch, tab_nme) AS


(VALUES (TABLE_SCHEMA('fred3','graeme'),TABLE_NAME('fred3')),
(TABLE_SCHEMA('xxxxx')
,TABLE_NAME('xxxxx','xxx')))
SELECT *
FROM
temp1;
Figure 422, TABLE_SCHEMA and TABLE_NAME functions example

SELECT TIMESTAMP('1997-01-11-22.44.55.000000')
,TIMESTAMP('1997-01-11-22.44.55.000')
,TIMESTAMP('1997-01-11-22.44.55')
,TIMESTAMP('19970111224455')
,TIMESTAMP('1997-01-11','22.44.55')
FROM
staff
WHERE id = 10;
Figure 423, TIMESTAMP function examples

WITH temp1 (ts1) AS


(VALUES ('1999-12-31 23:59:59')
,('2002-10-30 11:22:33')
)
SELECT
ts1
,TIMESTAMP_FORMAT(ts1,'YYYY-MM-DD HH24:MI:SS') AS ts2
FROM
temp1
ORDER BY ts1;
ANSWER
===============================================
TS1
TS2
------------------- -------------------------1999-12-31 23:59:59 1999-12-31-23.59.59.000000
2002-10-30 11:22:33 2002-10-30-11.22.33.000000
Figure 424, TIMESTAMP_FORMAT function example

SELECT tm1
,TIMESTAMP_ISO(tm1)
FROM
scalar;

ANSWER
===================================
TM1
2
-------- -------------------------23:58:58 2000-09-01-23.58.58.000000
15:15:15 2000-09-01-15.15.15.000000
00:00:00 2000-09-01-00.00.00.000000
Figure 425, TIMESTAMP_ISO function example

WITH
temp1 (ts1,ts2) AS
(VALUES ('1996-03-01-00.00.01','1995-03-01-00.00.00')
,('1996-03-01-00.00.00','1995-03-01-00.00.01')),
temp2 (ts1,ts2) AS
(SELECT TIMESTAMP(ts1)
,TIMESTAMP(ts2)
FROM
temp1),
temp3 (ts1,ts2,df) AS
(SELECT ts1
,ts2
,CHAR(TS1 - TS2) AS df
ANSWER
FROM
temp2)
=============================
SELECT df
DF
DIF DYS
,TIMESTAMPDIFF(16,df) AS dif
--------------------- --- --,DAYS(ts1) - DAYS(ts2) AS dys
00010000000001.000000 365 366
FROM
temp3;
00001130235959.000000 360 366
Figure 426, TIMESTAMPDIFF function example

CREATE FUNCTION ts_diff_works(in_hi TIMESTAMP,in_lo TIMESTAMP)


RETURNS BIGINT
RETURN (BIGINT(DAYS(in_hi))
* 86400000000
+ BIGINT(MIDNIGHT_SECONDS(in_hi)) *
1000000
+ BIGINT(MICROSECOND(in_hi)))
-(BIGINT(DAYS(in_lo))
* 86400000000
+ BIGINT(MIDNIGHT_SECONDS(in_lo)) *
1000000
+ BIGINT(MICROSECOND(in_lo)));
Figure 427, Function to get difference between two timestamps

Figure 428, TRANSLATE function syntax

SELECT 'abcd'
,TRANSLATE('abcd')
,TRANSLATE('abcd','','a')
,TRANSLATE('abcd','A','A')
,TRANSLATE('abcd','A','a')
,TRANSLATE('abcd','A','ab')
,TRANSLATE('abcd','A','ab',' ')
,TRANSLATE('abcd','A','ab','z')
,TRANSLATE('abcd','AB','a')
FROM
staff
WHERE id = 10;
Figure 429, TRANSLATE function examples

==>
==>
==>

ANS.
====
abcd
ABCD
bcd
abcd
Abcd
A cd
A cd
Azcd
Abcd

NOTES
=================
No change
Make upper case
'a'=>' '
'A'=>'A'
'a'=>'A'
'a'=>'A','b'=>' '
'a'=>'A','b'=>' '
'a'=>'A','b'=>'z'
'a'=>'A'

SELECT c1
,REPLACE(c1,'AB','XY')
,REPLACE(c1,'BA','XY')
,TRANSLATE(c1,'XY','AB')
,TRANSLATE(c1,'XY','BA')
FROM
scalar
WHERE c1 = 'ABCD';
Figure 430, REPLACE vs. TRANSLATE

==>
==>
==>

ANSWER
======
ABCD
XYCD
ABCD
XYCD
YXCD

ANSWER
===============================================
D1
POS2
POS1
ZERO
NEG1
NEG2
------- ------- ------- ------- ------- ------123.400 123.400 123.400 123.000 120.000 100.000
23.450 23.440 23.400 23.000 20.000
0.000
3.456
3.450
3.400
3.000
0.000
0.000
0.056
0.050
0.000
0.000
0.000
0.000

WITH temp1(d1) AS
(VALUES (123.400)
,( 23.450)
,( 3.456)
,(
.056))
SELECT d1
,DEC(TRUNC(d1,+2),6,3) AS pos2
,DEC(TRUNC(d1,+1),6,3) AS pos1
,DEC(TRUNC(d1,+0),6,3) AS zero
,DEC(TRUNC(d1,-1),6,3) AS neg1
,DEC(TRUNC(d1,-2),6,3) AS neg2
FROM
temp1
ORDER BY 1 DESC;
Figure 431, TRUNCATE function examples

SELECT name
,LCASE(name) AS lname
,UCASE(name) AS uname
FROM
staff
WHERE id < 30;
Figure 432, UCASE function example

SELECT c1
,LENGTH(c1)
,VARCHAR(c1)
,LENGTH(VARCHAR(c1))
,VARCHAR(c1,4)

AS
AS
AS
AS

l1
v2
l2
v3

ANSWER
=========================
NAME
LNAME
UNAME
------- ------- ------Sanders sanders SANDERS
Pernal
pernal
PERNAL

ANSWER
========================
C1
L1 V2
L2 V3
------ -- ------ -- ---ABCDEF 6 ABCDEF 6 ABCD

FROM

scalar;

ABCD
AB

6 ABCD
6 AB

6 ABCD
6 AB

Figure 433, VARCHAR function examples

WITH temp1 (ts1) AS


(VALUES (TIMESTAMP('1999-12-31-23.59.59'))
,(TIMESTAMP('2002-10-30-11.22.33'))
)
SELECT
ts1
,VARCHAR_FORMAT(ts1,'YYYY-MM-DD HH24:MI:SS') AS ts2
FROM
temp1
ORDER BY ts1;
ANSWER
==============================================
TS1
TS2
-------------------------- ------------------1999-12-31-23.59.59.000000 1999-12-31 23:59:59
2002-10-30-11.22.33.000000 2002-10-30 11:22:33
Figure 434, VARCHAR_FORMAT function example

SELECT

WEEK(DATE('2000-01-01')) AS
,WEEK(DATE('2000-01-02')) AS
,WEEK(DATE('2001-01-02')) AS
,WEEK(DATE('2000-12-31')) AS
,WEEK(DATE('2040-12-31')) AS
FROM
sysibm.sysdummy1;
Figure 435, WEEK function examples

w1
w2
w3
w4
w5

WITH
temp1 (n) AS
(VALUES (0)
UNION ALL
SELECT n+1
FROM
temp1
WHERE n < 10),
temp2 (dt2) AS
(SELECT DATE('1998-12-27') + y.n YEARS
+ d.n DAYS
FROM
temp1 y
,temp1 d
WHERE y.n IN (0,2))
SELECT
CHAR(dt2,ISO)
dte
,SUBSTR(DAYNAME(dt2),1,3)
dy
,WEEK(dt2)
wk
,DAYOFWEEK(dt2)
dy
,WEEK_ISO(dt2)
wi
,DAYOFWEEK_ISO(dt2)
di
FROM
temp2
ORDER BY 1;

ANSWER
==================
W1 W2 W3 W4 W5
-- -- -- -- -1
2
1 54 53

ANSWER
==========================
DTE
DY WK DY WI DI
---------- --- -- -- -- -1998-12-27 Sun 53 1 52 7
1998-12-28 Mon 53 2 53 1
1998-12-29 Tue 53 3 53 2
1998-12-30 Wed 53 4 53 3
1998-12-31 Thu 53 5 53 4
1999-01-01 Fri 1 6 53 5
1999-01-02 Sat 1 7 53 6
1999-01-03 Sun 2 1 53 7
1999-01-04 Mon 2 2 1 1
1999-01-05 Tue 2 3 1 2
1999-01-06 Wed 2 4 1 3
2000-12-27 Wed 53 4 52 3
2000-12-28 Thu 53 5 52 4
2000-12-29 Fri 53 6 52 5
2000-12-30 Sat 53 7 52 6
2000-12-31 Sun 54 1 52 7
2001-01-01 Mon 1 2 1 1

2001-01-02
2001-01-03
2001-01-04
2001-01-05
2001-01-06

Figure 436, WEEK_ISO function example

SELECT dt1
,YEAR(dt1) AS yr
,WEEK(dt1) AS wk
FROM
scalar;

Figure 437, YEAR and WEEK functions example

SELECT

id
,salary
,"+"(salary)
AS s2
,"+"(salary,id) AS s3
FROM
staff
WHERE
id < 40
ORDER BY id;
Figure 438, PLUS function examples

Tue
Wed
Thu
Fri
Sat

1
1
1
1
1

3
4
5
6
7

1
1
1
1
1

2
3
4
5
6

ANSWER
======================
DT1
YR
WK
---------- ---- ---1996-04-22 1996
17
1996-08-15 1996
33
0001-01-01
1
1

ANSWER
=============================
ID SALARY
S2
S3
-- -------- -------- -------10 18357.50 18357.50 18367.50
20 18171.25 18171.25 18191.25
30 17506.75 17506.75 17536.75

SELECT

empno
,CHAR(birthdate,ISO)
AS bdate1
,CHAR(birthdate + 1 YEAR,ISO)
AS bdate2
,CHAR("+"(birthdate,DEC(00010000,8)),ISO)
AS bdate3
,CHAR("+"(birthdate,DOUBLE(1),SMALLINT(1)),ISO) AS bdate4
FROM
employee
WHERE
empno < '000040'
ORDER BY empno;
ANSWER
==================================================
EMPNO BDATE1
BDATE2
BDATE3
BDATE4
------ ---------- ---------- ---------- ---------000010 1933-08-24 1934-08-24 1934-08-24 1934-08-24
000020 1948-02-02 1949-02-02 1949-02-02 1949-02-02
000030 1941-05-11 1942-05-11 1942-05-11 1942-05-11
Figure 439, Adding one year to date value

SELECT

id
,salary

ANSWER
==============================

,"-"(salary)
AS s2
,"-"(salary,id) AS s3
FROM
staff
WHERE
id < 40
ORDER BY id;
Figure 440, MINUS function examples

id
,salary
,salary * id
AS s2
,"*"(salary,id) AS s3
FROM
staff
WHERE
id < 40
ORDER BY id;
Figure 441, MULTIPLY function examples

ID
-10
20
30

SALARY
-------18357.50
18171.25
17506.75

S2
---------18357.50
-18171.25
-17506.75

S3
-------18347.50
18151.25
17476.75

SELECT

ANSWER
===============================
ID SALARY
S2
S3
-- -------- --------- --------10 18357.50 183575.00 183575.00
20 18171.25 363425.00 363425.00
30 17506.75 525202.50 525202.50

SELECT

ANSWER
=============================
ID SALARY
S2
S3
-- -------- -------- -------10 18357.50 1835.750 1835.750
20 18171.25 908.562 908.562
30 17506.75 583.558 583.558

SELECT

ANSWER
===========================
ID N1
N2
N3
N4
--- ----- ----- ----- ----110 NganZ NganZ NganZ NganZ
210 LuZ
LuZ
LuZ
LuZ
270 LeaZ LeaZ LeaZ LeaZ

SELECT

ANSWER
====================
DEPT NAME
COMM
---- ------- ------15 Hanes
15 Rothman 1152.00
20 James
128.20
20 Pernal
612.45

id
,salary
,salary / id
AS s2
,"/"(salary,id) AS s3
FROM
staff
WHERE
id < 40
ORDER BY id;
Figure 442, DIVIDE function examples

id
,name || 'Z'
AS n1
,name CONCAT 'Z' AS n2
,"||"(name,'Z')
As n3
,CONCAT(name,'Z') As n4
FROM
staff
WHERE
LENGTH(name) < 5
ORDER BY id;
Figure 443, CONCAT function examples

dept
,name
,comm
FROM
staff
WHERE
dept < 30
AND
id
< 100
ORDER BY dept
,name;

Figure 444, Sample query - returns raw data

20 Sanders

15Hanes
15Rothman01152.00
20James00128.20
20Pernal00612.45
20Sanders
Figure 445, XML version of above data

15
1501152.00
2000128.20
2000612.45
20
Figure 446, Made name an attribute of employee

Figure 447, XMLSERIALIZE function syntax

SELECT

id
,XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Dept", dept)
AS CHAR(30)) AS xmldata
FROM
staff
WHERE
id BETWEEN 20 AND 30
ORDER BY id;
Figure 448, XMLSERIALIZE function example

Figure 449, XML2CLOB function syntax

Figure 450, XMLAGG function syntax

ANSWER
==================
ID XMLDATA
-- --------------20 20
30 38

SELECT

dept AS dp
,XMLSERIALIZE(CONTENT
XMLAGG(
XMLELEMENT(NAME "Nm",
ORDER BY id)
AS CHAR(40)) AS xmldata
FROM
staff
WHERE
dept < 30
AND
id
< 80
GROUP BY dept
ORDER BY dept;
Figure 451, XMLAGG function example

SELECT

FROM
WHERE
AND

name)
ANSWER
==================================
DP XMLDATA
-- ------------------------------15 HanesRothman
20 SandersPernal

XMLSERIALIZE(CONTENT
XMLAGG(
XMLELEMENT(NAME "Nm", name)
ORDER BY name)
AS CHAR(80)) AS xmldata
staff
dept < 30
id
< 80;

XMLDATA
-----------------------------------------------------------HanesPernalRothmanSanders
Figure 452, XMLAGG function example

Figure 453, XMLCONCAT function syntax

SELECT

id
,XMLSERIALIZE(CONTENT
XMLCONCAT(
XMLELEMENT(NAME "dp", dept)
,XMLELEMENT(NAME "nm", name)
)
AS CHAR(40)) AS xmldata
ANSWER
FROM
staff
==============================
WHERE
dept < 30
ID XMLDATA
AND
id
< 70
-- --------------------------ORDER BY id;
10 20Sanders
20 20Pernal
50 15Hanes
Figure 454, XMLCONCAT function example

Figure 455, XMLELEMENT function syntax

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "staff"
,XMLELEMENT(NAME "nm", name)
,XMLELEMENT(NAME "sc", salary, '+', comm)
)
AS CHAR(90)) AS xmldata
FROM
staff
WHERE
dept < 30
AND
id
< 60
ORDER BY id;

ANSWER
========================================================
Sanders18357.50+
Pernal18171.25+00612.45
Figure 456, XMLELEMENT function example

Figure 457, XMLATTRIBUTES function syntax

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Emp",
XMLATTRIBUTES(name AS "Nm", dept)
)
AS VARCHAR(100)) AS xmldata
FROM
staff
ANSWER
WHERE
dept < 30
==================================
AND
id
< 60
ORDER BY dept
,name;
Figure 458, XMLATTRIBUTES function example

Figure 459, XMLFOREST function syntax

SELECT

XMLSERIALIZE(CONTENT
XMLFOREST(name AS "Nm", dept AS "dp", comm)
AS VARCHAR(100)) AS xmldata
FROM
staff
WHERE
id IN (10,20)
ORDER BY id DESC;
ANSWER
===============================================
Pernal2000612.45
Sanders20
Figure 460, XMLFOREST function example

Figure 461, XMLNAMESPACES function syntax

SELECT

XMLSERIALIZE(CONTENT
XMLFOREST(
XMLNAMESPACES(DEFAULT 'http:\t1.com'
,
'http:\t2.com' AS "t2"
,
'http:\t3.com' AS "t3")
,name AS "nm", salary AS "sal")
AS VARCHAR(300)) AS xmldata
FROM
staff
WHERE
id = 20;
ANSWER (line breaks/indentation added)
===========================================
Pernal
18171.25
Figure 462, XMLNAMESPACES function example

SELECT

dept
,name
,comm
FROM
staff
WHERE
dept < 30
AND
id
< 100
ORDER BY dept
,name;
Figure 463, Sample query - returns raw data

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Emp",
XMLELEMENT(NAME "Dept", dept),
XMLELEMENT(NAME "Name", name),

ANSWER
====================
DEPT NAME
COMM
---- ------- ------15 Hanes
15 Rothman 1152.00
20 James
128.20
20 Pernal
612.45
20 Sanders
-

XMLELEMENT(NAME "Comm", comm)


)
AS VARCHAR(100))
FROM
staff
WHERE
dept < 30
AND
id
< 100
ORDER BY dept
,name;
ANSWER
===================================================================
15Hanes
15Rothman01152.00
20James00128.20
20Pernal00612.45
20Sanders
Figure 464, Sample query - returns XML data

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Emp",
XMLATTRIBUTES(name AS "Name"),
XMLELEMENT(NAME "Dept", dept),
XMLELEMENT(NAME "Comm", comm)
)
AS VARCHAR(100))
FROM
staff
WHERE
dept < 30
AND
id
< 100
ORDER BY dept
,name;
ANSWER
==============================================================
15
1501152.00
2000128.20
2000612.45
20
Figure 465, Sample query - returns XML data + attribute

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Data",
XMLELEMENT(NAME "Chr1",
XMLELEMENT(NAME "Chr2",
XMLELEMENT(NAME "VChr",
XMLELEMENT(NAME "Dec1",
XMLELEMENT(NAME "Dec2",
XMLELEMENT(NAME "Flt1",
XMLELEMENT(NAME "Int1",
XMLELEMENT(NAME "Int2",
XMLELEMENT(NAME "Time",
XMLELEMENT(NAME "Date",
XMLELEMENT(NAME "Ts" ,
)
AS VARCHAR(300)) AS xmldata

CHAR
(c1,3)),
CHAR
(c1,5)),
VARCHAR(c1,5)),
DECIMAL(n1,7,2)),
DECIMAL(n2,9,1)),
FLOAT (n2)),
INTEGER(n1)),
INTEGER(n2)),
TIME
(t1)),
DATE
(t1)),
TIMESTAMP(t1))

FROM

(SELECT

FROM
WHERE
)AS xxx;

'ABC'
,1234.56
,1234567
,TIMESTAMP('2004-09-14-22.33.44.123456')
staff
id = 10

AS
AS
AS
AS

c1
n1
n2
t1

ANSWER (line-breaks/indentation added)


======================================
ABC
ABC
ABC
01234.56
01234567.0
1.234567E6
1234
1234567
22:33:44
2004-09-14
2004-09-14T22:33:44.123456

Figure 466, XMLELEMENT output examples

ANSWER
WITH temp1 (indata) AS
===========================
(VALUES ('<txt
,('"txt'))
txt>
txt>
SELECT
indata
&txt
&txt
,XMLSERIALIZE(CONTENT
"txt
"txt
XMLELEMENT(NAME "Out", indata))
AS CHAR(50)) AS outdata
FROM
temp1;
Figure 467, Convert XML input strings

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Emp", dept, name, comm)
AS CHAR(50)) AS outdata
FROM
staff
ANSWER
WHERE
dept < 30
===========================
AND
id
< 100
15Hanes
ORDER BY dept
15Rothman01152.0020James00128.20
20Pernal00612.45
20Sanders
Figure 468, Concatenation done in XML function

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Emp", CHAR(dept) || name || CHAR(comm))

AS CHAR(50)) AS outdata
staff
dept < 30
id
< 100
dept
,name;

FROM
WHERE
AND
ORDER BY

ANSWER
=================================
15
20
20

Rothman01152.00
James00128.20
Pernal00612.45

Figure 469, Concatenation done before XML function

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Emp",
XMLATTRIBUTES(name), dept, comm)
)
AS CHAR(100)) AS xmldata
FROM
staff
WHERE
dept < 30
ANSWER
AND
id
< 100
====================================
ORDER BY dept
15
,name;
1501152.00
2000128.20
2000612.45
20
Figure 470, One element, one attribute, two data-items

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Emp",
XMLATTRIBUTES(name, dept, comm)
)
AS VARCHAR(100)) AS xmldata
FROM
staff
WHERE
dept < 30
AND
id
< 100
ORDER BY dept
ANSWER
,name;
====================================================

Figure 471, One element, three attributes, no data-items

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Emp",
XMLATTRIBUTES(name AS "Nm", dept AS "Dpt", comm)
)
AS VARCHAR(100)) AS xmldata

FROM
WHERE
AND
ORDER BY

staff
dept < 30
id
< 100
dept
,name;

ANSWER
=================================================

Figure 472, Assign names to attributes

SELECT

XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "Dpt",
XMLATTRIBUTES(dept),
XMLAGG(
XMLELEMENT(NAME "Emp",
XMLELEMENT(NAME "Nm", name),
XMLELEMENT(NAME "Cm", comm))
ORDER BY id)
)
AS VARCHAR(300)) AS xmldata
FROM
staff
WHERE
dept < 30
AND
id
< 100
GROUP BY dept;
ANSWER (line-breaks/indentation added)
===============================================
Hanes
Rothman01152.00
Sanders
Pernal00612.45
James00128.20
Figure 473, XMLAGG function example

Figure 474, REC2XML function syntax

WITH temp1 (indata) AS


(VALUES ('<txt
txt>
txt>
&txt
&txt
"txt
"txt
'txt
&apos;txt
Figure 475, REC2XML function character conversion

WITH temp1 (indata) AS


(VALUES ('<txt
txt>
txt>
&txt
&txt
"txt
"txt
'txt
'txt
Figure 476, REC2XML function without character conversion

SELECT
FROM
WHERE
ORDER BY

REC2XML(1.0, 'COLATTVAL', 'row', dept, name, comm) AS txt


staff
id BETWEEN 30 AND 40
dept
,name;
ANSWER (line-breaks/indentation added)
============================================
38
Marenghi

38
O&apos;Brien
00846.55
Figure 477, REC2XML function example

Figure 478, Sourced function syntax

CREATE FUNCTION digi_int (SMALLINT)


RETURNS CHAR(5)
SOURCE SYSIBM.DIGITS(SMALLINT);
Figure 479, Create sourced function

SELECT

id
,DIGITS(id)
,digi_int(id)
FROM
staff
WHERE
id < 40
ORDER BY id;

AS ID
AS I2
AS I3

ANSWER
==============
ID I2
I3
-- ----- ----10 00010 00010
20 00020 00020
30 00030 00030

Figure 480, Using sourced function - works

SELECT

id
,digi_int(INT(id))
FROM
staff
WHERE
id < 50;
Figure 481, Using sourced function - fails

ANSWER
=======

CREATE DISTINCT TYPE us_dollars AS DEC(7,2) WITH COMPARISONS;


CREATE TABLE customers
(ID
SMALLINT
,balance
us_dollars

NOT NULL
NOT NULL);

INSERT INTO customers VALUES (1 ,111.11),(2 ,222.22);


SELECT
*
FROM
customers
ORDER BY ID;
Figure 482, Create distinct type and test table

SELECT

id
,balance * 10
FROM
customers
ORDER BY id;
Figure 483, Do multiply - fails

ANSWER
==========
ID balance
-- ------1 111.11
2 222.22

ANSWER
=======

CREATE FUNCTION "*" (us_dollars,INT)


RETURNS us_dollars
SOURCE SYSIBM."*"(DECIMAL,INT);
Figure 484, Create sourced function

SELECT

id
,balance * 10 AS newbal
FROM
customers
ORDER BY id;

ANSWER
==========
ID NEWBAL
-- ------1 1111.10
2 2222.20

Figure 485, Do multiply - works

SELECT

id
,"*"(balance,10) AS newbal
FROM
customers
ORDER BY id;
Figure 486, Do multiply - works

ANSWER
==========
ID NEWBAL
-- ------1 1111.10
2 2222.20

Figure 487, Scalar and Table function syntax

CREATE FUNCTION Test()


RETURNS CHAR(5)
RETURN 'abcde';
Figure 488, Function returns nullable, but never null, value

CREATE FUNCTION returns_zero() RETURNS SMALLINT RETURN 0;


SELECT

id
AS id
,returns_zero() AS zz
FROM
staff
WHERE
id = 10;
Figure 489, Simple function usage

ANSWER
======
ID ZZ
-- -10 0

CREATE FUNCTION calc(inval SMALLINT) RETURNS INT RETURN inval * 10;


CREATE FUNCTION calc(inval INTEGER) RETURNS INT RETURN inval * 5;
SELECT

id
AS id
,calc(SMALLINT(id)) AS c1
,calc(INTEGER (id)) AS C2
FROM
staff
WHERE
id < 30
ORDER BY id;
DROP FUNCTION calc(SMALLINT);
DROP FUNCTION calc(INTEGER);
Figure 490, Two functions with same name

ANSWER
==========
ID C1 C2
-- --- --10 100 50
20 200 100

CREATE FUNCTION rnd(inval INT)


RETURNS SMALLINT
NOT DETERMINISTIC
RETURN RAND() * 50;
SELECT

id
AS id
,rnd(1) AS RND
FROM
staff
WHERE
id < 40
ORDER BY id;
Figure 491, Not deterministic function

CREATE FUNCTION get_sal(inval SMALLINT)


RETURNS DECIMAL(7,2)
RETURN SELECT salary
FROM
staff
WHERE id = inval;
SELECT

id
AS id
,get_sal(id) AS salary
FROM
staff
WHERE
id < 40
ORDER BY id;
Figure 492, Function using query

ANSWER
======
ID RND
-- --10 37
20
8
30 42

ANSWER
===========
ID SALARY
-- -------10 18357.50
20 18171.25
30 17506.75

CREATE FUNCTION max_sal(inval SMALLINT)


RETURNS DECIMAL(7,2)
RETURN WITH
ddd (max_sal) AS
(SELECT MAX(S2.salary)
FROM
staff S1
,staff S2
WHERE
S1.id
= inval
AND
S1.dept = s2.dept)
,yyy (max_sal) AS
(SELECT MAX(S2.salary)
FROM
staff S1
,staff S2
WHERE
S1.id
= inval
AND
S1.years = s2.years)
SELECT CASE
WHEN ddd.max_sal > yyy.max_sal
THEN ddd.max_sal
ELSE yyy.max_sal
END
FROM
ddd, yyy;
SELECT

id
,salary

AS id
AS SAL1

ANSWER
====================
ID SAL1
SAL2

,max_sal(id) AS SAL2
-FROM
staff
10
WHERE
id < 40
20
ORDER BY id;
30
Figure 493, Function using common table expression

-------18357.50
18171.25
17506.75

-------22959.20
18357.50
19260.25

CREATE FUNCTION remove_e(instr VARCHAR(50))


RETURNS VARCHAR(50)
RETURN replace(instr,'e','');
UPDATE
staff
SET
name = remove_e(name)
WHERE
id < 40;
Figure 494, Function used in update

--#SET DELIMITER !

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

CREATE FUNCTION reverse(instr VARCHAR(50))


RETURNS VARCHAR(50)
BEGIN ATOMIC
DECLARE outstr VARCHAR(50) DEFAULT '';
DECLARE curbyte SMALLINT
DEFAULT 0;
SET curbyte = LENGTH(RTRIM(instr));
WHILE curbyte >= 1 DO
SET outstr = outstr || SUBSTR(instr,curbyte,1);
SET curbyte = curbyte - 1;
END WHILE;
RETURN outstr;
END!
ANSWER
SELECT
id
AS id
====================
,name
AS name1
ID NAME1
NAME2
,reverse(name) AS name2
-- -------- ------FROM
staff
10 Sanders srednaS
WHERE
id < 40
20 Pernal
lanreP
ORDER BY id!
30 Marenghi ihgneraM
Figure 495, Function using compound SQL

--#SET DELIMITER !
CREATE FUNCTION check_len(instr VARCHAR(50))
RETURNS SMALLINT
BEGIN ATOMIC
IF instr IS NULL THEN
RETURN NULL;
END IF;
IF length(instr) < 6 THEN
SIGNAL SQLSTATE '75001'

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

SET MESSAGE_TEXT = 'Input string is < 6';


ELSEIF length(instr) < 7 THEN
RETURN -1;
END IF;
RETURN length(instr);
END!
SELECT

id
AS id
,name
AS name1
,check_len(name) AS name2
FROM
staff
WHERE
id < 60
ORDER BY id!
Figure 496, Function with error checking logic

CREATE FUNCTION get_staff()


RETURNS TABLE (ID
SMALLINT
,name
VARCHAR(9)
,YR
SMALLINT)
RETURN SELECT id
,name
,years
FROM
staff;
SELECT
*
FROM
TABLE(get_staff()) AS s
WHERE
id < 40
ORDER BY id;
Figure 497, Simple table function

ANSWER
=================
ID NAME1
NAME2
-- -------- ----10 Sanders
7
20 Pernal
-1
30 Marenghi
8
40 O'Brien
7

ANSWER
==============
ID NAME
YR
-- -------- -10 Sanders
7
20 Pernal
8
30 Marenghi 5

Figure 498, Table function usage - syntax

CREATE FUNCTION get_st(inval INTEGER)


RETURNS TABLE (id
SMALLINT
,name
VARCHAR(9)
,yr
SMALLINT)
RETURN SELECT id
,name
,years
FROM
staff
WHERE
id = inval;
SELECT
*
FROM
TABLE(get_st(30)) AS sss (id, nnn, yy);
Figure 499, Table function with parameters

ANSWER
==============
ID NNN
YY
-- -------- -30 Marenghi 5

CREATE FUNCTION make_data()


RETURNS TABLE (KY
SMALLINT
,DAT CHAR(5))
RETURN WITH temp1 (k#) AS (VALUES (1),(2),(3))
SELECT k#
,DIGITS(SMALLINT(k#))
FROM
temp1;
SELECT
*
FROM
TABLE(make_data()) AS ttt;
Figure 500, Table function that creates data

ANSWER
========
KY DAT
-- ----1 00001
2 00002
3 00003

CREATE FUNCTION staff_list(lo_key INTEGER


IMPORTANT
,lo_sal INTEGER)
============
RETURNS TABLE (id
SMALLINT
This example
,salary DECIMAL(7,2)
uses an "!"
,max_sal DECIMAL(7,2)
as the stmt
,id_max SMALLINT)
delimiter.
LANGUAGE SQL
READS SQL DATA
EXTERNAL ACTION
DETERMINISTIC
BEGIN ATOMIC
DECLARE hold_sal DECIMAL(7,2) DEFAULT 0;
DECLARE hold_key SMALLINT;
IF lo_sal < 0 THEN
SIGNAL SQLSTATE '75001'
SET MESSAGE_TEXT = 'Salary too low';
END IF;
FOR get_max AS
SELECT id
AS in_key
,salary As in_sal
FROM
staff
WHERE id >= lo_key
DO
IF in_sal > hold_sal THEN
SET hold_sal = in_sal;
SET hold_key = in_key;
END IF;
END FOR;
RETURN
SELECT id
,salary
,hold_sal
,hold_key
ANSWER
FROM
staff
============================
WHERE id >= lo_key;
ID SALARY
MAX_SAL ID_MAX
END!
--- -------- -------- -----70 16502.83 22959.20
160
SELECT
*
80 13504.60 22959.20
160
FROM
TABLE(staff_list(66,1)) AS ttt
90 18001.75 22959.20
160
WHERE
id < 111
100 18352.80 22959.20
160
ORDER BY id!
110 12508.20 22959.20
160
Figure 501, Table function with compound SQL

CREATE FUNCTION julian_out(inval DATE)


RETURNS CHAR(7)
RETURN RTRIM(CHAR(YEAR(inval)))
|| SUBSTR(DIGITS(DAYOFYEAR(inval)),8);
SELECT

empno
,CHAR(hiredate,ISO)
AS h_date
,JULIAN_OUT(hiredate) AS j_date
FROM
employee
WHERE
empno < '000050'
ORDER BY empno;
Figure 502, Convert Date into Julian Date

CREATE FUNCTION julian_in(inval


RETURNS DATE
RETURN DATE('0001-01-01')
+ (INT(SUBSTR(inval,1,4))
+ (INT(SUBSTR(inval,5,3))
Figure 503, Convert Julian Date

SELECT
FROM
WHERE

ANSWER
=========================
EMPNO H_DATE
J_DATE
------ ---------- ------000010 1965-01-01 1965001
000020 1973-10-10 1973283
000030 1975-04-05 1975095

CHAR(7))
- 1) YEARS
- 1) DAYS;
into Date

empno
,hiredate
employee
YEAR(hiredate) = YEAR(CURRENT DATE) - 1;

Figure 504, Select rows where hire-date = prior year

CREATE FUNCTION year_month(inval DATE)


RETURNS INTEGER
RETURN (YEAR(inval) * 12) + MONTH(inval);
Figure 505, Create year-month function

SELECT

empno
,hiredate
FROM
employee
WHERE
YEAR_MONTH(hiredate) = YEAR_MONTH(CURRENT DATE) - 1;
Figure 506, Select rows where hire-date = prior month

CREATE FUNCTION sunday_week(inval DATE)


RETURNS INTEGER
RETURN DAYS(inval) / 7;
Figure 507, Create week-number function

CREATE FUNCTION monday_week(inval DATE)


RETURNS INTEGER
RETURN (DAYS(inval) - 1) / 7;
Figure 508, Create week-number function

WITH
ANSWER
temp1 (num,dt) AS
==================================
(VALUES (1
DATE
DAY WK IS SUN_WK MON_WK
,DATE('2004-12-29'))
---------- --- -- -- ------ -----UNION ALL
2004-12-29 Wed 53 53 104563 104563
SELECT num + 1
2004-12-30 Thu 53 53 104563 104563
,dt + 1 DAY
2004-12-31 Fri 53 53 104563 104563
FROM
temp1
2005-01-01 Sat 1 53 104563 104563
WHERE
num < 15
2005-01-02 Sun 2 53 104564 104563
),
2005-01-03 Mon 2 1 104564 104564
temp2 (dt,dy) AS
2005-01-04 Tue 2 1 104564 104564
(SELECT dt
2005-01-05 Wed 2 1 104564 104564
,SUBSTR(DAYNAME(dt),1,3) 2005-01-06 Thu 2 1 104564 104564
FROM
temp1
2005-01-07 Fri 2 1 104564 104564
)
2005-01-08 Sat 2 1 104564 104564
SELECT
CHAR(dt,ISO)
AS date
2005-01-09 Sun 3 1 104565 104564
,dy
AS day
2005-01-10 Mon 3 2 104565 104565
,WEEK(dt)
AS wk
2005-01-11 Tue 3 2 104565 104565
,WEEK_ISO(dt)
AS is
2005-01-12 Wed 3 2 104565 104565
,sunday_week(dt) AS sun_wk
,monday_week(dt) AS mon_wk
FROM
temp2
ORDER BY 1;
Figure 509, Use week-number functions

CREATE FUNCTION NumList(max_num INTEGER)


RETURNS TABLE(num INTEGER)
LANGUAGE SQL
RETURN
WITH temp1 (num) AS
(VALUES (0)
UNION ALL
SELECT num + 1

FROM
WHERE

temp1
num < max_num

)
SELECT num
FROM
temp1;
Figure 510, Create num-list function

SELECT
FROM

*
TABLE(NumList(-1)) AS xxx;

ANSWERS
=======
0

SELECT
FROM

*
TABLE(NumList(+0)) AS xxx;

SELECT
FROM

*
TABLE(NumList(+3)) AS xxx;

0
1
2
3

SELECT
*
FROM
TABLE(NumList(CAST(NULL AS INTEGER))) AS xxx;
Figure 511, Using num-list function

SELECT

actno
ANSWER
,emstdate
=================================
,emendate
ACTNO EMSTDATE
EMENDATE
#DAYS
,DAYS(emendate) ----- ---------- ---------- ----DAYS(emstdate) AS #days
70 1982-06-15 1982-07-01
16
FROM
emp_act act
80 1982-03-01 1982-04-15
45
WHERE
empno
= '000260'
AND
projno = 'AD3113'
AND
actno
< 100
AND
emptime = 0.5
ORDER BY actno;
Figure 512, Select activity start & end date

SELECT

FROM

actno
,#days
,num
,emstdate + num DAYS AS new_date
(SELECT
actno
,emstdate
,emendate
,DAYS(emendate) DAYS(emstdate) AS #days
FROM
emp_act act
WHERE
empno
= '000260'
AND
projno = 'AD3113'

ANSWER
==========================
ACTNO #DAYS NUM NEW_DATE
----- ----- --- ---------70
16
0 1982-06-15
70
16
1 1982-06-16
70
16
2 1982-06-17
70
16
3 1982-06-18
70
16
4 1982-06-19
70
16
5 1982-06-20
70
16
6 1982-06-21
70
16
7 1982-06-22

AND
actno
< 100
70
16
8 1982-06-23
AND
emptime = 0.5
70
16
9 1982-06-24
)AS aaa
70
16 10 1982-06-25
,TABLE(NumList(#days)) AS ttt
etc...
ORDER BY actno
,num;
Figure 513, Generate one row per date between start & end dates (1 of 2)

SELECT

actno
,#days
,num
ACTNO #DAYS NUM NEW_DATE
,emstdate + num DAYS AS new_date
----- ----- --- ---------FROM
(SELECT
actno
70
16
0 1982-06-15
,emstdate
70
16
1 1982-06-16
,emendate
70
16
2 1982-06-17
,DAYS(emendate) 70
16
3 1982-06-18
DAYS(emstdate) AS #days
70
16
4 1982-06-19
FROM
emp_act act
70
16
5 1982-06-20
WHERE
empno
= '000260'
70
16
6 1982-06-21
AND
projno = 'AD3113'
70
16
7 1982-06-22
AND
actno
< 100
70
16
8 1982-06-23
AND
emptime = 0.5
70
16
9 1982-06-24
)AS aaa
70
16 10 1982-06-25
LEFT OUTER JOIN
etc...
TABLE(NumList(#days)) AS ttt
ON
1 = 1
ORDER BY actno
,num;
Figure 514, Generate one row per date between start & end dates (2 of 2)

CREATE FUNCTION ISCHAR (inval VARCHAR(250))


RETURNS SMALLINT
LANGUAGE SQL
RETURN
CASE
WHEN TRANSLATE(UPPER(inval),' ','ABCDEFGHIJKLMNOPQRSTUVWXYZ') = ' '
THEN 1
ELSE 0
END;
Figure 515, Check if input value is character

CREATE FUNCTION ISNUM (inval VARCHAR(250))


RETURNS SMALLINT
LANGUAGE SQL
RETURN
CASE
WHEN TRANSLATE(inval,' ','01234567890') = ' '
THEN 1

ELSE 0
END;
Figure 516, Check if input value is numeric

WITH temp (indata) AS


(VALUES ('ABC'),('123'),('3.4')
,('-44'),('A1 '),('
'))
SELECT indata
AS indata
,ISCHAR(indata) AS c
,ISNUM(indata) AS n
FROM
temp;

ANSWER
==========
INDATA C N
------ - ABC
1 0
123
0 1
3.4
0 0
-44
0 0
A1
0 0
1 1

Figure 517, Example of functions in use

CREATE FUNCTION ISNUM2 (inval VARCHAR(255))


RETURNS CHAR(4)
LANGUAGE SQL
RETURN
CASE
WHEN inval
= ' '
THEN '
'
WHEN LOCATE(' ',RTRIM(LTRIM(inval)))
> 0
THEN '
'
WHEN TRANSLATE(inval,' ','01234567890')
= inval
THEN '
'
WHEN TRANSLATE(inval,' ','01234567890')
= ' '
THEN 'INT '
WHEN TRANSLATE(inval,' ','+01234567890')
= ' '
AND LOCATE('+',LTRIM(inval))
= 1
AND LENGTH(REPLACE(inval,'+',''))
= LENGTH(inval)
THEN 'INT+'
WHEN TRANSLATE(inval,' ','-01234567890')
= ' '
AND LOCATE('-',LTRIM(inval))
= 1
AND LENGTH(REPLACE(inval,'-',''))
= LENGTH(inval)
THEN 'INT-'
WHEN TRANSLATE(inval,' ','.01234567890')
= ' '
AND LENGTH(REPLACE(inval,'.',''))
= LENGTH(inval)
THEN 'DEC '
WHEN TRANSLATE(inval,' ','+.01234567890') = ' '
AND LOCATE('+',LTRIM(inval))
= 1
AND LENGTH(REPLACE(inval,'+',''))
= LENGTH(inval)
AND LENGTH(REPLACE(inval,'.',''))
= LENGTH(inval)
THEN 'DEC+'
Figure 518, Check if input value is numeric - part 1 of 2

WHEN

TRANSLATE(inval,' ','-.01234567890')

= ' '

- 1

- 1
- 1

- 1
- 1

AND LOCATE('-',LTRIM(inval))
= 1
AND LENGTH(REPLACE(inval,'-',''))
= LENGTH(inval) - 1
AND LENGTH(REPLACE(inval,'.',''))
= LENGTH(inval) - 1
THEN 'DEC-'
ELSE '
'
END;
Figure 519, Check if input value is numeric - part 2 of 2

WITH temp (indata) AS


(VALUES ('ABC'),('123'),('3.4')
,('-44'),('+11'),('-1-')
,('12+'),('+.1'),('-0.')
,('
'),('1 1'),(' . '))
SELECT indata
AS indata
,ISNUM2(indata) AS type
,CASE
WHEN ISNUM2(indata) <> ''
THEN DEC(indata,5,2)
ELSE NULL
END
AS number
FROM
temp;

Figure 520, Example of function in use

ANSWER
==================
INDATA TYPE NUMBER
------ ---- -----ABC
123
INT 123.00
3.4
DEC
3.40
-44
INT- -44.00
+11
INT+ 11.00
-112+
+.1
DEC+
0.10
-0.
DEC0.00
1 1
.
-

Figure 521, ORDER BY syntax

CREATE VIEW SEQ_DATA(col1,col2)


AS VALUES ('ab','xy')
,('AB','xy')
,('ac','XY')
,('AB','XY')
,('Ab','12');
Figure 522, ORDER BY sample data definition

SELECT

col1
,col2
FROM
seq_data
ORDER BY col1 ASC
,col2;

ANSWER
=========
COL1 COL2
---- ---ab
xy
ac
XY
Ab
12

SEQ_DATA
+---------+
|COL1|COL2|
|----+----|
|ab |xy |
|AB |xy |
|ac |XY |

AB
AB
Figure 523, Simple ORDER BY

SELECT

col1
,col2
FROM
seq_data
ORDER BY TRANSLATE(col1) ASC
,TRANSLATE(col2) ASC

Figure 524, Case insensitive ORDER BY

SELECT
col2
FROM
seq_data
ORDER BY col1
,col2;

Figure 525, ORDER BY on not-displayed column

SELECT

col1
,col2
FROM
seq_data
ORDER BY SUBSTR(col1,2) DESC
,col2
,1;

Figure 526, ORDER BY second byte of first column

SELECT

FROM

col1
,HEX(col1) AS hex1
,col2
,HEX(col2) AS hex2
seq_data

xy
XY

|AB |XY |
|Ab |12 |
+---------+

ANSWER
=========
COL1 COL2
---- ---Ab
12
ab
xy
AB
XY
AB
xy
ac
XY

ANSWER
======
COL2
---xy
XY
12
xy
XY

ANSWER
=========
COL1 COL2
---- ---ac
XY
AB
xy
AB
XY
Ab
12
ab
xy

ANSWER
===================
COL1 HEX1 COL2 HEX2
---- ---- ---- ---AB
4142 XY
5859

ORDER BY HEX(col1)
,HEX(col2)

AB
Ab
ab
ac

4142
4162
6162
6163

xy
12
xy
XY

7879
3132
7879
5859

Figure 527, ORDER BY in bit-data sequence

SELECT
FROM

col1
(SELECT
FROM
ORDER BY
) AS xxx
ORDER BY ORDER OF

col1
seq_data
col2
xxx;

Figure 528, ORDER BY nested ORDER BY

SELECT
FROM

*
(SELECT
FROM

*
(SELECT
*
FROM
seq_data
ORDER BY col2
)AS xxx
ORDER BY ORDER OF xxx
,SUBSTR(col1,2)
)AS yyy
ORDER BY ORDER OF yyy
,col1;
Figure 529, Multiple nested ORDER BY statements

SELECT

empno
,projno AS prj
,actno AS act
,ROW_NUMBER() OVER() AS r#
FROM
FINAL TABLE
(INSERT INTO emp_act (empno, projno, actno)
VALUES ('400000','ZZZ',999)
,('400000','VVV',111))
ORDER BY INPUT SEQUENCE;
Figure 530, ORDER BY insert input sequence

Figure 531, GROUP BY syntax

ANSWER
======
COL1
---Ab
ab
AB
ac
AB

SEQ_DATA
+---------+
|COL1|COL2|
|----+----|
|ab |xy |
|AB |xy |
|ac |XY |
|AB |XY |
|Ab |12 |
+---------+

ANSWER
=========
COL1 COL2
---- ---Ab
12
ab
xy
AB
xy
AB
XY
ac
XY

ANSWER
=================
EMPNO PRJ ACT R#
------ --- --- -400000 ZZZ 999 1
400000 VVV 111 2

GROUP BY division, department, team


GROUP BY division, department
GROUP BY division
GROUP BY division, team
GROUP BY department, team
GROUP BY department
GROUP BY team
GROUP BY ()
<= grand-total
Figure 532, Possible groupings

GROUP
UNION
GROUP
UNION
GROUP
UNION
GROUP

BY division, department, team


ALL
BY division, department
ALL
BY division
ALL
BY ()

GROUP BY GROUPING SETS ((division, department, team)


,(division, department)
,(division)
,())
GROUP BY ROLLUP (division, department, team)
Figure 533, Three ways to write the same GROUP BY

CREATE VIEW employee_view AS


SELECT
SUBSTR(workdept,1,1)
,workdept
,sex
,INTEGER(salary)
FROM
employee
WHERE
workdept < 'D20';
COMMIT;

SELECT
*
FROM
employee_view
ORDER BY 1,2,3,4;

AS
AS
AS
AS

d1
dept
sex
salary

ANSWER
==================
D1 DEPT SEX SALARY
-- ---- --- -----A A00 F
52750
A A00 M
29250
A A00 M
46500
B B01 M
41250
C C01 F
23800
C C01 F
28420
C C01 F
38250
D D11 F
21340
D D11 F
22250
D D11 F
29840
D D11 M
18270
D D11 M
20450
D D11 M
24680
D D11 M
25280
D D11 M
27740

Figure 534, GROUP BY Sample Data

d1, dept, sex


,SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
FROM
employee_view
WHERE
dept <> 'ABC'
GROUP BY d1, dept, sex
HAVING
dept
> 'A0'
AND (SUM(salary) > 100
OR
MIN(salary) > 10
OR
COUNT(*)
<> 22)
ORDER BY d1, dept, sex;
Figure 535, Simple GROUP BY

D11

32250

SELECT

ANSWER
========================
D1 DEPT SEX SALARY #ROWS
-- ---- --- ------ ----A A00 F
52750
1
A A00 M
75750
2
B B01 M
41250
1
C C01 F
90470
3
D D11 F
73430
3
D D11 M
148670
6

SELECT

ANSWER
================
SEX SALARY #ROWS
--- ------ ----F
52750
1
F
90470
3
F
73430
3
M
75750
2
M
41250
1
M
148670
6

sex
,SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
FROM
employee_view
WHERE
sex IN ('F','M')
GROUP BY dept
,sex
ORDER BY sex;
Figure 536, GROUP BY on non-displayed field

SELECT

SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
FROM
employee_view
WHERE
d1 <> 'X'
GROUP BY SUBSTR(dept,3,1)
HAVING
COUNT(*) <> 99;
Figure 537, GROUP BY on derived field, not shown

ANSWER
============
SALARY #ROWS
------ ----128500
3
353820
13

SELECT

ANSWER
==================
WPART SALARY #ROWS
----- ------ ----1
353820
13
0
128500
3

SUBSTR(dept,3,1)
AS wpart
,SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
FROM
employee_view
GROUP BY SUBSTR(dept,3,1)
ORDER BY wpart DESC;
Figure 538, GROUP BY on derived field, shown

GROUP BY GROUPING SETS ((A,B,C))

is equivalent to

GROUP BY A
,B
,C

GROUP BY GROUPING SETS (A,B,C)

is equivalent to

GROUP
UNION
GROUP
UNION
GROUP

GROUP BY GROUPING SETS (A,(B,C))

is equivalent to

GROUP BY A
UNION ALL
GROUP BY B
,BY C

BY A
ALL
BY B
ALL
BY C

Figure 539, GROUPING SETS in parenthesis vs. not

GROUP BY GROUPING SETS (A)


,GROUPING SETS (B)
,GROUPING SETS (C)

is equivalent to

GROUP BY A
,B
,C

GROUP BY GROUPING SETS (A)


,GROUPING SETS ((B,C))

is equivalent to

GROUP BY A
,B
,C

GROUP BY GROUPING SETS (A)


,GROUPING SETS (B,C)

is equivalent to

GROUP BY A
,B
UNION ALL
GROUP BY A
,C

Figure 540, Multiple GROUPING SETS

GROUP BY A
,GROUPING SETS ((B,C))

is equivalent to

GROUP BY A
,B
,C
Figure 541, Simple GROUP BY expression and GROUPING SETS combined

GROUP BY A
,B
,GROUPING SETS ((B,C))

is equivalent to

GROUP BY A
,B
,C

GROUP BY A
,B

is equivalent to

GROUP BY A
,B

,GROUPING SETS (B,C)

,C
UNION ALL
GROUP BY A
,B

GROUP BY A
,B
,C
,GROUPING SETS (B,C)

is equivalent to

GROUP BY A
,B
,C
UNION ALL
GROUP BY A
,B
,C
Figure 542, Mixing simple GROUP BY expressions and GROUPING SETS

GROUP BY GROUPING SETS ((A,B,C)


,(A,B)
,(C))

is equivalent to

GROUP BY A
,B
,C
UNION ALL
GROUP BY A
,B
UNION ALL
GROUP BY C

GROUP BY GROUPING SETS ((A)


,(B,C)
,(A)
,A
,((C)))

is equivalent to

GROUP BY A
UNION ALL
GROUP BY B
,C
UNION ALL
GROUP BY A
UNION ALL
GROUP BY A
UNION ALL
GROUP BY C

Figure 543, GROUPING SETS with multiple components

GROUP BY GROUPING SETS ((A,B,C)


,(A,B)
,(A)
,())

GROUP BY A
,B
,C
UNION ALL
GROUP BY A
,B
is equivalent to
UNION ALL
GROUP BY A
UNION ALL
ROLLUP(A,B,C)
grand-totl
Figure 544, GROUPING SET with multiple components, using grand-total

GROUP BY GROUPING SETS ((A,B,C)

is equivalent to

is equivalent to

GROUP BY A

,(A,B)
,(A,C)
,(B,C)
,(A)
,(B)
,(C)
,())

,B
,C
UNION ALL
GROUP BY A
,B
UNION ALL
GROUP BY A
,C
UNION ALL
GROUP BY B
is equivalent to
,C
UNION ALL
GROUP BY A
UNION ALL
CUBE(A,B,C)
GROUP BY B
UNION ALL
GROUP BY C
UNION ALL
grand-totl
Figure 545, GROUPING SET with multiple components, using grand-total

SELECT

d1
ANSWER
,dept
==============================
,sex
D1 DEPT SEX
SAL #R DF WF SF
,SUM(salary)
AS sal
-- ---- --- ------ -- -- -- -,SMALLINT(COUNT(*)) AS #r
A A00 F
52750 1 0 0 0
,GROUPING(d1)
AS f1
A A00 M
75750 2 0 0 0
,GROUPING(dept)
AS fd
B B01 M
41250 1 0 0 0
,GROUPING(sex)
AS fs
C C01 F
90470 3 0 0 0
FROM
employee_view
D D11 F
73430 3 0 0 0
GROUP BY GROUPING SETS (d1)
D D11 M
148670 6 0 0 0
,GROUPING SETS ((dept,sex))
ORDER BY d1
,dept
,sex;
Figure 546, Multiple GROUPING SETS, making one GROUP BY

SELECT

d1
ANSWER
,dept
==============================
,sex
D1 DEPT SEX
SAL #R F1 FD FS
,SUM(salary)
AS sal
-- ---- --- ------ -- -- -- -,SMALLINT(COUNT(*)) AS #r
A
A00 128500 3 0 0 1
,GROUPING(d1)
AS f1
A
F
52750 1 0 1 0
,GROUPING(dept)
AS fd
A
M
75750 2 0 1 0
,GROUPING(sex)
AS fs
B
B01 41250 1 0 0 1
FROM
employee_view
B
M
41250 1 0 1 0
GROUP BY GROUPING SETS (d1)
C
C01 90470 3 0 0 1
,GROUPING SETS (dept,sex)
C
F
90470 3 0 1 0
ORDER BY d1
D
D11 222100 9 0 0 1
,dept
D
F
73430 3 0 1 0
,sex;
D
M
148670 6 0 1 0
Figure 547, Multiple GROUPING SETS, making two GROUP BY results

SELECT

d1
ANSWER
,dept
==============================
,sex
D1 DEPT SEX SAL
#R F1 FD FS
,SUM(salary)
AS sal
-----------------------------,SMALLINT(COUNT(*)) AS #r
A A00 F
52750 1 0 0 0
,GROUPING(d1)
AS f1
A A00 M
75750 2 0 0 0
,GROUPING(dept)
AS fd
B B01 M
41250 1 0 0 0
,GROUPING(sex)
AS fs
C C01 F
90470 3 0 0 0
FROM
employee_view
D D11 F
73430 3 0 0 0
GROUP BY d1
D D11 M
148670 6 0 0 0
,dept
,GROUPING SETS ((dept,sex))
ORDER BY d1
,dept
,sex;
Figure 548, Repeated field essentially ignored

SELECT

d1
ANSWER
,dept
==============================
,sex
D1 DEPT SEX SAL
#R F1 FD FS
,SUM(salary)
AS sal
-----------------------------,SMALLINT(COUNT(*)) AS #r
A A00 F
52750 1 0 0 0
,GROUPING(d1)
AS f1
A A00 M
75750 2 0 0 0
,GROUPING(dept)
AS fd
A A00 128500 3 0 0 1
,GROUPING(sex)
AS fs
B B01 M
41250 1 0 0 0
FROM
employee_view
B B01 41250 1 0 0 1
GROUP BY d1
C C01 F
90470 3 0 0 0
,DEPT
C C01 90470 3 0 0 1
,GROUPING SETS (dept,sex)
D D11 F
73430 3 0 0 0
ORDER BY d1
D D11 M
148670 6 0 0 0
,dept
D D11 222100 9 0 0 1
,sex;
Figure 549, Repeated field impacts query result

GROUP BY d1
,dept
,GROUPING SETS ((dept,sex))

is equivalent to

GROUP BY d1
,dept
sex

GROUP BY d1
,dept
,GROUPING SETS (dept,sex)

is equivalent to

GROUP BY d1
,dept
sex
UNION ALL
GROUP BY d1
,dept
,dept

Figure 550, Repeated field impacts query result

GROUP BY ROLLUP(A,B,C)

===>

GROUP BY GROUPING SETS((A,B,C)


,(A,B)
,(A)
,())

GROUP BY ROLLUP(C,B)

===>

GROUP BY GROUPING SETS((C,B)


,(C)
,())

GROUP BY ROLLUP(A)

===>

GROUP BY GROUPING SETS((A)


,())

Figure 551, ROLLUP vs. GROUPING SETS

GROUP BY ROLLUP(A,(B,C))

===>

GROUP BY GROUPING SETS((A,B,C)


,(A)
,())

Figure 552, ROLLUP vs. GROUPING SETS

GROUP BY ROLLUP(A)
,ROLLUP(B,C)

===>

Figure 553, ROLLUP vs. GROUPING SETS

ROLLUP(A)

GROUPING SETS((A)
,())

GROUP BY GROUPING SETS((A,B,C)


,(A,B)
,(A)
,(B,C)
,(B)
,())

ROLLUP(B,C)

GROUPING SETS((B,C)
,(B)
())
Figure 554, Multiplying GROUPING SETS

SELECT

dept
,SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
,GROUPING(dept)
AS fd

=
=

GROUPING SETS((A,B,C)
,(A,B)
,(A)
,(B,C)
,(B)
,(())

ANSWER
====================
DEPT SALARY #ROWS FD
---- ------ ----- --

FROM
employee_view
GROUP BY dept
ORDER BY dept;

A00
B01
C01
D11

128500
41250
90470
222100

3
1
3
9

0
0
0
0

Figure 555, Simple GROUP BY

SELECT

dept
,SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
,GROUPING(dept)
AS FD
FROM
employee_view
GROUP BY ROLLUP(dept)
ORDER BY dept;

ANSWER
====================
DEPT SALARY #ROWS FD
---- ------ ----- -A00 128500
3 0
B01
41250
1 0
C01
90470
3 0
D11 222100
9 0
482320
16 1

Figure 556, GROUP BY with ROLLUP

SELECT

dept
,SUM(salary)
AS salary
,SMALLINT(COUNT(*))
AS #rows
,GROUPING(dept)
AS fd
FROM
employee_view
GROUP BY dept
UNION ALL
SELECT
CAST(NULL AS CHAR(3)) AS dept
,SUM(salary)
AS salary
,SMALLINT(COUNT(*))
AS #rows
,CAST(1 AS INTEGER)
AS fd
FROM
employee_view
ORDER BY dept;
Figure 557, ROLLUP done the old-fashioned way

SELECT

dept
,SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
,GROUPING(dept)
AS fd
FROM
employee_view
GROUP BY dept
,ROLLUP(dept)
ORDER BY dept;

ANSWER
====================
DEPT SALARY #ROWS FD
---- ------ ----- -A00 128500
3 0
B01
41250
1 0
C01
90470
3 0
D11 222100
9 0
482320
16 1

ANSWER
====================
DEPT SALARY #ROWS FD
---- ------ ----- -A00 128500
3 0
A00 128500
3 0
B01
41250
1 0
B01
41250
1 0
C01
90470
3 0
C01
90470
3 0
D11 222100
9 0
D11 222100
9 0
Figure 558, Repeating a field in GROUP BY and ROLLUP (error)

GROUP BY dept
=> GROUP BY dept
=> GROUP BY dept
,ROLLUP(dept)
,GROUPING SETS((dept)
UNION ALL
,())
GROUP BY dept
,()
Figure 559, Repeating a field, explanation

SELECT

dept
,sex
,SUM(salary)
,SMALLINT(COUNT(*))
,GROUPING(dept)
,GROUPING(sex)
FROM
employee_view
GROUP BY dept
,ROLLUP(sex)
ORDER BY dept
,sex;

ANSWER
===========================
AS salary
DEPT SEX SALARY #ROWS FD FS
AS #rows
---- --- ------ ----- -- -AS fd
A00 F
52750
1 0 0
AS fs
A00 M
75750
2 0 0
A00 128500
3 0 1
B01 M
41250
1 0 0
B01 41250
1 0 1
C01 F
90470
3 0 0
C01 90470
3 0 1
D11 F
73430
3 0 0
D11 M
148670
6 0 0
D11 222100
9 0 1
Figure 560, GROUP BY on 1st field, ROLLUP on 2nd

SELECT

dept
,sex
,SUM(salary)
,SMALLINT(COUNT(*))
,GROUPING(dept)
,GROUPING(sex)
FROM
employee_view
GROUP BY ROLLUP(dept
,sex)
ORDER BY dept
,sex;

AS
AS
AS
AS

salary
#rows
fd
fs

ANSWER
===========================
DEPT SEX SALARY #ROWS FD FS
---- --- ------ ----- -- -A00 F
52750
1 0 0
A00 M
75750
2 0 0
A00 128500
3 0 1
B01 M
41250
1 0 0
B01 41250
1 0 1
C01 F
90470
3 0 0
C01 90470
3 0 1
D11 F
73430
3 0 0
D11 M
148670
6 0 0
D11 222100
9 0 1
482320
16 1 1

Figure 561, ROLLUP on DEPT, then SEX

SELECT

sex
,dept
,SUM(salary)
,SMALLINT(COUNT(*))
,GROUPING(dept)
,GROUPING(sex)

AS
AS
AS
AS

salary
#rows
fd
fs

ANSWER
===========================
SEX DEPT SALARY #ROWS FD FS
--- ---- ------ ----- -- -F
A00
52750
1 0 0
F
C01
90470
3 0 0

FROM
employee_view
GROUP BY ROLLUP(sex
,dept)
ORDER BY sex
,dept;
Figure 562, ROLLUP on SEX, then DEPT

SELECT

sex
,dept
,SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
,GROUPING(dept)
AS fd
,GROUPING(sex)
AS fs
FROM
employee_view
GROUP BY GROUPING SETS ((sex, dept)
,(sex)
,())
ORDER BY sex
,dept;
Figure 563, ROLLUP on SEX, then DEPT

SELECT

sex
,dept
,SUM(salary)
,SMALLINT(COUNT(*))
,GROUPING(dept)
,GROUPING(sex)
FROM
employee_view
GROUP BY ROLLUP(sex)
,ROLLUP(dept)
ORDER BY sex
,dept;

AS
AS
AS
AS

salary
#rows
fd
fs

Figure 564, Two independent ROLLUPS

SELECT

dept
,sex
,SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
,GROUPING(dept)
AS fd

F
F
M
M
M
M
-

D11
A00
B01
D11
-

73430
216650
75750
41250
148670
265670
482320

3
7
2
1
6
9
16

0
1
0
0
0
1
1

0
0
0
0
0
0
1

ANSWER
===========================
SEX DEPT SALARY #ROWS FD FS
--- ---- ------ ----- -- -F
A00
52750
1 0 0
F
C01
90470
3 0 0
F
D11
73430
3 0 0
F
216650
7 1 0
M
A00
75750
2 0 0
M
B01
41250
1 0 0
M
D11 148670
6 0 0
M
265670
9 1 0
482320
16 1 1

ANSWER
===========================
SEX DEPT SALARY #ROWS FD FS
--- ---- ------ ----- -- -F
A00
52750
1 0 0
F
C01
90470
3 0 0
F
D11
73430
3 0 0
F
216650
7 1 0
M
A00
75750
2 0 0
M
B01
41250
1 0 0
M
D11 148670
6 0 0
M
265670
9 1 0
A00 128500
3 0 1
B01
41250
1 0 1
C01
90470
3 0 1
D11 222100
9 0 1
482320
16 1 1

ANSWER
===========================
DEPT SEX SALARY #ROWS FD FS
---- --- ------ ----- -- -A00 F
52750
1 0 0

,GROUPING(sex)
AS fs
FROM
employee_view
GROUP BY ROLLUP((dept,sex))
ORDER BY dept
,sex;

A00
B01
C01
D11
D11
-

M
M
F
F
M
-

75750
41250
90470
73430
148670
482320

2
1
3
3
6
16

0
0
0
0
0
1

0
0
0
0
0
1

Figure 565, Combined-field ROLLUP

SELECT

SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
FROM
employee_view
GROUP BY ROLLUP(sex
,dept)
HAVING
GROUPING(dept) = 1
AND
GROUPING(sex) = 1
ORDER BY salary;
Figure 566, Use HAVING to get only grand-total row

ANSWER
============
SALARY #ROWS
------ ----482320
16

SELECT

ANSWER
============
SALARY #ROWS
------ ----482320
16

SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
FROM
employee_view
GROUP BY GROUPING SETS(());
Figure 567, Use GROUPING SETS to get grand-total row

SELECT

SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
FROM
employee_view
GROUP BY ();
Figure 568, Use GROUP BY to get grand-total row

SELECT
FROM

SUM(salary)
AS salary
,SMALLINT(COUNT(*)) AS #rows
employee_view;

Figure 569, Get grand-total row directly

ANSWER
============
SALARY #ROWS
------ ----482320
16

ANSWER
============
SALARY #ROWS
------ ----482320
16

GROUP BY CUBE(A,B,C)

===>

GROUP BY GROUPING SETS((A,B,C)


,(A,B)
,(A,C)
,(B,C)
,(A)
,(B)
,(C)
,())

GROUP BY CUBE(C,B)

===>

GROUP BY GROUPING SETS((C,B)


,(C)
,(B)
,())

GROUP BY CUBE(A)

===>

GROUP BY GROUPING SETS((A)


,())

Figure 570, CUBE vs. GROUPING SETS

GROUP BY CUBE(A,(B,C))

===>

GROUP BY GROUPING SETS((A,B,C)


,(B,C)
,(A)
,())

Figure 571, CUBE vs. GROUPING SETS

GROUP BY CUBE(A,B)
,CUBE(B,C)

==>

GROUPING SETS((A,B,C),(A,B),(A,B,C),(A,B)
,(A,B,C),(A,B),(A,C),(A)
,(B,C),(B),(B,C),(B)
,(B,C),(B),(C),())
Figure 572, CUBE vs. GROUPING SETS

SELECT

d1
,dept
,sex
,INT(SUM(salary))
AS
,SMALLINT(COUNT(*)) AS
,GROUPING(d1)
AS
,GROUPING(dept)
AS
,GROUPING(sex)
AS
FROM
employee_view
GROUP BY CUBE(d1, dept, sex)
ORDER BY d1
,dept
,sex;

sal
#r
f1
fd
fs

ANSWER
==============================
D1 DEPT SEX
SAL #R F1 FD FS
-- ---- --- ------ -- -- -- -A A00 F
52750 1 0 0 0
A A00 M
75750 2 0 0 0
A A00 128500 3 0 0 1
A F
52750 1 0 1 0
A M
75750 2 0 1 0
A 128500 3 0 1 1
B B01 M
41250 1 0 0 0
B B01 41250 1 0 0 1
B M
41250 1 0 1 0
B 41250 1 0 1 1
C C01 F
90470 3 0 0 0
C C01 90470 3 0 0 1
C F
90470 3 0 1 0

C
D
D
D
D
D
D
-

D11
D11
D11
A00
A00
A00
B01
B01
C01
C01
D11
D11
D11
-

F
M
F
M
F
M
M
F
F
M
F
M
-

90470 3
73430 3
148670 6
222100 9
73430 3
148670 6
222100 9
52750 1
75750 2
128500 3
41250 1
41250 1
90470 3
90470 3
73430 3
148670 6
222100 9
216650 7
265670 9
482320 16

0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
1
1
1
1
1

1
0
0
0
1
1
1
0
0
0
0
0
0
0
0
0
0
1
1
1

1
0
0
1
0
0
1
0
0
1
0
1
0
1
0
0
1
0
0
1

Figure 573, CUBE example

SELECT

d1
ANSWER
,dept
==============================
,sex
D1 DEPT SEX
SAL #R F1 FD FS
,INT(SUM(salary))
AS sal
-- ---- --- ------ -- -- -- -,SMALLINT(COUNT(*)) AS #r
A A00 F
52750 1 0 0 0
,GROUPING(d1)
AS f1
A A00 M
75750 2 0 0 0
,GROUPING(dept)
AS fd
etc... (same as prior query)
,GROUPING(sex)
AS fs
FROM
employee_view
GROUP BY GROUPING SETS ((d1, dept, sex)
,(d1,dept)
,(d1,sex)
,(dept,sex)
,(d1)
,(dept)
,(sex)
,())
ORDER BY d1
,dept
,sex;
Figure 574, CUBE expressed using multiple GROUPING SETS

SELECT

FROM

d1
,dept
,sex
,INT(SUM(salary))
,SMALLINT(COUNT(*))
,GROUPING(d1)
,GROUPING(dept)
,GROUPING(sex)
employee_VIEW

AS
AS
AS
AS
AS

sal
#r
f1
fd
fs

ANSWER
==============================
D1 DEPT SEX SAL
#R F1 FD FS
-----------------------------A A00 F
52750 1 0 0 0
A A00 M
75750 2 0 0 0
B B01 M
41250 1 0 0 0
C C01 F
90470 3 0 0 0
D D11 F
73430 3 0 0 0

GROUP BY CUBE((d1, dept, sex))


ORDER BY d1
,dept
,sex;
Figure 575, CUBE on compound fields

D
-

D11
-

M
-

148670 6
482320 16

GROUP BY CUBE((A,B,C)) => GROUP BY GROUING SETS((A,B,C) =>


,())

0
1

0
1

0
1

GROUP BY A
,B
,C
UNION ALL
GROUP BY()

Figure 576, CUBE on compound field, explanation

SELECT

d1
AS d1
,dept
AS dpt
,sex
AS sx
,INT(SUM(salary))
AS sal
,SMALLINT(COUNT(*)) AS r
FROM
employee_VIEW
GROUP BY d1
,dept
,sex
ORDER BY 1,2,3;
Figure 577, Basic GROUP BY example

ANSWER
==================
D1 DPT SX
SAL R
-- --- -- ------ A A00 F
52750 1
A A00 M
75750 2
B B01 M
41250 1
C C01 F
90470 3
D D11 F
73430 3
D D11 M 148670 6

DESIRED SUB-TOTALS
==================
D1, DEPT, and SEX.
D1 and DEPT.
D1 and SEX.
D1.
SEX.
Grand total.

EQUIVILENT TO
=====================================
GROUP BY GROUPING SETS ((d1,dept,sex)
,(d1,dept)
,(d1,sex)
,(d1)
,(sex)
EQUIVILENT TO
,())
=======================
GROUP BY ROLLUP(d1,dept)
,ROLLUP(sex)
Figure 578, Sub-totals that we want to get

SELECT
FROM

*
(SELECT

d1
,dept
,sex
,INT(SUM(salary))

AS
AS
AS
AS

d1
dpt
sx
sal

,SMALLINT(COUNT(*))
AS #r
,SMALLINT(GROUPING(d1))
AS g1
,SMALLINT(GROUPING(dept)) AS gd
,SMALLINT(GROUPING(sex))
AS gs
FROM
EMPLOYEE_VIEW
ANSWER
GROUP BY CUBE(d1,dept,sex)
============================
)AS xxx
D1 DPT SX SAL
#R G1 GD GS
WHERE
(g1,gd,gs) = (0,0,0)
-- --- -- ------ -- -- -- -OR
(g1,gd,gs) = (0,0,1)
A A00 F
52750 1 0 0 0
OR
(g1,gd,gs) = (0,1,0)
A A00 M
75750 2 0 0 0
OR
(g1,gd,gs) = (0,1,1)
A A00 - 128500 3 0 0 1
OR
(g1,gd,gs) = (1,1,0)
A F
52750 1 0 1 0
OR
(g1,gd,gs) = (1,1,1)
A M
75750 2 0 1 0
ORDER BY 1,2,3;
A - 128500 3 0 1 1
B B01 M
41250 1 0 0 0
B B01 41250 1 0 0 1
B M
41250 1 0 1 0
B 41250 1 0 1 1
C C01 F
90470 3 0 0 0
C C01 90470 3 0 0 1
C F
90470 3 0 1 0
C 90470 3 0 1 1
D D11 F
73430 3 0 0 0
D D11 M 148670 6 0 0 0
D D11 - 222100 9 0 0 1
D F
73430 3 0 1 0
D M 148670 6 0 1 0
D - 222100 9 0 1 1
- F 216650 7 1 1 0
- M 265670 9 1 1 0
- - 482320 16 1 1 1
Figure 579, Get lots of sub-totals, using CUBE

(G1,GD,GS) = (0,0,0)
(G1,GD,GS) = (0,0,1)
(G1,GD,GS) = (0,1,0)
(G1,GD,GS) = (0,1,1)
(G1,GD,GS) = (1,1,0)
(G1,GD,GS) = (1,1,1)
Figure 580, Predicates

SELECT

<==
D1, DEPT, SEX
<==
D1, DEPT
<==
D1, SEX
<==
D1,
<==
SEX,
<==
grand total
used - explanation

d1
,dept
,sex
,INT(SUM(salary))
AS sal
,SMALLINT(COUNT(*)) AS #r
FROM
employee_view
GROUP BY ROLLUP(d1,dept)
,ROLLUP(sex)
ORDER BY 1,2,3;

ANSWER
=====================
D1 DEPT SEX
SAL #R
-- ---- --- ------ -A A00 F
52750 1
A A00 M
75750 2
A A00 128500 3
A F
52750 1
A M
75750 2
A 128500 3
B B01 M
41250 1
B B01 41250 1

Figure 581, Get lots of sub-totals, using ROLLUP

B
B
C
C
C
C
D
D
D
D
D
D
-

C01
C01
D11
D11
D11
-

M
F
F
F
M
F
M
F
M
-

41250 1
41250 1
90470 3
90470 3
90470 3
90470 3
73430 3
148670 6
222100 9
73430 3
148670 6
222100 9
216650 7
265670 9
482320 16

SELECT

dept, job
,COUNT(*)
FROM
staff
GROUP BY dept, job
ORDER BY dept, job;
Figure 582, GROUP BY with ORDER BY

WITH staff2 (dept, avgsal) AS


ANSWER
(SELECT
dept
=================
,AVG(salary)
ID NAME
DEPT
FROM
staff
--- -------- ---GROUP BY dept
160 Molinare
10
HAVING
AVG(salary) > 18000
210 Lu
10
)
240 Daniels
10
SELECT
a.id
260 Jones
10
,a.name
,a.dept
FROM
staff a
,staff2 b
WHERE
a.dept = b.dept
ORDER BY a.id;
Figure 583, GROUP BY on one side of join - using common table expression

SELECT
FROM

a.id
,a.name
,a.dept
staff a
,(SELECT

dept
AS dept
,AVG(salary) AS avgsal
FROM
staff
GROUP BY dept

ANSWER
=================
ID NAME
DEPT
--- -------- ---160 Molinare
10
210 Lu
10
240 Daniels
10
260 Jones
10

HAVING
AVG(salary) > 18000
)AS b
WHERE
a.dept = b.dept
ORDER BY a.id;
Figure 584, GROUP BY on one side of join - using full-select

SELECT
FROM
WHERE

COUNT(*)
staff
id < 1;

AS c1

ANSWER
======
0

SELECT
COUNT(*) AS c1
FROM
staff
WHERE
id < 1
GROUP BY id;
Figure 585, COUNT and No Rows

CREATE
SELECT
FROM
WHERE

VIEW staff_v1 AS
id, name
staff
ID BETWEEN 10 AND 30;

ANSWER
======
no row

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

CREATE VIEW staff_v2 AS


SELECT id, job
FROM
staff
WHERE id BETWEEN 20 AND 50
UNION ALL
SELECT id, 'Clerk' AS job
FROM
staff
WHERE id = 30;
Figure 586, Sample Views used in Join Examples

STAFF_V2
+---------+
|ID|JOB
|
|--|------|
|20|Sales |
|30|Clerk |
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+

Figure 587, Join Syntax #1

SELECT

v1.id
,v1.name
,v2.job
FROM
staff_v1 v1
,staff_v2 v2
WHERE
v1.id = v2.id
ORDER BY v1.id
,v2.job;
Figure 588, Sample two-table join

JOIN ANSWER
=================
ID NAME
JOB
-- -------- ----20 Pernal
Sales
30 Marenghi Clerk
30 Marenghi Mgr

SELECT

v1.id
,v2.job
,v3.name
FROM
staff_v1 v1
,staff_v2 v2
,staff_v1 v3
WHERE
v1.id = v2.id
AND
v2.id = v3.id
AND
v3.name LIKE 'M%'
ORDER BY v1.name
,v2.job;
Figure 589, Sample three-table join

JOIN ANSWER
=================
ID JOB
NAME
-- ----- -------30 Clerk Marenghi
30 Mgr
Marenghi

Figure 590, Join Syntax #2

SELECT

v1.id
,v1.name
,v2.job
FROM
staff_v1 v1
INNER JOIN
staff_v2 v2
ON
v1.id = v2.id
ORDER BY v1.id
,v2.job;
Figure 591, Sample two-table inner join

SELECT
FROM
JOIN
ON
JOIN

v1.id
,v2.job
,v3.name
staff_v1 v1
staff_v2 v2
v1.id = v2.id

staff_v1 v3
ON
v2.id = v3.id
WHERE
v3.name LIKE 'M%'
ORDER BY v1.name
,v2.job;

JOIN ANSWER
=================
ID NAME
JOB
-- -------- ----20 Pernal
Sales
30 Marenghi Clerk
30 Marenghi Mgr

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

JOIN ANSWER
=================
ID JOB
NAME
-- ----- -------30 Clerk Marenghi
30 Mgr
Marenghi
Figure 592, Sample three-table inner join

STAFF_V2
+---------+
|ID|JOB
|
|--|------|
|20|Sales |
|30|Clerk |
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+

SELECT
*
FROM
staff_v1 v1
LEFT OUTER JOIN
staff_v2 v2
ON
1
= 1
AND
v1.id
= v2.id
ORDER BY v1.id
,v2.job;
Figure 593, Sample Views used in Join Examples

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders - 20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr

SELECT
*
FROM
staff_v1 v1
LEFT OUTER JOIN
staff_v2 v2
ON
1
= 1
WHERE
v1.id
= v2.id
ORDER BY v1.id
,v2.job;
Figure 594, Sample Views used in Join Examples

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

STAFF_V2
+---------+
|ID|JOB
|
Join on ID
|--|------|
==========>
|20|Sales |
|30|Clerk |
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+
Figure 595, Example of Inner Join

INNER-JOIN ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr

SELECT
FROM

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr

*
staff_v1 v1
,staff_v2 v2
WHERE
v1.id = v2.id
ORDER BY v1.id
,v2.job;
Figure 596, Inner Join SQL (1 of 2)

SELECT
*
FROM
staff_v1 v1
INNER JOIN
staff_v2 v2
ON
v1.id = v2.id
ORDER BY v1.id
,v2.job;
Figure 597, Inner Join SQL (2 of 2)

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr

SELECT
*
FROM
staff_v1 v1
INNER JOIN
staff_v2 v2
ON
v1.id
= v2.id
AND
v2.job <> 'Mgr'
ORDER BY v1.id
,v2.job;
Figure 598, Inner join, using ON check

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk

SELECT
*
FROM
staff_v1 v1
INNER JOIN
staff_v2 v2
ON
v1.id
= v2.id
WHERE
v2.job <> 'Mgr'
ORDER BY v1.id
,v2.job;
Figure 599, Inner join, using WHERE check

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

STAFF_V2
+---------+
|ID|JOB
|
|--|------|
=========>
|20|Sales |
|30|Clerk |
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+
Figure 600, Example of Left Outer Join

LEFT-OUTER-JOIN ANSWER
======================
ID NAME
ID JOB
-- -------- -- ----10 Sanders - 20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr

SELECT
*
FROM
staff_v1 v1
LEFT OUTER JOIN
staff_v2 v2
ON
v1.id = v2.id
ORDER BY 1,4;
Figure 601, Left Outer Join SQL (1 of 2)

SELECT
FROM
WHERE
UNION
SELECT

v1.*
,v2.*
staff_v1 v1
,staff_v2 v2
v1.id = v2.id

v1.*
,CAST(NULL AS SMALLINT) AS id
,CAST(NULL AS CHAR(5)) AS job
FROM
staff_v1 v1
WHERE
v1.id NOT IN
(SELECT id FROM staff_v2)
ORDER BY 1,4;
Figure 602, Left Outer Join SQL (2 of 2)

SELECT
*
FROM
staff_v1 v1
LEFT OUTER JOIN
staff_v2 v2
ON
v1.id
= v2.id
AND
v2.job <> 'Mgr'
ORDER BY v1.id
,v2.job;
Figure 603, ON check on table being joined to

<== This join gets all


rows in STAFF_V1
that match rows
in STAFF_V2.
<== This query gets
all the rows in
STAFF_V1 with no
matching rows
in STAFF_V2.

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders - 20 Pernal
20 Sales
30 Marenghi 30 Clerk

SELECT
*
ANSWER
FROM
staff_v1 v1
====================
LEFT OUTER JOIN
ID NAME
ID JOB
staff_v2 v2
-- -------- -- ----ON
v1.id
= v2.id
20 Pernal
20 Sales
WHERE
v2.job <> 'Mgr'
30 Marenghi 30 Clerk
ORDER BY v1.id
,v2.job;
Figure 604, WHERE check on table being joined to (1 of 2)

SELECT
*
ANSWER
FROM
staff_v1 v1
====================
LEFT OUTER JOIN
ID NAME
ID JOB
staff_v2 v2
-- -------- -- ----ON
v1.id
= v2.id
10 Sanders - WHERE
(v2.job <> 'Mgr'
20 Pernal
20 Sales
OR
v2.job IS NULL)
30 Marenghi 30 Clerk
ORDER BY v1.id
,v2.job;
Figure 605, WHERE check on table being joined to (2 of 2)

SELECT
*
FROM
staff_v1 v1
LEFT OUTER JOIN
staff_v2 v2
ON
v1.id
= v2.id
AND
v1.name > 'N'
ORDER BY v1.id
,v2.job;
Figure 606, ON check on table being joined from

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders - 20 Pernal
20 Sales
30 Marenghi - -

SELECT
*
ANSWER
FROM
staff_v1 v1
====================
LEFT OUTER JOIN
ID NAME
ID JOB
staff_v2 v2
-- -------- -- ----ON
v1.id
= v2.id
10 Sanders - WHERE
v1.name > 'N'
20 Pernal
20 Sales
ORDER BY v1.id
,v2.job;
Figure 607, WHERE check on table being joined from

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

STAFF_V2
+---------+
|ID|JOB
|
|--|------|
=========>
|20|Sales |
|30|Clerk |
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+
Figure 608, Example of Right Outer Join

RIGHT-OUTER-JOIN ANSWER
=======================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr
- 40 Sales
- 50 Mgr

SELECT
*
FROM
staff_v1 v1
RIGHT OUTER JOIN
staff_v2 v2
ON
v1.id = v2.id
ORDER BY v2.id
,v2.job;
Figure 609, Right Outer Join SQL (1 of 2)

SELECT
FROM
WHERE
UNION
SELECT

v1.*
,v2.*
staff_v1 v1
,staff_v2 v2
v1.id = v2.id

CAST(NULL AS SMALLINT)
AS id
,CAST(NULL AS VARCHAR(9)) AS name
,v2.*
FROM
staff_v2 v2
WHERE
v2.id NOT IN
(SELECT id FROM staff_v1)
ORDER BY 3,4;
Figure 610, Right Outer Join SQL (2 of 2)

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

STAFF_V2
+---------+
|ID|JOB
|
|--|------|
=========>
|20|Sales |
|30|Clerk |
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+
Figure 611, Example of Full Outer Join

SELECT
*
FROM
staff_v1 v1
FULL OUTER JOIN
staff_v2 v2
ON
v1.id = v2.id
ORDER BY v1.id
,v2.id
,v2.job;

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr
- 40 Sales
- 50 Mgr

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr
- 40 Sales
- 50 Mgr

FULL-OUTER-JOIN ANSWER
======================
ID NAME
ID JOB
-- -------- -- ----10 Sanders - 20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr
- 40 Sales
- 50 Mgr

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders - 20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr

- - -

40 Sales
50 Mgr

Figure 612, Full Outer Join SQL

SELECT
FROM
WHERE
UNION
SELECT
FROM
WHERE
UNION
SELECT

v1.*
,v2.*
staff_v1 v1
,staff_v2 v2
v1.id = v2.id
v1.*
,CAST(NULL AS SMALLINT) AS id
,CAST(NULL AS CHAR(5)) AS job
staff_v1 v1
v1.id NOT IN
(SELECT id FROM staff_v2)

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders - 20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr
- 40 Sales
- 50 Mgr

CAST(NULL AS SMALLINT)
AS id
,CAST(NULL AS VARCHAR(9)) AS name
,v2.*
FROM
staff_v2 v2
WHERE
v2.id NOT IN
(SELECT id FROM staff_v1)
ORDER BY 1,3,4;
Figure 613, Full Outer Join SQL

SELECT
*
FROM
staff_v1 v1
FULL OUTER JOIN
staff_v2 v2
ON
v1.id = v2.id
ORDER BY v1.id
,v2.id
,v2.job;

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders
- 20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr
- 40 Sales
- 50 Mgr

Figure 614, Full Outer Join, match on keys

SELECT
*
FROM
staff_v1 v1
FULL OUTER JOIN
staff_v2 v2
ON
v1.id = v2.id
AND
v1.id > 20
ORDER BY v1.id
,v2.id
,v2.job;

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders
- 20 Pernal
- 30 Marenghi 30 Clerk
30 Marenghi 30 Mgr
- 20 Sales
- 40 Sales

Figure 615, Full Outer Join, match on keys > 20

- -

50 Mgr

SELECT
*
FROM
staff_v1 v1
FULL OUTER JOIN
staff_v2 v2
ON
v1.id = v2.id
AND
+1 = -1
ORDER BY v1.id
,v2.id
,v2.job;

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders
- 20 Pernal
- 30 Marenghi - - 20 Sales
- 30 Clerk
- 30 Mgr
- 40 Sales
- 50 Mgr
Figure 616, Full Outer Join, match on keys (no rows match)

SELECT
*
FROM
staff_v1 v1
FULL OUTER JOIN
staff_v2 v2
ON
+1 = -1
ORDER BY v1.id
,v2.id
,v2.job;

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders
- 20 Pernal
- 30 Marenghi - - 20 Sales
- 30 Clerk
- 30 Mgr
- 40 Sales
- 50 Mgr
Figure 617, Full Outer Join, don't match on keys (no rows match)

SELECT
*
FROM
staff_v1 v1
FULL OUTER JOIN
staff_v2 v2
ON
+1 <> -1
ORDER BY v1.id
,v2.id
,v2.job;
STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|

STAFF_V2
+---------+
|ID|JOB
|
|--|------|
|20|Sales |
|30|Clerk |
|30|Mgr
|

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders 20 Sales
10 Sanders 30 Clerk
10 Sanders 30 Mgr
10 Sanders 40 Sales
10 Sanders 50 Mgr
20 Pernal
20 Sales
20 Pernal
30 Clerk
20 Pernal
30 Mgr
20 Pernal
40 Sales
20 Pernal
50 Mgr
30 Marenghi 20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr

+-----------+

|40|Sales |
30 Marenghi 40 Sales
|50|Mgr
|
30 Marenghi 50 Mgr
+---------+
Figure 618, Full Outer Join, don't match on keys (all rows match)

SELECT
*
FROM
staff_v1 v1
FULL JOIN
staff_v2 v2
ON
v1.id = v2.id
WHERE
v1.id = v2.id
ORDER BY 1,3,4;
Figure 619, Full Outer Join, turned into an inner

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----20 Pernal
20 Sales
30 Marenghi 30 Clerk
30 Marenghi 30 Mgr
join by WHERE

STAFF_V2
+---------+
|ID|JOB
|
OUTER-JOIN CRITERIA
|--|------|
==================>
|20|Sales |
V1.ID = V2.ID
|30|Clerk |
V1.ID < 30
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+
Figure 620, Outer join V1.ID < 30, sample data

ANSWER
============
???, DEPENDS

SELECT
*
ANSWER
FROM
staff_v1 v1
====================
FULL JOIN
ID NAME
ID JOB
staff_v2 v2
-- -------- -- ----ON
v1.id = v2.id
10 Sanders - WHERE
v1.id < 30
20 Pernal
20 Sales
ORDER BY 1,3,4;
Figure 621, Outer join V1.ID < 30, check applied in WHERE (after join)

SELECT
*
FROM
staff_v1 v1
FULL JOIN
staff_v2 v2
ON
v1.id = v2.id
AND
v1.id < 30
ORDER BY 1,3,4;

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders - 20 Pernal
20 Sales
30 Marenghi - - 30 Clerk

- 30 Mgr
- 40 Sales
- 50 Mgr
Figure 622, Outer join V1.ID < 30, check applied in ON (during join)

SELECT
FROM

*
(SELECT *
FROM
staff_v1
WHERE id < 30) AS v1
FULL OUTER JOIN
staff_v2 v2
ON
v1.id = v2.id
ORDER BY 1,3,4;

ANSWER
====================
ID NAME
ID JOB
-- -------- -- ----10 Sanders - 20 Pernal
20 Sales
- 30 Clerk
- 30 Mgr
- 40 Sales
- 50 Mgr
Figure 623, Outer join V1.ID < 30, check applied in WHERE (before join)

SELECT
*
FROM
staff_v1
FULL OUTER JOIN
staff_v2
ON
v1.id =
WHERE
v1.id <
OR
v1.id IS
ORDER BY 1,3,4;
Figure 624, Outer

SELECT
*
FROM
staff_v1
FULL OUTER JOIN
staff_v2
ON
v1.id =
WHERE
v1.id <
OR
v1.id =
OR
v1.id IS
ORDER BY 1,3,4;

ANSWER
====================
ID NAME
ID JOB
v2
-- -------- -- ----v2.id
10 Sanders - 30
20 Pernal
20 Sales
NULL
- 40 Sales
- 50 Mgr
join V1.ID < 30, (gives wrong answer - see text)
v1

ANSWER
====================
ID NAME
ID JOB
v2
-- -------- -- ----v2.id
10 Sanders - 30
20 Pernal
20 Sales
v2.id
30 Marenghi 30 Clerk
NULL
30 Marenghi 30 Mgr
- 40 Sales
- 50 Mgr
Figure 625, Outer join V1.ID < 30, (gives wrong answer - see text)

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|

v1

STAFF_V2
+---------+
|ID|JOB
|
|--|------|

=========>

CARTESIAN-PRODUCT
====================
ID NAME
ID JOB
-- -------- -- -----

|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

|20|Sales |
|30|Clerk |
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+

Figure 626, Example of Cartesian Product

10
10
10
10
10
20
20
20
20
20
30
30
30
30
30

Sanders
Sanders
Sanders
Sanders
Sanders
Pernal
Pernal
Pernal
Pernal
Pernal
Marenghi
Marenghi
Marenghi
Marenghi
Marenghi

20
30
30
40
50
20
30
30
40
50
20
30
30
40
50

Sales
Clerk
Mgr
Sales
Mgr
Sales
Clerk
Mgr
Sales
Mgr
Sales
Clerk
Mgr
Sales
Mgr

SELECT
FROM

*
staff_v1 v1
,staff_v2 v2
ORDER BY v1.id
,v2.id
,v2.job;
Figure 627, Cartesian Product SQL (1 of 2)

SELECT
*
FROM
staff_v1 v1
INNER JOIN
staff_v2 v2
ON
'A' <> 'B'
ORDER BY v1.id
,v2.id
,v2.job;
Figure 628, Cartesian Product SQL (2 of 2)

SELECT

v2a.id
,v2a.job
,v2b.id
FROM
staff_v2 v2a
,staff_v2 v2b
WHERE
v2a.job = v2b.job
AND
v2a.id < 40
ORDER BY v2a.id
,v2b.id;
Figure 629, Partial Cartesian Product SQL

ANSWER
===========
ID JOB
ID
-- ----- -20 Sales 20
20 Sales 40
30 Clerk 30
30 Mgr
30
30 Mgr
50

SELECT

v2.job
,COUNT(*) AS #rows
FROM
staff_v1 v1
,staff_v2 v2
GROUP BY v2.job
ORDER BY #rows
,v2.job;
Figure 630, Partial Cartesian Product SQL, with GROUP BY

ANSWER
===========
JOB
#ROWS
----- ----Clerk
3
Mgr
6
Sales
6

SELECT

ANSWER
=================
ID NAME
JOB
-- -------- ----10 Sanders 20 Pernal
Sales
30 Marenghi Clerk
30 Marenghi Mgr
40 ?
Sales
50 ?
Mgr

COALESCE(v1.id,v2.id) AS id
,COALESCE(v1.name,'?') AS name
,v2.job
FROM
staff_v1 v1
FULL OUTER JOIN
staff_v2 v2
ON
v1.id = v2.id
ORDER BY v1.id
,v2.job;
Figure 631, Use of COALESCE function in outer join

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

STAFF_V2
ANSWER
+---------+
NON-MATCHING
===================
|ID|JOB
|
OUTER-JOIN
ID NAME
ID JOB
|--|------|
===========>
-- ------- -- ----|20|Sales |
10 Sanders - |30|Clerk |
- 40 Sales
|30|Mgr
|
- 50 Mgr
|40|Sales |
|50|Mgr
|
+---------+
Figure 632, Example of outer join, only getting the non-matching rows

SELECT
FROM
WHERE
UNION
SELECT
FROM
WHERE

v1.*
,CAST(NULL AS SMALLINT) AS id
,CAST(NULL AS CHAR(5)) AS job
staff_v1 v1
v1.id NOT IN
(SELECT id FROM staff_v2)

<== Get all the rows


in STAFF_V1 that
have no matching
row in STAFF_V2.

CAST(NULL AS SMALLINT)
AS id
,CAST(NULL AS VARCHAR(9)) AS name
,v2.*
staff_v2 v2
v2.id NOT IN

<== Get all the rows


in STAFF_V2 that
have no matching
row in STAFF_V1.

(SELECT id FROM staff_v1)


ORDER BY 1,3,4;
Figure 633, Outer Join SQL, getting only non-matching rows

SELECT
*
FROM
(SELECT v1.*
,'V1' AS flag
FULL OUTER JOIN
(SELECT v2.*
,'V2' AS flag
ON
v1.id = v2.id
WHERE
v1.flag IS NULL
OR
v2.flag IS NULL
ORDER BY v1.id
,v2.id
,v2.job;

FROM staff_v1 v1) AS v1


FROM staff_v2 v2) AS v2

ANSWER
=============================
ID NAME
FLAG ID JOB
FLAG
-- ------- ---- -- ----- ---10 Sanders V1
- - 40 Sales V2
- 50 Mgr
V2
Figure 634, Outer Join SQL, getting only non-matching rows

WITH
v1 AS (SELECT v1.*
,'V1' AS flag
FROM staff_v1 v1)
,v2 AS (SELECT v2.*
,'V2' AS flag
FROM staff_v2 v2)
SELECT *
FROM
v1 v1
ANSWER
FULL OUTER JOIN
=============================
v2 v2
ID NAME
FLAG ID JOB
FLAG
ON
v1.id = v2.id
-- ------- ---- -- ----- ---WHERE
v1.flag IS NULL
10 Sanders V1
- OR
v2.flag IS NULL
- 40 Sales V2
ORDER BY v1.id, v2.id, v2.job;
- 50 Mgr
V2
Figure 635, Outer Join SQL, getting only non-matching rows

SELECT
*
FROM
staff_v1
FULL OUTER JOIN
staff_v2
ON
v1.id =
WHERE
v1.id IS
OR
v2.id IS
ORDER BY v1.id
,v2.id
,v2.job;
Figure 636, Outer

v1
v2
v2.id
NULL
NULL

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

Join SQL, getting only non-matching rows

STAFF_V2
+---------+
|ID|JOB
|
|--|------|
|20|Sales |
|30|Clerk |
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

STAFF_V2
+---------+
LEFT OUTER JOIN
|ID|JOB
|
==============>
|--|------|
V1.ID = V2.ID
|20|Sales |
V1.ID <> 30
|30|Clerk |
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+
Figure 637, Left outer join example

SELECT

v1.id
,v1.name
,v2.job
FROM
staff_v1
LEFT OUTER JOIN
staff_v2
ON
v1.id =
WHERE
v1.id <>
ORDER BY v1.id ;
Figure 638, Outer

ANSWER
===================
ID NAME
ID JOB
-- ------- -- ----10 Sanders - 20 Pernal 20 Sales

v1.id
,v1.name
,(SELECT
FROM
WHERE
FROM
staff_v1
WHERE
v1.id <>
ORDER BY v1.id;
Figure 639, Outer

v1
v2
v2.id
30
Join done in FROM phrase of SQL

SELECT

v1.id
,v1.name
,(SELECT
FROM
WHERE
FROM
staff_v1
ORDER BY v1.id;
Figure 640, Outer

v2.job
staff_v2 v2
v1.id = v2.id) AS jb
v1
30

v1.id

ANSWER
=================
ID NAME
JB
-- -------- ----10 Sanders 20 Pernal
Sales

Join done in SELECT phrase of SQL

SELECT

SELECT

ANSWER
=================
ID NAME
JOB
-- -------- ----10 Sanders 20 Pernal
Sales

v2.job
staff_v2 v2
v1.id = v2.id) AS jb
v1

ANSWER
=================
ID NAME
JB
-- -------- ----10 Sanders 20 Pernal
Sales

Join done in SELECT phrase of SQL - gets error

ANSWER

,v1.name
,(SELECT
FROM
WHERE
FROM
staff_v1
ORDER BY v1.id;
Figure 641, Outer

=================
ID NAME
JB
-- -------- ----10 Sanders 20 Pernal
Sales
30 Marenghi Mgr
Join done in SELECT phrase of SQL - fixed
MAX(v2.job)
staff_v2 v2
v1.id = v2.id) AS jb
v1

SELECT

v1.id
ANSWER
,v1.name
=================
,MAX(v2.job) AS jb
ID NAME
JB
FROM
staff_v1 v1
-- -------- ----LEFT OUTER JOIN
10 Sanders staff_v2 v2
20 Pernal
Sales
ON
v1.id = v2.id
30 Marenghi Mgr
GROUP BY v1.id
,v1.name
ORDER BY v1.id ;
Figure 642, Same as prior query - using join and GROUP BY

SELECT

v2.id
,CASE
WHEN v2.job <> 'Mgr'
THEN v2.job
ELSE (SELECT v1.name
FROM
staff_v1 v1
WHERE v1.id = v2.id)
END AS j2
FROM
staff_v2 v2
ORDER BY v2.id
,j2;
Figure 643, Sample Views used in Join Examples

ANSWER
===========
ID J2
-- -------20 Sales
30 Clerk
30 Marenghi
40 Sales
50 -

SELECT

ANSWER
====================
ID JOB
NAME
N2
-- ----- -------- -20 Sales Pernal
6
30 Clerk Marenghi 8
30 Mgr
Marenghi 8
40 Sales 50 Mgr
-

v2.id
,v2.job
,(SELECT
FROM
WHERE
,(SELECT
FROM
WHERE
FROM
staff_v2
ORDER BY v2.id
,v2.job;
Figure 644, Outer

v1.name
staff_v1 v1
v2.id = v1.id)
LENGTH(v1.name) AS n2
staff_v1 v1
v2.id = v1.id)
v2
Join done in SELECT, 2 columns

SELECT

v2.id
,v2.job
,v1.name
,LENGTH(v1.name) AS n2
FROM
staff_v2 v2
LEFT OUTER JOIN
staff_v1 v1
ON
v2.id = v1.id
ORDER BY v2.id
,v2.job;
Figure 645, Outer Join done in FROM, 2 columns

ANSWER
====================
ID JOB
NAME
N2
-- ----- -------- -20 Sales Pernal
6
30 Clerk Marenghi 8
30 Mgr
Marenghi 8
40 Sales 50 Mgr
-

SELECT

v1.id
,v1.name
,(SELECT SUM(x1.id)
FROM
staff_v1 x1
WHERE
x1.id <= v1.id
)AS sum_id
FROM
staff_v1 v1
ORDER BY v1.id
,v2.job;
Figure 646, Running total, using JOIN in SELECT

ANSWER
==================
ID NAME
SUM_ID
-- -------- -----10 Sanders
10
20 Pernal
30
30 Marenghi
60

SELECT

ANSWER
==================
ID NAME
SUM_ID
-- -------- -----10 Sanders
10
20 Pernal
30
30 Marenghi
60

v1.id
,v1.name
,SUM(id) OVER(ORDER BY id) AS sum_id
FROM
staff_v1 v1
ORDER BY v1.id;
Figure 647, Running total, using OLAP function

STAFF_V1
+-----------+
|ID|NAME
|
|--|--------|
|10|Sanders |
|20|Pernal |
|30|Marenghi|
+-----------+

STAFF_V2
+---------+
|ID|JOB
|
OUTER-JOIN CRITERIA
|--|------|
==================>
|20|Sales |
V1.ID
= V2.ID
|30|Clerk |
V2.JOB LIKE 'S%'
|30|Mgr
|
|40|Sales |
|50|Mgr
|
+---------+
Figure 648, Outer join, with WHERE filter

ANSWER
=================
ID NAME
JOB
-- -------- ----10 Sanders 20 Pernal
Sales
30 Marenghi -

SELECT

v1.id
,v1.name
,v2.job
FROM
staff_v1 v1
LEFT OUTER JOIN
staff_v2 v2
ON
v1.id
= v2.id
WHERE
v2.job LIKE 'S%'
ORDER BY v1.id
,v2.job;
Figure 649, Outer Join, WHERE done after - wrong

ANSWER (WRONG)
=================
ID NAME
JOB
-- -------- ----20 Pernal
Sales

SELECT

ANSWER
=================
ID NAME
JOB
-- -------- ----10 Sanders 20 Pernal
Sales
30 Marenghi -

v1.id
,v1.name
,v2.job
FROM
staff_v1 v1
LEFT OUTER JOIN
(SELECT *
FROM
staff_v2
WHERE
job LIKE 'S%'
)AS v2
ON
v1.id = v2.id
ORDER BY v1.id
,v2.job;
Figure 650, Outer Join, WHERE done before - correct

SELECT

v1.id
ANSWER
,v1.name
=================
,(SELECT v2.job
ID NAME
JOB
FROM
staff_v2 v2
-- -------- ----WHERE v1.id
= v2.id
10 Sanders AND v2.job LIKE 'S%')
20 Pernal
Sales
FROM
staff_v1 v1
30 Marenghi ORDER BY v1.id
,job;
Figure 651, Outer Join, WHERE done independently - correct

SELECT

eee.empno
,aaa.projno
,aaa.actno
,ppp.photo_format AS format
FROM
employee
eee
LEFT OUTER JOIN
emp_act
aaa

ANSWER
==========================
EMPNO PROJNO ACTNO FORMAT
------ ------ ----- -----000010 MA2110
10 000070 - 000130 - bitmap

ON
eee.empno
=
AND
aaa.emptime
=
AND
aaa.projno
LIKE
LEFT OUTER JOIN
emp_photo ppp
ON
eee.empno
=
AND
ppp.photo_format LIKE
WHERE
eee.lastname
LIKE
AND
eee.empno
<
AND
eee.empno
<>
ORDER BY eee.empno;
Figure 652, Join from Employee

aaa.empno
1
'M%1%'

60 bitmap
180 bitmap
60 -

ppp.empno
'b%'
'%A%'
'000170'
'000030'
to Activity and Photo

SELECT

eee.empno
,aaa.projno
,aaa.actno
,ppp.photo_format AS format
FROM
employee
eee
LEFT OUTER JOIN
emp_act
aaa
ON
eee.empno
= aaa.empno
AND
aaa.emptime
= 1
AND
aaa.projno
LIKE 'M%1%'
LEFT OUTER JOIN
emp_photo ppp
ON
aaa.empno
= ppp.empno
AND
ppp.photo_format LIKE 'b%'
WHERE
eee.lastname
LIKE '%A%'
AND
eee.empno
< '000170'
AND
eee.empno
<> '000030'
ORDER BY eee.empno;
Figure 653, Join from Employee to Activity,

SELECT

000150 MA2112
000150 MA2112
000160 MA2113

ddd.deptno AS dp#
,eee.empno
,aaa.projno
,ppp.projname
FROM
(SELECT *
FROM
department
WHERE
deptname
LIKE '%A%'
AND
deptname NOT LIKE '%U%'
AND
deptno
< 'E'
)AS ddd
INNER JOIN
employee
eee
ON
ddd.deptno
= eee.workdept
AND
eee.lastname LIKE '%A%'
LEFT OUTER JOIN
emp_act
aaa
ON
aaa.empno
= eee.empno
AND
aaa.emptime
<= 0.5
INNER JOIN
project
ppp

ANSWER
==========================
EMPNO PROJNO ACTNO FORMAT
------ ------ ----- -----000010 MA2110
10 000070 - 000130 - 000150 MA2112
60 bitmap
000150 MA2112
180 bitmap
000160 MA2113
60 -

then from Activity to Photo

ON
aaa.projno
AND
ppp.projname
ORDER BY ddd.deptno
,eee.empno
,aaa.projno;

= ppp.projno
LIKE '%Q%'

Figure 654, Complex join - wrong

ANSWER
================================
DP# EMPNO PROJNO PROJNAME
--- ------ ------ -------------C01 000030 IF1000 QUERY SERVICES
C01 000130 IF1000 QUERY SERVICES

SELECT

ddd.deptno AS dp#
,eee.empno
,xxx.projno
,xxx.projname
FROM
(SELECT *
FROM
department
WHERE
deptname
LIKE '%A%'
AND
deptname NOT LIKE '%U%'
AND
deptno
< 'E'
)AS ddd
INNER JOIN
employee
eee
ON
ddd.deptno
= eee.workdept
AND
eee.lastname LIKE '%A%'
LEFT OUTER JOIN
(SELECT
aaa.empno
,aaa.emptime
,aaa.projno
,ppp.projname
FROM
emp_act
aaa
INNER JOIN
project
ppp
ON
aaa.projno
= ppp.projno
AND
ppp.projname LIKE '%Q%'
)AS xxx
ON
xxx.empno
= eee.empno
AND
xxx.emptime
<= 0.5
ORDER BY ddd.deptno
,eee.empno
ANSWER
,xxx.projno;
================================
DP# EMPNO PROJNO PROJNAME
--- ------ ------ -------------C01 000030 IF1000 QUERY SERVICES
C01 000130 IF1000 QUERY SERVICES
D21 000070 D21 000240 Figure 655, Complex join - right

CREATE TABLE table1


(t1a
CHAR(1)
,t1b
CHAR(2)
,PRIMARY KEY(t1a));

NOT NULL
NOT NULL

TABLE1
+-------+
|T1A|T1B|
|---|---|

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|

COMMIT;
CREATE TABLE table2
(t2a
CHAR(1)
,t2b
CHAR(1)
,t2c
CHAR(1));

|A |AA |
|B |BB |
|C |CC |
+-------+

NOT NULL
NOT NULL

|A |A |A |
|B |A | - |
+-----------+
"-" = null

INSERT INTO table1 VALUES ('A','AA'),('B','BB'),('C','CC');


INSERT INTO table2 VALUES ('A','A','A'),('B','A',NULL);
Figure 656, Sample tables used in sub-query examples

Figure 657, Sub-query syntax diagram

SELECT *
FROM
table1
WHERE t1a =
(SELECT t2a
FROM
table2
WHERE t2a = 'A');

ANSWER
=======
T1A T1B
--- -A
AA
SUB-Q
RESLT
+---+
|T2A|
|---|
|A |
+---+

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

Figure 658, No keyword sub-query, works

SELECT *
FROM
table1
WHERE t1a =
(SELECT t2a
FROM
table2);
SUB-Q
RESLT
+---+
|T2A|
|---|
|A |
|B |
+---+
Figure 659, No keyword sub-query, fails

ANSWER
=======

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

SELECT *
FROM
table1
WHERE t1a > ANY
(SELECT t2a
FROM
table2);

ANSWER
=======
T1A T1B
--- -B
BB
C
CC

SUB-Q
RESLT
+---+
|T2A|
|---|
|A |
|B |
+---+

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

Figure 660, ANY sub-query

SUB-QUERY CHECK
================
> ANY(sub-qurey)
< ANY(sub-query)

EQUIVALENT COLUMN FUNCTION


============================
> MINIMUM(sub-query results)
< MAXIMUM(sub-query results)

> ALL(sub-query)
> MAXIMUM(sub-query results)
< ALL(sub-query)
< MINIMUM(sub-query results)
Figure 661, ANY and ALL vs. column functions

SELECT *
FROM
table1
WHERE t1a = ALL
(SELECT t2b
FROM
table2
WHERE t2b >= 'A');

ANSWER
=======
T1A T1B
--- -A
AA

Figure 662, ALL sub-query, with non-empty sub-query result

SELECT *
FROM
table1
WHERE t1a = ALL
(SELECT t2b
FROM
table2
WHERE t2b >= 'X');

ANSWER
=======
T1A T1B
--- -A
AA
B
BB
C
CC

SUB-Q
RESLT
+---+
|T2B|
|---|
|A |
|A |
+---+

SUB-Q
RESLT
+---+
|T2B|
|---|
+---+

Figure 663, ALL sub-query, with empty sub-query result

SELECT *
FROM
table1
WHERE t1a = ALL

ANSWER
======
0 rows

(SELECT
FROM
WHERE
AND 0 <>
(SELECT
FROM
WHERE

t2b
table2
t2b >= 'X')

TABLE1
TABLE2
+-------+ +-----------+
|T1A|T1B| |T2A|T2B|T2C|
COUNT(*)
|---|---| |---|---|---|
table2
|A |AA | |A |A |A |
t2b >= 'X');
|B |BB | |B |A | - |
|C |CC | +-----------+
+-------+ "-" = null
Figure 664, ALL sub-query, with extra check for empty set

SELECT *
FROM
table1
WHERE EXISTS
(SELECT *
FROM
table2);

SQ-#1
RESLT
+---+
|T2B|
|---|
+---+

SQ-#2
RESLT
+---+
|(*)|
|---|
|0 |
+---+

ANSWER
=======
T1A T1B
--- -A
AA
B
BB
C
CC

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+
Figure 665, EXISTS sub-query, always returns a match

SELECT *
FROM
table1
WHERE EXISTS
(SELECT *
FROM
table2
WHERE t2b >= 'X');
Figure 666, EXISTS sub-query, always returns a non-match

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

ANSWER
======
0 rows

SELECT *
FROM
table1
WHERE EXISTS
(SELECT COUNT(*)
FROM
table2
WHERE t2b = 'X');

ANSWER
=======
T1A T1B
--- -A
AA
B
BB
C
CC

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+
Figure 667, EXISTS sub-query, always returns a match

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

SELECT *
FROM
table1
WHERE NOT EXISTS
(SELECT *

ANSWERS
=======
T1A T1B
--- ---

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|

TABLE1
+-------+
|T1A|T1B|
|---|---|

FROM
WHERE
AND

table2
t2c >= 'A'
t2c <> t1a);

AA

|A |AA |
|B |BB |
|C |CC |
+-------+

|A |A |A |
|B |A | - |
+-----------+
"-" = null

SELECT *
FROM
table1
WHERE t1a = ALL
(SELECT t2c
FROM
table2
WHERE t2c >= 'A');
Figure 668, NOT EXISTS vs. ALL, ignore nulls, find match

SELECT *
FROM
table1
WHERE NOT EXISTS
(SELECT *
FROM
table2
WHERE t2c >= 'X'
AND t2c <> t1a);

ANSWERS
=======
T1A T1B
--- --A
AA
B
BB
C
CC

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

SELECT *
FROM
table1
WHERE t1a = ALL
(SELECT t2c
FROM
table2
WHERE t2c >= 'X');
Figure 669, NOT EXISTS vs. ALL, ignore nulls, no match

SELECT *
FROM
table1
WHERE NOT EXISTS
(SELECT *
FROM
table2
WHERE t2c <> t1a);

ANSWER
=======
T1A T1B
--- --A
AA

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

SELECT *
ANSWER
FROM
table1
=======
WHERE t1a = ALL
no rows
(SELECT t2c
FROM
table2);
Figure 670, NOT EXISTS vs. ALL, process nulls

SELECT *
FROM
table2
WHERE t2c <> 'A';

SELECT *
FROM
table2
WHERE t2c <> 'B';

SELECT *
FROM
table2
WHERE t2c <> 'C';

ANSWER
ANSWER
===========
===========
T2A T2B T2C
T2A T2B T2C
--- --- ----- --- --no rows
A
A
A
Figure 671, List of values in T2C <> T1A value

SELECT *
FROM
table1
WHERE NOT EXISTS
(SELECT *
FROM
table2
WHERE t2c <> t1a
OR t2c IS NULL);

ANSWER
=======
no rows

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

ANSWER
=======
T1A T1B
--- -A
AA
B
BB

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

Figure 672, NOT EXISTS - same as ALL

SELECT *
FROM
table1
WHERE t1a IN
(SELECT t2a
FROM
table2);

ANSWER
===========
T2A T2B T2C
--- --- --A
A
A

Figure 673, IN sub-query example, two matches

SELECT *
FROM
table1
WHERE t1a IN
(SELECT t2a
FROM
table2
WHERE t2a >= 'X');
Figure 674, IN sub-query example, no matches

SELECT *
FROM
table2
WHERE t2c IN
(SELECT t2c
FROM
table2);
SELECT *

ANSWERS
===========
T2A T2B T2C
--- --- --A
A
A

ANSWER
======
0 rows

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+

FROM
WHERE

table2
t2c = ANY
(SELECT t2c
FROM
table2);
Figure 675, IN and = ANY sub-query examples, with nulls

"-" = null

SELECT *
FROM
table1
WHERE t1a NOT IN
(SELECT t2c
FROM
table2);

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+
Figure 676, NOT IN sub-query example, no matches

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

SELECT *
FROM
table1
WHERE t1a NOT IN
(SELECT t2c
FROM
table2
WHERE t2c IS NOT NULL);

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

ANSWER
======
0 rows

ANSWER
=======
T1A T1B
--- -B
BB
C
CC

Figure 677, NOT IN sub-query example, matches

SELECT *
FROM
table1
WHERE NOT EXISTS
(SELECT *
FROM
table2
WHERE t1a = t2c);

ANSWER
=======
T1A T1B
--- -B
BB
C
CC

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+
Figure 678, NOT EXISTS sub-query example, matches

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

SELECT *
FROM
table1
WHERE t1a IN
(SELECT t2a
FROM
table2);

ANSWER
=======
T1A T1B
--- -A
AA
B
BB

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |

+-------+

"-" = null

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

ANSWER
===========
T2A T2B T2C
--- --- --A
A
A

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

Figure 679, Uncorrelated sub-query

SELECT *
FROM
table1
WHERE t1a IN
(SELECT t2a
FROM
table2
WHERE t1a = t2a);

ANSWER
=======
T1A T1B
--- -A
AA
B
BB

Figure 680, Correlated sub-query

SELECT *
FROM
table2
WHERE EXISTS
(SELECT
FROM
WHERE

aa
*
table2 bb
aa.t2a = bb.t2b);

Figure 681,Correlated sub-query, with correlation names

SELECT *
FROM
table1
WHERE (t1a,t1b) IN
(SELECT t2a, t2b
FROM
table2);

ANSWER
======
0 rows

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

SELECT *
ANSWER
FROM
table1
======
WHERE EXISTS
0 rows
(SELECT
*
FROM
table2
WHERE
t1a = t2a
AND
t1b = t2b);
Figure 682, Multi-field sub-queries, equal checks

SELECT *
FROM
table1
WHERE EXISTS

ANSWER
=======
T1A T1B

TABLE1
+-------+
|T1A|T1B|

TABLE2
+-----------+
|T2A|T2B|T2C|

(SELECT
FROM
WHERE
AND

*
table2
t1a = t2a
t1b >= t2b);

--- -A
AA
B
BB

|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+
Figure 683, Multi-field sub-query, with non-equal check

SELECT empno
,lastname
,salary
FROM
employee
WHERE salary >
(SELECT MAX(salary)
FROM
employee
WHERE empno NOT IN
(SELECT empno
FROM
emp_act
WHERE projno LIKE 'MA%'))
ORDER BY 1;
Figure 684, Nested Sub-Queries

|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

ANSWER
=========================
EMPNO LASTNAME SALARY
------ --------- -------000010 HAAS
52750.00
000110 LUCCHESSI 46500.00

SELECT

COUNT(*)
AS #rows
,MAX(deptno) AS maxdpt
FROM
department
WHERE
deptname LIKE 'Z%'
ORDER BY 1;
Figure 685, Getting a null value from a not null field

ANSWER
=============
#ROWS MAXDEPT
----- ------0
null

SELECT *
FROM
table1
WHERE 0 =
(SELECT
FROM
WHERE

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

t1
COUNT(*)
table2 t2
t1.t1a = t2.t2c);

SELECT *
FROM
table1 t1
WHERE NOT EXISTS
(SELECT *
FROM
table2 t2
WHERE t1.t1a = t2.t2c);
SELECT *
FROM
table1
WHERE t1a NOT IN
(SELECT t2c
FROM
table2
WHERE t2c IS NOT NULL);

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

ANSWER
=======
T1A T1B
--- --B
BB
C
CC

Figure 686, Sub-queries, true if none match

SELECT t1.*
FROM
table1 t1
LEFT OUTER JOIN
table2 t2
ON
t1.t1a = t2.t2c
WHERE t2.t2c IS NULL;
Figure 687, Outer join, true if none match

SELECT *
FROM
table1
WHERE EXISTS
(SELECT
FROM
WHERE
SELECT *
FROM
table1
WHERE 1 <=
(SELECT
FROM
WHERE

t1
*
table2 t2
t1.t1a = t2.t2c);

ANSWER
=======
T1A T1B
--- --B
BB
C
CC

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

t1
COUNT(*)
table2 t2
t1.t1a = t2.t2c);

ANSWER
=======
T1A T1B
--- --A
AA

SELECT *
FROM
table1
WHERE t1a = ANY
(SELECT t2c
FROM
table2);
SELECT *
FROM
table1
WHERE t1a = SOME
(SELECT t2c
FROM
table2);
SELECT *
FROM
table1
WHERE t1a IN
(SELECT t2c
FROM
table2);
Figure 688, Sub-queries, true if any match

WITH t2 AS
(SELECT DISTINCT t2c
FROM
table2
)
SELECT t1.*

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |

FROM

table1 t1
,t2
WHERE t1.t1a = t2.t2c;

|B |BB |
|C |CC |
+-------+

SELECT t1.*
FROM
table1 t1
,(SELECT DISTINCT t2c
FROM
table2
)AS t2
WHERE
t1.t1a = t2.t2c;

|B |A | - |
+-----------+
"-" = null
ANSWER
=======
T1A T1B
--- --A
AA

SELECT t1.*
FROM
table1 t1
INNER JOIN
(SELECT
DISTINCT t2c
FROM
table2
)AS t2
ON
t1.t1a = t2.t2c;
Figure 689, Joins, true if any match

SELECT *
FROM
table1 t1
WHERE 10 =
(SELECT
COUNT(*)
FROM
table2 t2
WHERE
t1.t1a = t2.t2b);
SELECT *
FROM
table1
WHERE EXISTS
(SELECT
FROM
WHERE
GROUP BY
HAVING

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

t2b
table2
t1a = t2b
t2b
COUNT(*) = 10);

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null
ANSWER
======
0 rows

SELECT *
FROM
table1
WHERE t1a IN
(SELECT
t2b
FROM
table2
GROUP BY t2b
HAVING
COUNT(*) = 10);
Figure 690, Sub-queries, true if ten match (1 of 2)

SELECT *
FROM
table1
WHERE (t1a,10) IN
(SELECT
t2b, COUNT(*)
FROM
table2
GROUP BY t2b);
Figure 691, Sub-queries, true if ten match (2 of 2)

ANSWER
======
0 rows

WITH t2 AS
(SELECT
t2b
FROM
table2
GROUP BY t2b
HAVING
COUNT(*) = 10
)
SELECT t1.*
FROM
table1 t1
,t2
WHERE t1.t1a = t2.t2b;
SELECT t1.*
FROM
table1 t1
,(SELECT
FROM
GROUP BY
HAVING
)AS t2
WHERE
t1.t1a =

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null

ANSWER
======
0 rows

t2b
table2
t2b
COUNT(*) = 10
t2.t2b;

SELECT t1.*
FROM
table1 t1
INNER JOIN
(SELECT
t2b
FROM
table2
GROUP BY t2b
HAVING
COUNT(*) = 10
)AS t2
ON
t1.t1a = t2.t2b;
Figure 692, Joins, true if ten match

SELECT *
FROM
table1
WHERE t1a = ALL
(SELECT t2b
FROM
table2);
SELECT *
FROM
table1
WHERE NOT EXISTS
(SELECT *
FROM
table2
WHERE t1a <> t2b);

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

Figure 693, Sub-queries, true if all match, find rows

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null
ANSWER
=======
T1A T1B
--- --A
AA

SELECT *
FROM
table1
WHERE t1a = ALL
(SELECT t2b
FROM
table2
WHERE t2b >= 'X');

ANSWER
=======
T1A T1B
--- --A
AA
B
BB
C
CC

SELECT *
FROM
table1
WHERE NOT EXISTS
(SELECT *
FROM
table2
WHERE t1a <> t2b
AND t2b >= 'X');
Figure 694, Sub-queries, true if all match, empty set

SELECT *
FROM
table1
WHERE t1a = ALL
(SELECT t2b
FROM
table2
WHERE t2b >= 'X')
AND 0 <>
(SELECT COUNT(*)
FROM
table2
WHERE t2b >= 'X');

TABLE1
+-------+
|T1A|T1B|
|---|---|
|A |AA |
|B |BB |
|C |CC |
+-------+

TABLE2
+-----------+
|T2A|T2B|T2C|
|---|---|---|
|A |A |A |
|B |A | - |
+-----------+
"-" = null
ANSWER
======
0 rows

SELECT *
FROM
table1
WHERE t1a IN
(SELECT MAX(t2b)
FROM
table2
WHERE t2b >= 'X'
HAVING COUNT(DISTINCT t2b) = 1);
Figure 695, Sub-queries, true if all match, and at least one value found

R1
UNION
R2
R1
-A
A
A
B
B
C
C
C
E

R2
-A
A
B
B
B
C
D

----A
B
C
D
E

R1
UNION
ALL
R2
----A
A
A
A
A
B
B
B
B
B
C

R1
INTERSECT
R2
--------A
B
C

R1
INTERSECT
ALL
R2
----A
A
B
B
C

R1
EXCEPT
R2
-----E

R1
EXCEPT
ALL
R2
-----A
C
C
E

C
C
C
D
E
Figure 696, Examples of Union, Except, and Intersect

Figure 697, Union, Except, and Intersect syntax

CREATE VIEW
AS VALUES
CREATE VIEW
AS VALUES

R1 (R1)
('A'),('A'),('A'),('B'),('B'),('C'),('C'),('C'),('E');
R2 (R2)
('A'),('A'),('B'),('B'),('B'),('C'),('D');
ANSWER
======
SELECT
R1
R1 R2
FROM
R1
-- -ORDER BY R1;
A
A
A
A
SELECT
R2
A
B
FROM
R2
B
B
ORDER BY R2;
B
B
C
C
C
D
C
E
Figure 698, Query sample views

SELECT
FROM
UNION
SELECT
FROM
ORDER BY

R1
R1
R2
R2
1;

SELECT
R1
FROM
R1
UNION ALL
SELECT
R2
FROM
R2
ORDER BY 1;

Figure 699, Union and Union All SQL

R1
-A
A
A
B
B
C
C
C
E

R2
-A
A
B
B
B
C
D

UNION
=====
A
B
C
D
E

UNION ALL
=========
A
A
A
A
A
B
B
B
B
B
C
C
C
C
D
E

SELECT
R1
FROM
R1
INTERSECT
SELECT
R2
FROM
R2
ORDER BY 1;

R1
-A
A
A
B
B
C
C
C
E

R2
-A
A
B
B
B
C
D

INTERSECT
=========
A
B
C

SELECT
R1
FROM
R1
INTERSECT ALL
SELECT
R2
FROM
R2
ORDER BY 1;
Figure 700, Intersect and Intersect All SQL

SELECT
FROM
EXCEPT
SELECT
FROM
ORDER BY

R1
R1
R2
R2
1;

SELECT
R1
FROM
R1
EXCEPT ALL
SELECT
R2
FROM
R2
ORDER BY 1;
Figure 701,

SELECT
FROM
EXCEPT
SELECT
FROM
ORDER BY

R1 R2
-- -A
A
A
A
A
B
B
B
B
B
C
C
C
D
C
E
Except and Except All SQL (R1 on top)

R2
R2
R1
R1
1;

SELECT
R2
FROM
R2
EXCEPT ALL
SELECT
R1
FROM
R1
ORDER BY 1;
Figure 702,

R1 R2
-- -A
A
A
A
A
B
B
B
B
B
C
C
C
D
C
E
Except and Except All SQL (R2 on top)

INTERSECT ALL
=============
A
A
B
B
C

R1
EXCEPT
R2
=====
E

R1
EXCEPT ALL
R2
==========
A
C
C
E

R2
EXCEPT
R1
=====
D

R2
EXCEPT ALL
R1
==========
B
D

SELECT
FROM
UNION
SELECT
FROM
EXCEPT
SELECT
FROM
ORDER BY
ANSWER
======
E

R1
R1
R2
R2
R2
R2
1;

(SELECT
FROM
UNION
SELECT
FROM
)EXCEPT
SELECT
FROM
ORDER BY

R1
R1
R2
R2
R2
R2
1;

SELECT
FROM
UNION
(SELECT
FROM
EXCEPT
SELECT
FROM
)ORDER BY

R1
R1
R2
R2
R2
R2
1;

R1
-A
A
A
B
B
C
C
C
E

R2
-A
A
B
B
B
C
D

ANSWER
======
E

ANSWER
======
A
B
C
E
Figure 703, Use of parenthesis in Union

CREATE TABLE sales_data_2002


(sales_date
DATE
NOT NULL
,daily_seq#
INTEGER
NOT NULL
,cust_id
INTEGER
NOT NULL
,amount
DEC(10,2)
NOT NULL
,invoice#
INTEGER
NOT NULL
,sales_rep
CHAR(10)
NOT NULL
,CONSTRAINT C CHECK (YEAR(sales_date) = 2002)
,PRIMARY KEY (sales_date, daily_seq#));
CREATE TABLE sales_data_2003
(sales_date
DATE
NOT NULL
,daily_seq#
INTEGER
NOT NULL
,cust_id
INTEGER
NOT NULL
,amount
DEC(10,2)
NOT NULL
,invoice#
INTEGER
NOT NULL
,sales_rep
CHAR(10)
NOT NULL
,CONSTRAINT C CHECK (YEAR(sales_date) = 2003)
,PRIMARY KEY (sales_date, daily_seq#));
CREATE VIEW sales_data AS
SELECT *
FROM
sales_data_2002
UNION ALL
SELECT *
FROM
sales_data_2003;
Figure 704, Define view to combine yearly tables

INSERT INTO sales_data VALUES ('2002-11-22',1,123,100.10,996,'SUE')


,('2002-11-22',2,123,100.10,997,'JOHN')
,('2003-01-01',1,123,100.10,998,'FRED')
,('2003-01-01',2,123,100.10,999,'FRED');

UPDATE sales_data
SET
amount = amount / 2
WHERE sales_rep = 'JOHN';
DELETE
FROM
WHERE
AND
Figure

sales_data
sales_date = '2003-01-01'
daily_seq# = 2;
705, Insert, update, and delete using view

SALES_DATE DAILY_SEQ# CUST_ID AMOUNT INVOICE# SALES_REP


---------- ---------- ------- ------ -------- --------01/01/2003
1
123 100.10
998 FRED
11/22/2002
1
123 100.10
996 SUE
11/22/2002
2
123
50.05
997 JOHN
Figure 706, View contents after insert, update, delete

CREATE TABLE staff_summary AS


(SELECT
dept
,COUNT(*) AS count_rows
,SUM(id) AS sum_id
FROM
staff
GROUP BY dept)
DATA INITIALLY DEFERRED REFRESH IMMEDIATE;
Figure 707, Sample materialized query table DDL

ORIGINAL QUERY
OPTIMIZED QUERY
==============
=================================
SELECT
dept
SELECT Q1.dept AS "dept"
,AVG(id)
,Q1.sum_id / Q1.count_rows
FROM
staff
FROM
staff_summary AS Q1
GROUP BY dept
Figure 708, Original and optimized queries

Figure 709, Materialized query table DDL, syntax diagram

MATERIALIZED QUERY TABLE


==========================

ALLOWABLE ACTIONS ON TABLE


=====================================

REFRESH
=========
DEFERRED

MAINTAINED BY
REFRESH TABLE
INSERT/UPDATE/DELETE
=============
=============
====================
SYSTEM
yes
no
USER
no
yes
IMMEDIATE
SYSTEM
yes
no
Figure 710, Materialized query table options vs. allowable actions

UPDATE DATABASE CONFIGURATION USING dft_refresh_age ANY;


Figure 711, Changing default refresh age for database

Figure 712, Set refresh age command, syntax

SET CURRENT
SET CURRENT
SET CURRENT
Figure 713,

REFRESH AGE
0;
REFRESH AGE = ANY;
REFRESH AGE = 99999999999999;
Set refresh age command, examples

UPDATE DATABASE CONFIGURATION USING dft_refresh_age ANY;


Figure 714, Changing default maintained type for database

Figure 715,Set maintained type command, syntax

SET CURRENT
SET CURRENT
SET CURRENT
Figure 716,

MAINTAINED
TYPES
= ALL;
MAINTAINED TABLE TYPES
= SYSTEM;
MAINTAINED TABLE TYPES FOR OPTIMIZATION = USER, SYSTEM;
Set maintained type command, examples

UPDATE DATABASE CONFIGURATION USING DFT_QUERYOPT 5;

Figure 717, Changing default maintained type for database

Figure 718,Set maintained type command, syntax

SET CURRENT QUERY OPTIMIZATION = 9;


Figure 719, Set query optimization, example

MQT DEFINITION
DATABASE/APPLICATION STATUS
DB2
==========================
===================================
USE
REFRESH
MAINTAINED-BY
REFRESH-AGE
MAINTAINED-TYPE
MQT
=========
==============
===========
=====================
===
IMMEDIATE
SYSTEM
Yes
DEFERRED
SYSETM
ANY
ALL or SYSTEM
Yes
DEFERRED
USER
ANY
ALL or USER
Yes
DEFERRED
FEDERATED-TOOL
ANY
ALL or FEDERATED-TOOL
Yes
Figure 720, When DB2 will consider using a materialized query table

SELECT

CURRENT REFRESH AGE


AS age_ts
,CURRENT TIMESTAMP
AS current_ts
,CURRENT QUERY OPTIMIZATION
AS q_opt
FROM
sysibm.sysdummy1;
Figure 721, Selecting special registers

CREATE TABLE staff_names AS


(SELECT
dept
,COUNT(*)
AS
,SUM(salary)
AS
,AVG(salary)
AS
,MAX(salary)
AS
,MIN(salary)
AS
,STDDEV(salary)
AS
,VARIANCE(salary) AS
,CURRENT TIMESTAMP AS
FROM
staff
WHERE
TRANSLATE(name) LIKE
AND
salary
>
GROUP BY dept
HAVING
COUNT(*) = 1

count_rows
sum_salary
avg_salary
max_salary
min_salary
std_salary
var_salary
last_change
'%A%'
10000

)DATA INITIALLY DEFERRED REFRESH DEFERRED;


Figure 722, Refresh deferred materialized query table DDL

CREATE TABLE emp_summary AS


(SELECT
emp.workdept
,COUNT(*)
AS num_rows
,COUNT(emp.salary) AS num_salary
,SUM(emp.salary)
AS sum_salary
,COUNT(emp.comm)
AS num_comm
,SUM(emp.comm)
AS sum_comm
FROM
employee emp
GROUP BY emp.workdept
)DATA INITIALLY DEFERRED REFRESH IMMEDIATE;
Figure 723, Refresh immediate materialized query table DDL

SELECT

emp.workdept
,DEC(SUM(emp.salary),8,2)
AS sum_sal
,DEC(AVG(emp.salary),7,2)
AS avg_sal
,SMALLINT(COUNT(emp.comm)) AS #comms
,SMALLINT(COUNT(*))
AS #emps
FROM
employee emp
WHERE
emp.workdept
> 'C'
GROUP BY emp.workdept
HAVING
COUNT(*)
<> 5
AND
SUM(emp.salary) > 50000
ORDER BY sum_sal DESC;
Figure 724, Query that uses materialized query table (1 of 3)

SELECT

emp.workdept
,COUNT(*)
AS #rows
FROM
employee emp
WHERE
emp.workdept IN
(SELECT deptno
FROM
department
WHERE deptname LIKE '%S%')
GROUP BY emp.workdept
HAVING
SUM(salary) > 50000;
Figure 725, Query that uses materialized query table (2 of 3)

SELECT
FROM

#emps
,DEC(SUM(sum_sal),9,2)
,SMALLINT(COUNT(*))
(SELECT
emp.workdept

AS sal_sal
AS #depts

,DEC(SUM(emp.salary),8,2)
AS sum_sal
,MAX(emp.salary)
AS max_sal
,SMALLINT(COUNT(*))
AS #emps
FROM
employee emp
GROUP BY emp.workdept
)AS XXX
GROUP BY #emps
HAVING
COUNT(*) > 1
ORDER BY #emps
FETCH FIRST 3 ROWS ONLY
OPTIMIZE FOR 3 ROWS;
Figure 726, Query that uses materialized query table (3 of 3)

CREATE TABLE staff_all


(id
SMALLINT
NOT NULL
,name
VARCHAR(9)
NOT NULL
,job
CHAR(5)
,salary
DECIMAL(7,2)
,PRIMARY KEY(id));
Figure 727, Create source table

CREATE TABLE staff_all_dup AS


(SELECT *
FROM
staff_all)
DATA INITIALLY DEFERRED REFRESH IMMEDIATE;
Figure 728, Create duplicate data table

CREATE TABLE staff_all_dup_some AS


(SELECT *
FROM
staff_all
WHERE
id < 30)
DATA INITIALLY DEFERRED REFRESH IMMEDIATE;
Figure 729, Create table - duplicate certain rows only

CREATE TABLE staff_to_fire


(id
SMALLINT
NOT NULL
,name
VARCHAR(9)
NOT NULL
,dept
SMALLINT
,PRIMARY KEY(id));
Figure 730, Create source table

CREATE TABLE staff_combo AS


(SELECT aaa.id
AS id1
,aaa.job
AS job
,fff.id
as id2
,fff.dept
AS dept
FROM
staff_all
aaa
,staff_to_fire fff
WHERE
aaa.id = fff.id)
DATA INITIALLY DEFERRED REFRESH IMMEDIATE;
Figure 731, Materialized query table on join

SELECT

emp.workdept
,DEC(SUM(emp.salary),8,2)
AS sum_sal
,MAX(emp.salary)
AS max_sal
FROM
employee emp
GROUP BY emp.workdept;
Figure 732, Query that doesn't use materialized query table (1 of 2)

SELECT

emp.workdept
,DEC(SUM(emp.salary),8,2)
AS sum_sal
,COUNT(DISTINCT salary)
AS #salaries
FROM
employee emp
GROUP BY emp.workdept;
Figure 733, Query that doesn't use materialized query table (2 of 2)

REFRESH TABLE emp_summary;


COMMIT;
SET INTEGRITY FOR emp_summary iMMEDIATE CHECKED;
COMMIT;
Figure 734, Materialized query table refresh commands

CREATE TABLE dept_emp_summary AS


(SELECT
emp.workdept
,dpt.deptname
,COUNT(*)
AS
,COUNT(emp.salary) AS
,SUM(emp.salary)
AS
,COUNT(emp.comm)
AS
,SUM(emp.comm)
AS

num_rows
num_salary
sum_salary
num_comm
sum_comm

FROM

employee
emp
,department dpt
WHERE
dpt.deptno = emp.workdept
GROUP BY emp.workdept
,dpt.deptname
)DATA INITIALLY DEFERRED REFRESH IMMEDIATE;
Figure 735, Multi-table materialized query table DDL

SELECT

d.deptname
,d.deptno
,DEC(AVG(e.salary),7,2)
AS avg_sal
,SMALLINT(COUNT(*))
AS #emps
FROM
department d
,employee
e
WHERE
e.workdept
= d.deptno
AND
d.deptname LIKE '%S%'
GROUP BY d.deptname
,d.deptno
HAVING
SUM(e.comm)
> 4000
ORDER BY avg_sal DESC;
Figure 736, Query that uses materialized query table

SELECT

FROM

Q2.$C0
,Q2.$C1
,Q2.$C2
,Q2.$C3
(SELECT

AS
AS
AS
AS

"deptname"
"deptno"
"avg_sal"
"#emps"
Q1.deptname
,Q1.workdept
,DEC((Q1.sum_salary / Q1.num_salary),7,2)
,SMALLINT(Q1.num_rows)
dept_emp_summary AS Q1
(Q1.deptname LIKE '%S%')
(4000 < Q1.sum_comm)

AS
AS
AS
AS

FROM
WHERE
AND
)AS Q2
ORDER BY Q2.$C2 DESC;
Figure 737, DB2 generated query to use materialized query table

$C0
$C1
$C2
$C3

CREATE TABLE dpt_emp_act_sumry


(SELECT
emp.workdept
,dpt.deptname
,emp.empno
,emp.firstnme
,SUM(act.emptime)
,COUNT(act.emptime)
,COUNT(*)
FROM
department dpt
,employee
emp
,emp_act
act

AS

AS sum_time
AS num_time
AS num_rows

WHERE
dpt.deptno = emp.workdept
AND
emp.empno = act.empno
GROUP BY emp.workdept
,dpt.deptname
,emp.empno
,emp.firstnme
)DATA INITIALLY DEFERRED REFRESH IMMEDIATE;
Figure 738, Three-table materialized query table DDL

SELECT

d.deptno
,d.deptname
,DEC(AVG(a.emptime),5,2) AS avg_time
FROM
department d
,employee
e
,emp_act
a
WHERE
d.deptno
= e.workdept
AND
e.empno
= a.empno
AND
d.deptname LIKE '%S%'
AND
e.firstnme LIKE '%S%'
GROUP BY d.deptno
,d.deptname
ORDER BY 3 DESC;
Figure 739, Query that uses materialized query table

SELECT

Q4.$C0 AS "deptno"
,Q4.$C1 AS "deptname"
,Q4.$C2 AS "avg_time"
FROM
(SELECT
Q3.$C3
AS $C0
,Q3.$C2
AS $C1
,DEC((Q3.$C1 / Q3.$C0),5,2) AS $C2
FROM
(SELECT
SUM(Q2.$C2)
AS $C0
,SUM(Q2.$C3)
AS $C1
,Q2.$C0
AS $C2
,Q2.$C1
AS $C3
FROM
(SELECT
Q1.deptname
AS $C0
,Q1.workdept
AS $C1
,Q1.num_time
AS $C2
,Q1.sum_time
AS $C3
FROM
dpt_emp_act_sumry AS Q1
WHERE
(Q1.firstnme LIKE '%S%')
AND
(Q1.DEPTNAME LIKE '%S%')
)AS Q2
GROUP BY Q2.$C1
,Q2.$C0
)AS Q3
)AS Q4
ORDER BY Q4.$C2 DESC;
Figure 740, DB2 generated query to use materialized query table

CREATE INDEX dpt_emp_act_sumx1


ON dpt_emp_act_sumry
(workdept
,deptname
,empno
,firstnme);
CREATE INDEX dpt_emp_act_sumx2
ON dpt_emp_act_sumry
(num_rows);
Figure 741, Indexes for DPT_EMP_ACT_SUMRY materialized query table

SELECT

d.deptno
,d.deptname
,e.empno
,e.firstnme
,INT(AVG(a.emptime)) AS avg_time
FROM
department d
,employee
e
,emp_act
a
WHERE
d.deptno
= e.workdept
AND
e.empno
= a.empno
AND
d.deptno LIKE 'D%'
GROUP BY d.deptno
,d.deptname
,e.empno
,e.firstnme
ORDER BY 1,2,3,4;
Figure 742, Sample query that use WORKDEPT index

SELECT

d.deptno
,d.deptname
,e.empno
,e.firstnme
,COUNT(*)
AS #acts
FROM
department d
,employee
e
,emp_act
a
WHERE
d.deptno
= e.workdept
AND
e.empno
= a.empno
GROUP BY d.deptno
,d.deptname
,e.empno
,e.firstnme
HAVING
COUNT(*) > 4
ORDER BY 1,2,3,4;
Figure 743, Sample query that uses NUM_ROWS index

CREATE TABLE emp_sum AS


(SELECT
workdept
,job
,SUM(salary)
AS sum_sal
,COUNT(*)
AS #emps
,GROUPING(workdept) AS grp_dpt
,GROUPING(job)
AS grp_job
FROM
employee
GROUP BY CUBE(workdept
,job))
DATA INITIALLY DEFERRED REFRESH DEFERRED
ORGANIZE BY DIMENSIONS (workdept, job)
IN tsempsum;
Figure 744, Materialized query table organized by dimensions

CREATE TABLE emp_sumry AS


(SELECT
workdept
AS dept
,COUNT(*)
AS #rows
,COUNT(salary)
AS #sal
,SUM(salary)
AS sum_sal
FROM
employee emp
GROUP BY emp.workdept
)DATA INITIALLY DEFERRED REFRESH DEFERRED;
Figure 745, Sample materialized query table

CREATE TABLE emp_sumry_s


(dept
,num_rows
,num_sal
,sum_sal
,GLOBALTRANSID
,GLOBALTRANSTIME
)FOR emp_sumry PROPAGATE IMMEDIATE;
Figure 746, Staging table for the above materialized query table

SET INTEGRITY FOR emp_sumry_s STAGING IMMEDIATE UNCHECKED;


REFRESH TABLE emp_sumry;
<< make changes to the source table (i.e. employee) >>
REFRESH TABLE emp_sumry INCREMENTAL;
Figure 747, Enabling and the using a staging table

Figure 748, Identity Column syntax

CREATE TABLE invoice_data


(invoice#
INTEGER
NOT
GENERATED ALWAYS AS IDENTITY
(START WITH
1
,INCREMENT BY 1
,NO MAXVALUE
,NO CYCLE
,ORDER)
,sale_date
DATE
NOT
,customer_id
CHAR(20)
NOT
,product_id
INTEGER
NOT
,quantity
INTEGER
NOT
,price
DECIMAL(18,2)
NOT
,PRIMARY KEY
(invoice#));
Figure 749, Identity column, sample table

NULL

NULL
NULL
NULL
NULL
NULL

CREATE TABLE test_data


KEY# FIELD - VALUES ASSIGNED
(key# SMALLINT NOT NULL
============================
GENERATED ALWAYS AS IDENTITY
1 2 3 4 5 6 7 8 9 10 11 etc.
,dat1 SMALLINT NOT NULL
,ts1
TIMESTAMP NOT NULL
,PRIMARY KEY(key#));
Figure 750, Identity column, ascending sequence

CREATE TABLE test_data


KEY# FIELD - VALUES ASSIGNED
(key# SMALLINT NOT NULL
============================
GENERATED ALWAYS AS IDENTITY
6 3 0 -3 -6 -9 -12 -15 etc.
(START WITH
6
,INCREMENT BY -3
,NO CYCLE
,NO CACHE
,ORDER)
,dat1 SMALLINT NOT NULL
,ts1
TIMESTAMP NOT NULL
,PRIMARY KEY(key#));
Figure 751, Identity column, descending sequence

CREATE TABLE test_data


(key# SMALLINT NOT NULL
GENERATED ALWAYS AS IDENTITY

KEY# VALUES ASSIGNED


============================
123 123 123 123 123 123 etc.

(START WITH
123
,MAXVALUE
124
,INCREMENT BY 0
,NO CYCLE
,NO ORDER)
,dat1 SMALLINT NOT NULL
,ts1
TIMESTAMP NOT NULL);
Figure 752, Identity column, dumb sequence

CREATE TABLE test_data


KEY# VALUES ASSIGNED
(key# SMALLINT NOT NULL
============================
GENERATED ALWAYS AS IDENTITY
1 3 5 2 4 6 2 4 6 2 4 6 etc.
(START WITH
1
,INCREMENT BY 2
,MAXVALUE
6
,MINVALUE
2
,CYCLE
,NO CACHE
,ORDER)
,dat1 SMALLINT NOT NULL
,ts1
TIMESTAMP NOT NULL);
Figure 753, Identity column, odd values, then even, then stuck

CREATE TABLE invoice_data


(invoice#
INTEGER
NOT
GENERATED ALWAYS AS IDENTITY
(START WITH 100
,INCREMENT BY 1
,NO CYCLE
,ORDER)
,sale_date
DATE
NOT
,customer_id
CHAR(20)
NOT
,product_id
INTEGER
NOT
,quantity
INTEGER
NOT
,price
DECIMAL(18,2)
NOT
,PRIMARY KEY
(invoice#));
Figure 754, Identity column, definition

NULL

NULL
NULL
NULL
NULL
NULL

INSERT INTO invoice_data


VALUES (DEFAULT,'2001-11-22','ABC',123,100,10);
SELECT invoice#
FROM
FINAL TABLE
(INSERT INTO invoice_data
(sale_date,customer_id,product_id,quantity,price)
VALUES ('2002-11-22','DEF',123,100,10)
,('2003-11-22','GHI',123,100,10));
Figure 755, Invoice table, sample inserts

ANSWER
========
INVOICE#
-------101
102

INVOICE#
SALE_DATE
CUSTOMER_ID
PRODUCT_ID
----------------------------- -----100
2001-11-22
ABC
123
101
2002-11-22
DEF
123
102
2003-11-22
GHI
123
Figure 756, Invoice table, after inserts

QUANTITY
-------100
100
100

PRICE
----10.00
10.00
10.00

ALTER TABLE invoice_data


ALTER COLUMN invoice#
RESTART WITH 1000
SET INCREMENT BY 2;
Figure 757, Invoice table, restart identity column value

INSERT INTO invoice_data


VALUES (DEFAULT,'2004-11-24','XXX',123,100,10)
,(DEFAULT,'2004-11-25','YYY',123,100,10);
Figure 758, Invoice table, more sample inserts

INVOICE#
SALE_DATE
CUSTOMER_ID
PRODUCT_ID
-----------------------------------100
2001-11-22
ABC
123
101
2002-11-22
DEF
123
102
2003-11-22
GHI
123
1000
2004-11-24
XXX
123
1002
2004-11-25
YYY
123
Figure 759, Invoice table, after second inserts

QUANTITY
-------100
100
100
100
100

Figure 760, Identity Column alter syntax

CREATE TABLE customers


(cust#
INTEGER
NOT NULL
GENERATED ALWAYS AS IDENTITY (NO CACHE)

PRICE
----10.00
10.00
10.00
10.00
10.00

,cname
,ctype
,PRIMARY KEY
COMMIT;

CHAR(10)
CHAR(03)
(cust#));

NOT NULL
NOT NULL

SELECT cust#
FROM
FINAL TABLE
(INSERT INTO customers
VALUES (DEFAULT,'FRED','XXX'));
ROLLBACK;

ANSWER
======
CUST#
----1

SELECT cust#
FROM
FINAL TABLE
(INSERT INTO customers
VALUES (DEFAULT,'FRED','XXX'));
COMMIT;
Figure 761, Gaps in Values, example

ANSWER
======
CUST#
----2

SELECT

MIN(cust#) AS minc
,MAX(cust#) AS maxc
,COUNT(*)
AS rows
FROM
FINAL TABLE
(INSERT INTO customers
VALUES (DEFAULT,'FRED','xxx')
,(DEFAULT,'DAVE','yyy')
,(DEFAULT,'JOHN','zzz'));
Figure 762, Selecting identity column values inserted

CREATE TABLE invoice_table


(invoice#
INTEGER
NOT
GENERATED ALWAYS AS IDENTITY
,sale_date
DATE
NOT
,customer_id
CHAR(20)
NOT
,product_id
INTEGER
NOT
,quantity
INTEGER
NOT
,price
DECIMAL(18,2)
NOT
,PRIMARY KEY
(invoice#));
COMMIT;

ANSWER
==============
MINC MAXC ROWS
---- ---- ---3
5
3

NULL
NULL
NULL
NULL
NULL
NULL

INSERT INTO invoice_table


VALUES (DEFAULT,'2000-11-22','ABC',123,100,10);
WITH temp (id) AS
(VALUES (IDENTITY_VAL_LOCAL()))
SELECT *
FROM
temp;
COMMIT;
WITH temp (id) AS
(VALUES (IDENTITY_VAL_LOCAL()))
SELECT *
FROM
temp;

<<< ANSWER
======
ID
---1
<<< ANSWER
======
ID
----

Figure 763, IDENTITY_VAL_LOCAL function examples

INSERT INTO invoice_table


VALUES (DEFAULT,'2000-11-23','ABC',123,100,10);
INSERT INTO invoice_table
VALUES (DEFAULT,'2000-11-24','ABC',123,100,10)
,(DEFAULT,'2000-11-25','ABC',123,100,10);
SELECT

invoice#
AS inv#
,sale_date
,IDENTITY_VAL_LOCAL() AS id
FROM
invoice_table
ORDER BY 1;
COMMIT;
Figure 764, IDENTITY_VAL_LOCAL function examples

SELECT invoice#
AS inv#
,sale_date
,IDENTITY_VAL_LOCAL() AS id
FROM
invoice_table
WHERE id = IDENTITY_VAL_LOCAL();
Figure 765, IDENTITY_VAL_LOCAL usage in predicate

ANSWER
==================
INV# SALE_DATE ID
---- ---------- -1 11/22/2000 2
2 11/23/2000 2
3 11/24/2000 2
4 11/25/2000 2

ANSWER
==================
INV# SALE_DATE ID
---- ---------- -2 11/23/2000 2

CREATE SEQUENCE fred


AS DECIMAL(31)
START WITH 100
INCREMENT BY 2
NO MINVALUE
NO MAXVALUE
NO CYCLE
CACHE 20
ORDER;
Figure 766, Create sequence

SEQ# VALUES ASSIGNED


====================
100 102 104 106 etc.

ALTER SEQUENCE fred


RESTART WITH -55
INCREMENT BY -5
MINVALUE
-1000
MAXVALUE
+1000
NO CACHE
NO ORDER

SEQ# VALUES ASSIGNED


====================
-55 -60 -65 -70 etc.

CYCLE;
Figure 767, Alter sequence attributes

CREATE SEQUENCE biggest_sale_to_date


AS INTEGER
START WITH 345678
INCREMENT BY 0;
Figure 768, Sequence that doesn't change

SEQ# VALUES ASSIGNED


====================
345678, 345678, etc.

CREATE SEQUENCE fred;


COMMIT;

ANSWER
======
SEQ#
---1
2
3
4
5

WITH temp1 (n1) AS


(VALUES 1
UNION ALL
SELECT n1 + 1
FROM
temp1
WHERE n1 < 5
)
SELECT NEXTVAL FOR fred AS seq#
FROM
temp1;
Figure 769, Selecting the NEXTVAL

CREATE SEQUENCE fred;


COMMIT;

ANSWERS
=======

WITH temp1 (prv) AS


(VALUES (PREVVAL FOR fred))
SELECT *
FROM
temp1;

===>

PRV
---

WITH temp1 (nxt) AS


(VALUES (NEXTVAL FOR fred))
SELECT *
FROM
temp1;

===>

NXT
--1

WITH temp1 (prv) AS


(VALUES (PREVVAL FOR fred))
SELECT *
FROM
temp1;

===>

PRV
--1

WITH temp1 (n1) AS


(VALUES 1
UNION ALL
SELECT n1 + 1
FROM
temp1
WHERE n1 < 5
)

===>

NXT PRV
--- --2
1
3
1
4
1
5
1
6
1

SELECT NEXTVAL FOR fred AS nxt


,PREVVAL FOR fred AS prv
FROM
temp1;
Figure 770, Use of NEXTVAL and PREVVAL expressions

CREATE SEQUENCE fred;


COMMIT;

ANSWERS
=======

WITH temp1 AS
(SELECT
id
,NEXTVAL FOR fred AS nxt
FROM
staff
WHERE
id < 100
)
SELECT *
FROM
temp1
WHERE id = 50 + (nxt * 0);

===>

ID NXT
-- --50
5

WITH temp1 (nxt, prv) AS


(VALUES (NEXTVAL FOR fred
,PREVVAL FOR fred))
SELECT *
FROM
temp1;
Figure 771, NEXTVAL values used but not retrieved

===>

NXT PRV
--- --10
9

CREATE SEQUENCE cust#


START WITH
1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE
ORDER;
CREATE TABLE us_customer
(cust#
INTEGER
,cname
CHAR(10)
,frst_sale
DATE
,#sales
INTEGER
,PRIMARY KEY
(cust#));

NOT
NOT
NOT
NOT

NULL
NULL
NULL
NULL

CREATE TRIGGER us_cust_ins


NO CASCADE BEFORE INSERT ON us_customer
REFERENCING NEW AS nnn
FOR EACH ROW MODE DB2SQL
SET nnn.cust# = NEXTVAL FOR cust#;
CREATE TABLE intl_customer
(cust#
INTEGER
,cname
CHAR(10)
,frst_sale
DATE
,#sales
INTEGER
,PRIMARY KEY
(cust#));
CREATE TRIGGER intl_cust_ins

NOT
NOT
NOT
NOT

NULL
NULL
NULL
NULL

NO CASCADE BEFORE INSERT ON intl_customer


REFERENCING NEW AS nnn
FOR EACH ROW MODE DB2SQL
SET nnn.cust# = NEXTVAL FOR cust#;
Figure 772, Create tables that use a common sequence

SELECT

cust#
,cname
FROM
FINAL TABLE
(INSERT INTO us_customer (cname, frst_sale, #sales)
VALUES ('FRED','2002-10-22',1)
,('JOHN','2002-10-23',1));
cust#
,cname
FROM
FINAL TABLE
(INSERT INTO intl_customer (cname, frst_sale, #sales)
VALUES ('SUE','2002-11-12',2)
,('DEB','2002-11-13',2));
Figure 773, Insert into tables with common sequence

ANSWERS
===========
CUST# CNAME
----- ----1 FRED
2 JOHN

SELECT

WITH temp (prev) AS


(VALUES (PREVVAL FOR cust#))
SELECT *
FROM
temp;
Figure 774, Get previous value - select

VALUES PREVVAL FOR CUST# INTO :host-var


Figure 775, Get previous value - into host-variable

CREATE SEQUENCE delete_rows


START WITH
1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE
ORDER;
CREATE SEQUENCE delete_stmts
START WITH
1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE

CUST#
----3
4

CNAME
----SUE
DEB

ANSWER
======
PREV
---4

ORDER;
CREATE TABLE customer
(cust#
INTEGER
,cname
CHAR(10)
,frst_sale
DATE
,#sales
INTEGER
,PRIMARY KEY
(cust#));

NOT
NOT
NOT
NOT

NULL
NULL
NULL
NULL

CREATE TRIGGER cust_del_rows


AFTER DELETE ON customer
FOR EACH ROW MODE DB2SQL
WITH temp1 (n1) AS (VALUES(1))
SELECT NEXTVAL FOR delete_rows
FROM
temp1;
CREATE TRIGGER cust_del_stmts
AFTER DELETE ON customer
FOR EACH STATEMENT MODE DB2SQL
WITH temp1 (n1) AS (VALUES(1))
SELECT NEXTVAL FOR delete_stmts
FROM
temp1;
Figure 776, Count deletes done to table

CREATE TABLE sales_invoice


(invoice#
INTEGER
NOT NULL
,sale_date
DATE
NOT NULL
,customer_id
CHAR(20)
NOT NULL
,product_id
INTEGER
NOT NULL
,quantity
INTEGER
NOT NULL
,price
DECIMAL(18,2)
NOT NULL
,PRIMARY KEY
(invoice#));
Figure 777, Sample table, roll your own sequence#

CREATE TRIGGER sales_insert


NO CASCADE BEFORE
INSERT ON sales_invoice
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
SET nnn.invoice# =
(SELECT COALESCE(MAX(invoice#),0) + 1
FROM
sales_invoice);
Figure 778, Sample trigger, roll your own sequence#

INSERT INTO sales_invoice VALUES (0,'2001-06-22','ABC',123,10,1);


INSERT INTO sales_invoice VALUES (0,'2001-06-23','DEF',453,10,1);
COMMIT;

INSERT INTO sales_invoice VALUES (0,'2001-06-24','XXX',888,10,1);


ROLLBACK;
INSERT INTO sales_invoice VALUES (0,'2001-06-25','YYY',999,10,1);
COMMIT;
ANSWER
==============================================================
INVOICE# SALE_DATE
CUSTOMER_ID PRODUCT_ID QUANTITY PRICE
-------- ---------- ----------- ---------- -------- ----1 06/22/2001 ABC
123
10
1.00
2 06/23/2001 DEF
453
10
1.00
3 06/25/2001 YYY
999
10
1.00
Figure 779, Sample inserts, roll your own sequence#

CREATE TABLE control_table


(table_name
CHAR(18)
NOT NULL
,table_nmbr
INTEGER
NOT NULL
,PRIMARY KEY (table_name));
Figure 780, Control Table, DDL

INSERT
INSERT
INSERT
Figure

INTO
INTO
INTO
781,

control_table VALUES ('invoice_table',0);


control_table VALUES ('2nd_data_tble',0);
control_table VALUES ('3rd_data_tble',0);
Control Table, sample inserts

CREATE TABLE invoice_table


(unqval
CHAR(13) FOR BIT DATA
,invoice#
INTEGER
,sale_date
DATE
,customer_id
CHAR(20)
,product_id
INTEGER
,quantity
INTEGER
,price
DECIMAL(18,2)
,PRIMARY KEY(unqval));
Figure 782, Sample Data Table, DDL

CREATE TRIGGER invoice1


NO CASCADE BEFORE INSERT ON invoice_table
REFERENCING NEW AS nnn
FOR EACH ROW MODE DB2SQL
SET nnn.unqval
= GENERATE_UNIQUE()
,nnn.invoice# = NULL;

NOT NULL
NOT
NOT
NOT
NOT
NOT

NULL
NULL
NULL
NULL
NULL

Figure 783, Before trigger

CREATE TRIGGER invoice2


AFTER INSERT ON invoice_table
REFERENCING NEW AS nnn
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
UPDATE control_table
SET
table_nmbr = table_nmbr + 1
WHERE table_name = 'invoice_table';
UPDATE invoice_table
SET
invoice# =
(SELECT table_nmbr
FROM
control_table
WHERE table_name = 'invoice_table')
WHERE unqval
= nnn.unqval
AND invoice# IS NULL;
END
Figure 784, After trigger

CREATE TRIGGER invoice3


NO CASCADE BEFORE UPDATE OF invoice# ON invoice_table
REFERENCING OLD AS ooo
NEW AS nnn
FOR EACH ROW MODE DB2SQL
WHEN (ooo.invoice# <> nnn.invoice#)
SIGNAL SQLSTATE '71001' ('no updates allowed - you twit');
Figure 785, Update trigger

SELECT
FROM

id
,salary
(SELECT

s.*
,ROW_NUMBER() OVER(ORDER BY salary DESC) AS sorder
FROM
staff s
WHERE
id < 200
ANSWER
)AS xxx
=============
WHERE
sorder BETWEEN 2 AND 3
ID
SALARY
ORDER BY id;
--- -------50 20659.80
140 21150.00
Figure 786, Nested Table Expression

WITH xxx (id, salary, sorder) AS

(SELECT

ID
,salary
,ROW_NUMBER() OVER(ORDER BY salary DESC) AS sorder
FROM
staff
WHERE
id < 200
)
ANSWER
SELECT
id
=============
,salary
ID
SALARY
FROM
xxx
--- -------WHERE
sorder BETWEEN 2 AND 3
50 20659.80
ORDER BY id;
140 21150.00
Figure 787, Common Table Expression

WITH
ANSWER
rows_wanted AS
================================
(SELECT *
ID NAME
SALARY
SUM_SAL PCT
FROM
staff
-- ------- -------- -------- --WHERE
id
< 100
70 Rothman 16502.83 34504.58 47
AND
UCASE(name) LIKE '%T%'
90 Koonitz 18001.75 34504.58 52
),
sum_salary AS
(SELECT SUM(salary) AS sum_sal
FROM
rows_wanted)
SELECT
id
,name
,salary
,sum_sal
,INT((salary * 100) / sum_sal) AS pct
FROM
rows_wanted
,sum_salary
ORDER BY id;
Figure 788, Common Table Expression

DECLARE GLOBAL TEMPORARY TABLE session.fred


(dept
SMALLINT
NOT NULL
,avg_salary
DEC(7,2)
NOT NULL
,num_emps
SMALLINT
NOT NULL)
ON COMMIT PRESERVE ROWS;
COMMIT;
INSERT INTO session.fred
SELECT
dept
,AVG(salary)
,COUNT(*)
FROM
staff
WHERE
id > 200
GROUP BY dept;
COMMIT;
SELECT
FROM

COUNT(*) AS cnt
session.fred;

DELETE FROM session.fred

ANSWER#1
========
CNT
--4
ANSWER#2
==========================
DEPT AVG_SALARY NUM_EMPS

WHERE

dept > 80;

SELECT *
FROM
session.fred;
Figure 789, Declared Global Temporary Table

---10
51
66

---------20168.08
15161.43
17215.24

-------3
3
5

WITH staff_dept AS
ANSWER
(SELECT
dept
AS dept#
==========================
,MAX(salary) AS max_sal
ID DEPT SALARY
MAX_SAL
FROM
staff
--- ---- -------- -------WHERE
dept < 50
10
20 18357.50 18357.50
GROUP BY dept
190
20 14252.75 18357.50
)
200
42 11508.60 18352.80
SELECT
id
220
51 17654.50
,dept
,salary
,max_sal
FROM
staff
LEFT OUTER JOIN
staff_dept
ON
dept
= dept#
WHERE
name LIKE 'S%'
ORDER BY id;
Figure 790, Identical query (1 of 3) - using Common Table Expression

SELECT

id
,dept
,salary
,max_sal
FROM
staff
LEFT OUTER JOIN
(SELECT

ANSWER
==========================
ID DEPT SALARY
MAX_SAL
--- ---- -------- -------10
20 18357.50 18357.50
190
20 14252.75 18357.50
200
42 11508.60 18352.80
220
51 17654.50
-

SELECT

ANSWER
==========================
ID DEPT SALARY
MAX_SAL
--- ---- -------- -------10
20 18357.50 18357.50
190
20 14252.75 18357.50

dept
AS dept#
,MAX(salary) AS max_sal
FROM
staff
WHERE
dept < 50
GROUP BY dept
)AS STAFF_dept
ON
dept
= dept#
WHERE
name LIKE 'S%'
ORDER BY id;
Figure 791, Identical query (2 of 3) - using full-select in FROM

id
,dept
,salary
,(SELECT
FROM
WHERE

MAX(salary)
staff s2
s1.dept = s2.dept

AND
s2.dept < 50
200
42 11508.60 18352.80
GROUP BY dept)
220
51 17654.50
AS max_sal
FROM
staff s1
WHERE
name LIKE 'S%'
ORDER BY id;
Figure 792, Identical query (3 of 3) - using full-select in SELECT

Figure 793, Common Table Expression Syntax

WITH temp1 AS
ANSWER
(SELECT MAX(name) AS max_name
==================
,MAX(dept) AS max_dept
MAX_NAME MAX_DEPT
FROM
staff
--------- -------)
Yamaguchi
84
SELECT *
FROM
temp1;
Figure 794, Common Table Expression, using named fields

WITH temp1 (max_name,max_dept) AS


ANSWER
(SELECT MAX(name)
==================
,MAX(dept)
MAX_NAME MAX_DEPT
FROM
staff
--------- -------)
Yamaguchi
84
SELECT *
FROM
temp1;
Figure 795, Common Table Expression, using unnamed fields

WITH
temp1 AS
(SELECT

dept
,AVG(salary) AS avg_sal
FROM
staff
GROUP BY dept),
temp2 AS
(SELECT
MAX(avg_sal) AS max_avg
FROM
temp1)
SELECT *
FROM
temp2;
Figure 796, Query with two common table expressions

ANSWER
==========
MAX_AVG
---------20865.8625

SELECT *
ANSWER
FROM (SELECT MAX(avg_sal) AS max_avg
==========
FROM (SELECT dept
MAX_AVG
,AVG(salary) AS avg_sal
---------FROM
staff
20865.8625
GROUP BY dept
)AS temp1
)AS temp2;
Figure 797, Same as prior example, but using nested table expressions

WITH temp1 AS
(SELECT
id
,name
,dept
,salary
FROM
staff
WHERE
id
< 300
AND
dept
<> 55
AND
name LIKE 'S%'
AND
dept NOT IN
(SELECT deptnumb
FROM
org
WHERE division = 'SOUTHERN'
OR location = 'HARTFORD')
)
,temp2 AS
(SELECT
dept
,MAX(salary) AS max_sal
FROM
temp1
GROUP BY dept
)
SELECT
t1.id
,t1.dept
,t1.salary
,t2.max_sal
FROM
temp1 t1
,temp2 t2
WHERE
t1.dept = t2.dept
ORDER BY t1.id;
Figure 798, Deriving second temporary table

ANSWER
==========================
ID DEPT SALARY
MAX_SAL
--- ---- -------- -------10
20 18357.50 18357.50
190
20 14252.75 18357.50
200
42 11508.60 11508.60
220
51 17654.50 17654.50

from first

INSERT INTO staff


WITH temp1 (max1) AS
(SELECT MAX(id) + 1
FROM
staff
)
SELECT max1,'A',1,'B',2,3,4
FROM
temp1;
Figure 799, Insert using common table expression

INSERT INTO staff


SELECT MAX(id) + 1
,'A',1,'B',2,3,4
FROM
staff;
Figure 800, Equivalent insert (to above) without common table expression

SELECT

division
,DEC(AVG(dept_avg),7,2) AS div_dept
,COUNT(*)
AS #dpts
,SUM(#emps)
AS #emps
FROM
(SELECT
division
,dept
,AVG(salary) AS dept_avg
,COUNT(*)
AS #emps
FROM
staff
ANSWER
,org
==============================
WHERE
dept = deptnumb
DIVISION DIV_DEPT #DPTS #EMPS
GROUP BY division
--------- -------- ----- ----,dept
Corporate 20865.86
1
4
)AS xxx
Eastern
15670.32
3
13
GROUP BY division;
Midwest
15905.21
2
9
Western
16875.99
2
9
Figure 801, Nested column function usage

SELECT id
FROM (SELECT *
FROM (SELECT id, years, salary
FROM (SELECT *
FROM
(SELECT *
FROM
staff
WHERE dept < 77
)AS t1
WHERE id < 300
)AS t2
WHERE job LIKE 'C%'
)AS t3
WHERE salary < 18000
)AS t4
WHERE years < 5;
Figure 802, Nested full-selects

SELECT

a.id
,a.dept

ANSWER
======
ID
--170
180
230

ANSWER
=========================

,a.salary
,DEC(b.avgsal,7,2) AS avg_dept
FROM
staff a
LEFT OUTER JOIN
(SELECT
dept
AS dept
,AVG(salary) AS avgsal
FROM
staff
GROUP BY dept
HAVING
AVG(salary) > 16000
)AS b
ON
a.dept = b.dept
WHERE
a.id
< 40
ORDER BY a.id;
Figure 803, Join full-select to real table

ID DEPT SALARY AVG_DEPT


-- ---- -------- -------10
20 18357.50 16071.52
20
20 18171.25 16071.52
30
38 17506.75
-

SELECT

a.id
ANSWER
,a.dept
=========================
,a.salary
ID DEPT SALARY
DEPTSAL
,b.deptsal
-- ---- -------- -------FROM
staff a
10 20
18357.50 64286.10
,TABLE
20 20
18171.25 64286.10
(SELECT
b.dept
30 38
17506.75 77285.55
,SUM(b.salary) AS deptsal
FROM
staff b
WHERE
b.dept = a.dept
GROUP BY b.dept
)AS b
WHERE
a.id
< 40
ORDER BY a.id;
Figure 804, Full-select with external table reference

SELECT

a.id
ANSWER
,a.dept
=========================
,a.salary
ID DEPT SALARY
DEPTSAL
,b.deptsal
-- ---- -------- -------FROM
staff a
10 20
18357.50 64286.10
,(SELECT
b.dept
20 20
18171.25 64286.10
,SUM(b.salary) AS deptsal
30 38
17506.75 77285.55
FROM
staff b
GROUP BY b.dept
)AS b
WHERE
a.id
< 40
AND
b.dept = a.dept
ORDER BY a.id;
Figure 805, Full-select without external table reference

SELECT

id
,salary

ANSWER
====================

,(SELECT MAX(salary)
FROM
staff
) AS maxsal
FROM
staff a
WHERE
id < 60
ORDER BY id;

ID SALARY
-- -------10 18357.50
20 18171.25
30 17506.75
40 18006.00
50 20659.80
Figure 806, Use an uncorrelated Full-Select in a SELECT list

MAXSAL
-------22959.20
22959.20
22959.20
22959.20
22959.20

SELECT

id
ANSWER
,salary
====================
,(SELECT MAX(salary)
ID SALARY
MAXSAL
FROM
staff b
-- -------- -------WHERE a.dept = b.dept
10 18357.50 18357.50
) AS maxsal
20 18171.25 18357.50
FROM
staff a
30 17506.75 18006.00
WHERE
id < 60
40 18006.00 18006.00
ORDER BY id;
50 20659.80 20659.80
Figure 807, Use a correlated Full-Select in a SELECT list

SELECT id
ANSWER
,dept
==================================
,salary
ID DEPT SALARY 4
5
,(SELECT MAX(salary)
-- ---- -------- -------- -------FROM
staff b
10
20 18357.50 18357.50 22959.20
WHERE b.dept = a.dept)
20
20 18171.25 18357.50 22959.20
,(SELECT MAX(salary)
30
38 17506.75 18006.00 22959.20
FROM
staff)
40
38 18006.00 18006.00 22959.20
FROM
staff a
50
15 20659.80 20659.80 22959.20
WHERE id < 60
ORDER BY id;
Figure 808, Use correlated and uncorrelated Full-Selects in a SELECT list

INSERT INTO staff


SELECT id + 1
,(SELECT MIN(name)
FROM
staff)
,(SELECT dept
FROM
staff s2
WHERE s2.id = s1.id - 100)
,'A',1,2,3
FROM
staff s1
WHERE
id =
(SELECT MAX(id)
FROM
staff);
Figure 809, Full-select in INSERT

UPDATE staff a
SET
salary =
(SELECT AVG(salary)+ 2000
FROM
staff)
WHERE id < 60;

ANSWER:
SALARY
======= =================
ID DEPT BEFORE
AFTER
-- ---- -------- -------10
20 18357.50 18675.64
20
20 18171.25 18675.64
30
38 17506.75 18675.64
40
38 18006.00 18675.64
50
15 20659.80 18675.64
Figure 810, Use uncorrelated Full-Select to give workers company AVG salary (+$2000)

UPDATE staff a
SET
salary =
(SELECT AVG(salary) + 2000
FROM
staff b
WHERE a.dept = b.dept )
WHERE id < 60;

ANSWER:
SALARY
======= =================
ID DEPT BEFORE
AFTER
-- ---- -------- -------10
20 18357.50 18071.52
20
20 18171.25 18071.52
30
38 17506.75 17457.11
40
38 18006.00 17457.11
50
15 20659.80 17482.33
Figure 811, Use correlated Full-Select to give workers department AVG salary (+
$2000)

UPDATE staff a
SET
(salary,years) =
(SELECT AVG(salary) + 2000
,MAX(years)
FROM
staff b
WHERE a.dept = b.dept )
WHERE id < 60;
Figure 812, Update two fields by referencing Full-Select

Figure 813, Declared Global Temporary Table syntax

DECLARE GLOBAL TEMPORARY TABLE session.fred


(dept
SMALLINT
NOT NULL
,avg_salary
DEC(7,2)
NOT NULL
,num_emps
SMALLINT
NOT NULL)
ON COMMIT DELETE ROWS;

Figure 814, Declare Global Temporary Table - define columns

DECLARE GLOBAL TEMPORARY TABLE session.fred


LIKE staff INCLUDING COLUMN DEFAULTS
WITH REPLACE
ON COMMIT PRESERVE ROWS;
Figure 815, Declare Global Temporary Table - like another table

DECLARE GLOBAL TEMPORARY TABLE session.fred AS


(SELECT
dept
,MAX(id)
AS max_id
,SUM(salary) AS sum_sal
FROM
staff
WHERE
name <> 'IDIOT'
GROUP BY dept)
DEFINITION ONLY
WITH REPLACE;
Figure 816, Declare Global Temporary Table - like query output

DECLARE GLOBAL TEMPORARY TABLE session.fred


LIKE staff INCLUDING COLUMN DEFAULTS
WITH REPLACE ON COMMIT DELETE ROWS;
CREATE UNIQUE INDEX session.fredx ON Session.fred (id);
INSERT INTO session.fred
SELECT
*
FROM
staff
WHERE
id < 200;
SELECT
FROM

COUNT(*)
session.fred;

COMMIT;
SELECT COUNT(*)
FROM
session.fred;
Figure 817, Temporary table with index

DECLARE GLOBAL TEMPORARY TABLE session.fred


(dept
SMALLINT
NOT NULL
,avg_salary
DEC(7,2)
NOT NULL
,num_emps
SMALLINT
NOT NULL)

ANSWER
======
19
ANSWER
======
0

ON COMMIT DELETE ROWS;


INSERT INTO session.fred
SELECT
dept
,AVG(salary)
,COUNT(*)
FROM
staff
GROUP BY dept;
SELECT
FROM

ANSWER
======
8

COUNT(*)
session.fred;

DROP TABLE session.fred;


DECLARE GLOBAL TEMPORARY TABLE session.fred
(dept
SMALLINT
NOT NULL)
ON COMMIT DELETE ROWS;

ANSWER
======
0

SELECT COUNT(*)
FROM
session.fred;
Figure 818, Dropping a temporary table

CREATE USER TEMPORARY TABLESPACE FRED


MANAGED BY DATABASE
USING (FILE 'C:\DB2\TEMPFRED\FRED1' 1000
,FILE 'C:\DB2\TEMPFRED\FRED2' 1000
,FILE 'C:\DB2\TEMPFRED\FRED3' 1000);
GRANT USE OF TABLESPACE FRED TO PUBLIC;
Figure 819, Create USER TEMPORARY tablespace

HIERARCHY
+---------------+
|PKEY |CKEY |NUM|
|-----|-----|---|
|AAA |BBB | 1|
|AAA |CCC | 5|
|AAA |DDD | 20|
|CCC |EEE | 33|
|DDD |EEE | 44|
|DDD |FFF | 5|
|FFF |GGG | 5|
+---------------+
Figure 820, Sample Table description - Recursion

WITH parent (pkey, ckey) AS


(SELECT pkey, ckey
FROM
hierarchy

AAA
|
+-----+-----+
|
|
|
BBB
CCC
DDD
|
|
+-+ +-+--+
| |
|
EEE
FFF
|
|
GGG

ANSWER
=========
PKEY CKEY

PROCESSING
SEQUENCE

WHERE pkey = 'AAA'


UNION ALL
SELECT C.pkey, C.ckey
FROM
hierarchy C
,parent
P
WHERE P.ckey = C.pkey
)
SELECT pkey, ckey
FROM
parent;
Figure 821, SQL that does Recursion

---AAA
AAA
AAA
CCC
DDD
DDD
FFF

---BBB
CCC
DDD
EEE
EEE
FFF
GGG

==========
< 1st pass
""
""
< 2nd pass
< 3rd pass
""
< 4th pass

Figure 822, Recursive processing sequence

CREATE TABLE hierarchy


(pkey
CHAR(03)
NOT NULL
,ckey
CHAR(03)
NOT NULL
,num
SMALLINT
NOT NULL
,PRIMARY KEY(pkey, ckey)
,CONSTRAINT dt1 CHECK (pkey <> ckey)
,CONSTRAINT dt2 CHECK (num
> 0));
COMMIT;
CREATE UNIQUE INDEX hier_x1 ON hierarchy
(ckey, pkey);
COMMIT;
INSERT INTO hierarchy VALUES
('AAA','BBB', 1),
('AAA','CCC', 5),
('AAA','DDD',20),
('CCC','EEE',33),
('DDD','EEE',44),
('DDD','FFF', 5),
('FFF','GGG', 5);
COMMIT;
Figure 823, Sample Table DDL - Recursion

WITH parent (ckey) AS


(SELECT ckey
FROM
hierarchy
WHERE pkey = 'AAA'
UNION ALL
SELECT C.ckey
FROM
hierarchy C
,parent
P
WHERE P.ckey = C.pkey
)
SELECT ckey

ANSWER
======
CKEY
---BBB
CCC
DDD
EEE
EEE
FFF
GGG

HIERARCHY
+---------------+
|PKEY |CKEY |NUM|
|-----|-----|---|
|AAA |BBB | 1|
|AAA |CCC | 5|
|AAA |DDD | 20|
|CCC |EEE | 33|
|DDD |EEE | 44|
|DDD |FFF | 5|
|FFF |GGG | 5|

FROM
parent;
Figure 824, List of children of AAA

+---------------+

WITH parent (ckey) AS


(SELECT DISTINCT pkey
FROM
hierarchy
WHERE pkey = 'AAA'
UNION ALL
SELECT C.ckey
FROM
hierarchy C
,parent
P
WHERE P.ckey = C.pkey
)
SELECT ckey
FROM
parent;
Figure 825, List all children of AAA

ANSWER
======
CKEY
---AAA
BBB
CCC
DDD
EEE
EEE
FFF
GGG

HIERARCHY
+---------------+
|PKEY |CKEY |NUM|
|-----|-----|---|
|AAA |BBB | 1|
|AAA |CCC | 5|
|AAA |DDD | 20|
|CCC |EEE | 33|
|DDD |EEE | 44|
|DDD |FFF | 5|
|FFF |GGG | 5|
+---------------+

WITH parent (ckey) AS


(SELECT DISTINCT pkey
FROM
hierarchy
WHERE pkey = 'AAA'
UNION ALL
SELECT C.ckey
FROM
hierarchy C
,parent
P
WHERE P.ckey = C.pkey
)
SELECT DISTINCT ckey
FROM
parent;
Figure 826, List distinct children of AAA

ANSWER
======
CKEY
---AAA
BBB
CCC
DDD
EEE
FFF
GGG

HIERARCHY
+---------------+
|PKEY |CKEY |NUM|
|-----|-----|---|
|AAA |BBB | 1|
|AAA |CCC | 5|
|AAA |DDD | 20|
|CCC |EEE | 33|
|DDD |EEE | 44|
|DDD |FFF | 5|
|FFF |GGG | 5|
+---------------+

WITH parent (ckey) AS


(SELECT DISTINCT pkey
FROM
hierarchy
WHERE pkey = 'AAA'
UNION ALL
SELECT C.ckey
FROM
hierarchy C
,parent
P
WHERE P.ckey = C.pkey
),
distinct_parent (ckey) AS
(SELECT DISTINCT ckey
FROM
parent
)
SELECT ckey
FROM
distinct_parent;
Figure 827, List distinct children of AAA

ANSWER
======
CKEY
---AAA
BBB
CCC
DDD
EEE
FFF
GGG

HIERARCHY
+---------------+
|PKEY |CKEY |NUM|
|-----|-----|---|
|AAA |BBB | 1|
|AAA |CCC | 5|
|AAA |DDD | 20|
|CCC |EEE | 33|
|DDD |EEE | 44|
|DDD |FFF | 5|
|FFF |GGG | 5|
+---------------+

WITH parent (ckey, lvl) AS


(SELECT DISTINCT pkey, 0
FROM
hierarchy
WHERE pkey = 'AAA'
UNION ALL
SELECT C.ckey, P.lvl +1
FROM
hierarchy C
,parent
P
WHERE P.ckey = C.pkey
)
SELECT ckey, lvl
FROM
parent;
Figure 828, Show item level in hierarchy

WITH parent (ckey, lvl) AS


(SELECT DISTINCT pkey, 0
FROM
hierarchy
WHERE pkey = 'AAA'
UNION ALL
SELECT C.ckey, P.lvl +1
FROM
hierarchy C
,parent
P
WHERE P.ckey = C.pkey
)
SELECT ckey, lvl
FROM
parent
WHERE lvl < 3;
Figure 829, Select rows where LEVEL < 3

WITH parent (ckey, lvl) AS


(SELECT DISTINCT pkey, 0
FROM
hierarchy
WHERE pkey = 'AAA'
UNION ALL
SELECT C.ckey, P.lvl +1
FROM
hierarchy C
,parent
P
WHERE P.ckey = C.pkey
AND P.lvl+1 < 3
)
SELECT ckey, lvl
FROM
parent;
Figure 830, Select rows where LEVEL < 3

ANSWER
========
CKEY LVL
---- --AAA
0
BBB
1
CCC
1
DDD
1
EEE
2
EEE
2
FFF
2
GGG
3

ANSWER
========
CKEY LVL
---- --AAA
0
BBB
1
CCC
1
DDD
1
EEE
2
EEE
2
FFF
2

ANSWER
========
CKEY LVL
---- --AAA
0
BBB
1
CCC
1
DDD
1
EEE
2
EEE
2
FFF
2

AAA
|
+-----+-----+
|
|
|
BBB
CCC
DDD
|
|
+-+ +-+--+
| |
|
EEE
FFF
|
|
GGG

HIERARCHY
+---------------+
|PKEY |CKEY |NUM|
|-----|-----|---|
|AAA |BBB | 1|
|AAA |CCC | 5|
|AAA |DDD | 20|
|CCC |EEE | 33|
|DDD |EEE | 44|
|DDD |FFF | 5|
|FFF |GGG | 5|
+---------------+

AAA
|
+-----+-----+
|
|
|
BBB
CCC
DDD
|
|
+-+ +-+--+
| |
|
EEE
FFF
|
|
GGG

WITH parent (ckey, lvl) AS


(SELECT DISTINCT pkey, 0
FROM
hierarchy
WHERE pkey = 'AAA'
UNION ALL
SELECT C.ckey, P.lvl +1
FROM
hierarchy C
,parent
P
WHERE P.ckey = C.pkey
AND P.lvl+1 < 3
)
SELECT ckey, lvl
FROM
parent
WHERE lvl = 2;
Figure 831, Select rows where LEVEL = 2

ANSWER
========
CKEY LVL
---- --EEE
2
EEE
2
FFF
2

WITH children (kkey, lvl) AS


ANSWER
(SELECT ckey, 1
========
FROM
hierarchy
KKEY LVL
WHERE pkey = 'DDD'
---- --UNION ALL
AAA
-1
SELECT H.ckey, C.lvl + 1
EEE
1
FROM
hierarchy H
FFF
1
,children C
GGG
2
WHERE H.pkey = C.kkey
)
,parents (kkey, lvl) AS
(SELECT pkey, -1
FROM
hierarchy
WHERE ckey = 'DDD'
UNION ALL
SELECT H.pkey, P.lvl - 1
FROM
hierarchy H
,parents
P
WHERE H.ckey = P.kkey
)
SELECT
kkey ,lvl
FROM
children
UNION ALL
SELECT
kkey ,lvl
FROM
parents;
Figure 832, Find all children and parents of DDD

WITH temp1 (n1) AS


(SELECT id
FROM
staff
WHERE id = 10
UNION ALL
SELECT n1 +10
FROM
temp1
WHERE n1 < 50

HIERARCHY
+---------------+
|PKEY |CKEY |NUM|
|-----|-----|---|
|AAA |BBB | 1|
|AAA |CCC | 5|
|AAA |DDD | 20|
|CCC |EEE | 33|
|DDD |EEE | 44|
|DDD |FFF | 5|
|FFF |GGG | 5|
+---------------+

AAA
|
+-----+-----+
|
|
|
BBB
CCC
DDD
|
|
+-+ +-+--+
| |
|
EEE
FFF
|
|
GGG

ANSWER
======
N1
-warn
10
20
30

)
SELECT *
FROM
temp1;
Figure 833, Recursion - with warning message

40
50

WITH temp1 (n1) AS


(SELECT INT(id)
FROM
staff
WHERE id = 10
UNION ALL
SELECT n1 +10
FROM
temp1
WHERE n1 < 50
)
SELECT *
FROM
temp1;
Figure 834, Recursion - without warning message

DIVERGENT
=========

CONVERGENT
==========

RECURSIVE
=========

AAA
AAA
AAA<--+
|
|
|
|
+-+-+
+-+-+
+-+-+ |
|
|
|
|
|
| |
BBB CCC
BBB CCC
BBB CCC>+
|
|
|
|
+-+-+
+-+-+-+
+-+-+
|
|
|
|
|
|
DDD EEE
DDD EEE
DDD EEE
Figure 835, Hierarchy Flavours

ANSWER
======
N1
-10
20
30
40
50

BALANCED
========
AAA
|
+-+-+
|
|
BBB CCC
|
|
|
+---+
|
|
|
DDD EEE FFF

OBJECTS_RELATES
+---------------------+
|KEYO |PKEY |NUM|PRICE|
|-----|-----|---|-----|
|AAA |
|
| $10|
|BBB |AAA | 1| $21|
|CCC |AAA | 5| $23|
|DDD |AAA | 20| $25|
|EEE |DDD | 44| $33|
|FFF |DDD | 5| $34|
|GGG |FFF | 5| $44|
+---------------------+
Figure 836, Divergent Hierarchy - Table and Layout

UNBALANCED
==========
AAA
|
+-+-+
|
|
BBB CCC
|
+-+-+
|
|
DDD EEE

AAA
|
+-----+-----+
|
|
|
BBB
CCC
DDD
|
+--+--+
|
|
EEE
FFF
|
|
GGG

OBJECTS
RELATIONSHIPS
AAA
+-----------+
+---------------+
|
|KEYO |PRICE|
|PKEY |CKEY |NUM|
+-----+-----+
|-----|-----|
|-----|-----|---|
|
|
|
|AAA | $10|
|AAA |BBB | 1|
BBB
CCC
DDD
|BBB | $21|
|AAA |CCC | 5|
|
|
|CCC | $23|
|AAA |DDD | 20|
+-+ +-+--+
|DDD | $25|
|CCC |EEE | 33|
| |
|
|EEE | $33|
|DDD |EEE | 44|
EEE
FFF
|FFF | $34|
|DDD |FFF | 5|
|
|GGG | $44|
|FFF |GGG | 5|
|
+-----------+
+---------------+
GGG
Figure 837, Convergent Hierarchy - Tables and Layout

OBJECTS
+-----------+
|KEYO |PRICE|
|-----|-----|
|AAA | $10|
|BBB | $21|
|CCC | $23|
|DDD | $25|
|EEE | $33|
|FFF | $34|
|GGG | $44|
+-----------+

RELATIONSHIPS
AAA <------+
+---------------+
|
|
|PKEY |CKEY |NUM|
+-----+-----+
|
|-----|-----|---|
|
|
|
|
|AAA |BBB | 1|
BBB
CCC
DDD>-+
|AAA |CCC | 5|
|
|
|AAA |DDD | 20|
+-+ +-+--+
|CCC |EEE | 33|
| |
|
|DDD |AAA | 99|
EEE
FFF
|DDD |FFF | 5|
|
|DDD |EEE | 44|
|
|FFF |GGG | 5|
GGG
+---------------+
Figure 838, Recursive Hierarchy - Tables and Layout

AAA
|
+-----+-----+
|
|
|
BBB
CCC
DDD
|
|
|
|
|
+-+-+
|
|
|
|
EEE
FFF GGG HHH

<< Balanced hierarchy


Unbalanced hierarchy >>

AAA
|
+---+----+
|
|
|
| CCC DDD
|
|
|
| +-+ +-+-+
| |
|
|
FFF
GGG HHH
|
|
III

Figure 839, Balanced and Unbalanced Hierarchies

TROUBLE
+---------+

AAA <------+
|
|

|PKEY|CKEY|
+-----+-----+
|
|----|----|
|
|
|
|
|AAA |BBB |
BBB
CCC
DDD>-+
|AAA |CCC |
|
|
|AAA |DDD |
+-+ +-+--+
|CCC |EEE |
| |
|
|DDD |AAA |
<=== This row
EEE
FFF
|DDD |FFF |
points back to
|
|DDD |EEE |
the hierarchy
|
|FFF |GGG |
parent.
GGG
+---------+
Figure 840, Recursive Hierarchy - Sample Table and Layout

CREATE TABLE trouble


(pkey
CHAR(03)
,ckey
CHAR(03)

NOT NULL
NOT NULL);

CREATE UNIQUE INDEX tble_x1 ON trouble (pkey, ckey);


CREATE UNIQUE INDEX tble_x2 ON trouble (ckey, pkey);
INSERT INTO trouble VALUES
('AAA','BBB'),
('AAA','CCC'),
('AAA','DDD'),
('CCC','EEE'),
('DDD','AAA'),
('DDD','EEE'),
('DDD','FFF'),
('FFF','GGG');
Figure 841, Sample Table DDL - Recursive Hierarchy

WITH parent (pkey, ckey, lvl) AS


ANSWER
(SELECT DISTINCT
=============
pkey
PKEY CKEY LVL
,pkey
---- ---- --,0
AAA AAA
0
FROM
trouble
AAA BBB
1
WHERE pkey = 'AAA'
AAA CCC
1
UNION ALL
AAA DDD
1
SELECT C.pkey
CCC EEE
2
,C.ckey
DDD AAA
2
,P.lvl + 1
DDD EEE
2
FROM
trouble C
DDD FFF
2
,parent
P
AAA BBB
3
WHERE P.ckey
= C.pkey
AAA CCC
3
AND P.lvl + 1 < 4
AAA DDD
3
)
FFF GGG
3
SELECT *
FROM
parent;
Figure 842, Stop Recursive SQL after "n" levels

TROUBLE
+---------+
|PKEY|CKEY|
|----|----|
|AAA |BBB |
|AAA |CCC |
|AAA |DDD |
|CCC |EEE |
|DDD |AAA |
|DDD |FFF |
|DDD |EEE |
|FFF |GGG |
+---------+

CREATE FUNCTION LOCATE_BLOCK(searchstr VARCHAR(30000)


,lookinstr VARCHAR(30000))
RETURNS INTEGER
BEGIN ATOMIC
DECLARE lookinlen, searchlen INT;
DECLARE locatevar, returnvar INT DEFAULT 0;
DECLARE beginlook
INT DEFAULT 1;
SET lookinlen = LENGTH(lookinstr);
SET searchlen = LENGTH(searchstr);
WHILE locatevar = 0
AND
beginlook <= lookinlen DO
SET locatevar = LOCATE(searchstr,SUBSTR(lookinstr
,beginlook
,searchlen));
SET beginlook = beginlook + searchlen;
SET returnvar = returnvar + 1;
END WHILE;
IF locatevar = 0 THEN
SET returnvar = 0;
END IF;
RETURN returnvar;
END
Figure 843, LOCATE_BLOCK user defined function

SELECT id
,name
,LOCATE('th',name)
AS l1
,LOCATE_BLOCK('th',name) AS l2
FROM
staff
WHERE LOCATE('th',name) > 1;
Figure 844, LOCATE_BLOCK function example

ANSWER
=================
ID NAME
L1 L2
--- ------- -- -70 Rothman 3 2
220 Smith
4 0

WITH parent (pkey, ckey, lvl, path, loop) AS


(SELECT DISTINCT
pkey
,pkey
ANSWER
,0
===============================
,VARCHAR(pkey,20)
PKEY CKEY LVL PATH
LOOP
,0
---- ---- --- ------------ ---FROM
trouble
AAA AAA
0 AAA
0
WHERE pkey = 'AAA'
AAA BBB
1 AAABBB
0
UNION ALL
AAA CCC
1 AAACCC
0
SELECT C.pkey
AAA DDD
1 AAADDD
0
,C.ckey
CCC EEE
2 AAACCCEEE
0
,P.lvl + 1
DDD AAA
2 AAADDDAAA
1
,P.path || C.ckey
DDD EEE
2 AAADDDEEE
0
,LOCATE_BLOCK(C.ckey,P.path) DDD FFF
2 AAADDDFFF
0
FROM
trouble C
AAA BBB
3 AAADDDAAABBB
0
,parent P
AAA CCC
3 AAADDDAAACCC
0
WHERE P.ckey
= C.pkey
AAA DDD
3 AAADDDAAADDD
2

AND P.lvl + 1 < 4


)
SELECT *
FROM
parent;

FFF

GGG

This row ===>


points back to
the hierarchy
parent.

TROUBLE
+---------+
|PKEY|CKEY|
|----|----|
|AAA |BBB |
|AAA |CCC |
|AAA |DDD |
|CCC |EEE |
|DDD |AAA |
|DDD |FFF |
|DDD |EEE |
|FFF |GGG |
+---------+

3 AAADDDFFFGGG

AAA <------+
|
|
+-----+-----+
|
|
|
|
|
BBB
CCC
DDD>-+
|
|
+-+ +-+--+
| |
|
EEE
FFF
|
|
GGG

Figure 845, Show path, and rows in loop

WITH parent (pkey, ckey, lvl, path) AS


ANSWER
(SELECT DISTINCT
==========================
pkey
PKEY CKEY LVL PATH
,pkey
---- ----- -- -----------,0
AAA AAA
0 AAA
,VARCHAR(pkey,20)
AAA BBB
1 AAABBB
FROM
trouble
AAA CCC
1 AAACCC
WHERE pkey = 'AAA'
AAA DDD
1 AAADDD
UNION ALL
CCC EEE
2 AAACCCEEE
SELECT C.pkey
DDD EEE
2 AAADDDEEE
,C.ckey
DDD FFF
2 AAADDDFFF
,P.lvl + 1
FFF GGG
3 AAADDDFFFGGG
,P.path || C.ckey
FROM
trouble C
,parent P
WHERE P.ckey
= C.pkey
AND LOCATE_BLOCK(C.ckey,P.path) = 0
)
SELECT *
FROM
parent;
Figure 846, Use LOCATE_BLOCK function to stop recursion

WITH parent (pkey, ckey, lvl, path, loop) AS


(SELECT DISTINCT
pkey
,pkey
,0
,VARCHAR(pkey,20)
ANSWER
,0
===============================
FROM
trouble
PKEY CKEY LVL PATH
LOOP
WHERE pkey = 'AAA'
---- ---- --- ------------ ---UNION ALL
AAA AAA
0 AAA
0
SELECT C.pkey
AAA BBB
1 AAABBB
0
,C.ckey
AAA CCC
1 AAACCC
0
,P.lvl + 1
AAA DDD
1 AAADDD
0

,P.path || C.ckey
,LOCATE_BLOCK(C.ckey,P.path)
FROM
trouble C
,parent P
WHERE P.ckey = C.pkey
AND P.loop = 0

CCC
DDD
DDD
DDD
FFF

EEE
AAA
EEE
FFF
GGG

2
2
2
2
3

AAACCCEEE
AAADDDAAA
AAADDDEEE
AAADDDFFF
AAADDDFFFGGG

0
1
0
0
0

)
SELECT *
FROM
parent;
Figure 847, Use LOCATE_BLOCK function to stop recursion

WITH parent (pkey, ckey, lvl, path, loop)


(SELECT DISTINCT
pkey
,pkey
,0
,VARCHAR(pkey,20)
,0
FROM
trouble
WHERE pkey = 'AAA'
UNION ALL
SELECT C.pkey
,C.ckey
,P.lvl + 1
,P.path || C.ckey
,LOCATE_BLOCK(C.ckey,P.path)
FROM
trouble C
,parent P
WHERE P.ckey = C.pkey
AND P.loop = 0
)
SELECT pkey
,ckey
FROM
parent
WHERE loop > 0;
Figure 848,List rows that point back to a

AS

This row ===>


points back to
the hierarchy
parent.

ANSWER
=========
PKEY CKEY
---- ---DDD AAA

TROUBLE
+---------+
|PKEY|CKEY|
|----|----|
|AAA |BBB |
|AAA |CCC |
|AAA |DDD |
|CCC |EEE |
|DDD |AAA |
|DDD |FFF |
|DDD |EEE |
|FFF |GGG |
+---------+

parent

DECLARE GLOBAL TEMPORARY TABLE SESSION.del_list


(pkey
CHAR(03)
NOT NULL
,ckey
CHAR(03)
NOT NULL)
ON COMMIT PRESERVE ROWS;
INSERT INTO SESSION.del_list
WITH parent (pkey, ckey, lvl, path, loop) AS
(SELECT DISTINCT
pkey
,pkey
,0
,VARCHAR(pkey,20)
,0
FROM
trouble
WHERE pkey = 'AAA'
UNION ALL

TROUBLE
+---------+
|PKEY|CKEY|
|----|----|
|AAA |BBB |
|AAA |CCC |

SELECT C.pkey
,C.ckey
,P.lvl + 1
,P.path || C.ckey
,LOCATE_BLOCK(C.ckey,P.path)
FROM
trouble C
,parent P
WHERE P.ckey = C.pkey
AND P.loop = 0

This row ===>


points back to
the hierarchy
parent.

)
SELECT pkey
,ckey
FROM
parent
WHERE loop > 0;

DELETE
FROM
trouble
WHERE (pkey,ckey) IN
(SELECT pkey, ckey
FROM
SESSION.del_list);
Figure 849, Delete rows that loop back to a parent

AAA <------+
|
|
+-----+-----+
|
|
|
|
|
BBB
CCC
DDD>-+
|
|
+-+ +-+--+
| |
|
EEE
FFF
|
|
GGG

CREATE TRIGGER TBL_INS


NO CASCADE BEFORE INSERT ON trouble
REFERENCING NEW AS NNN
This trigger
FOR EACH ROW MODE DB2SQL
would reject
WITH temp (pkey, ckey) AS
insertion of
(VALUES (NNN.pkey
this row.
,NNN.ckey)
|
UNION ALL
|
SELECT TTT.pkey
+--->
,CASE
WHEN TTT.ckey = TBL.pkey
THEN RAISE_ERROR('70001','LOOP FOUND')
ELSE TBL.ckey
END
FROM
trouble TBL
,temp
TTT
WHERE TTT.ckey = TBL.pkey
)
SELECT *
FROM
temp;
Figure 850, INSERT trigger

CREATE TRIGGER TBL_UPD


NO CASCADE BEFORE UPDATE OF pkey, ckey ON trouble
REFERENCING NEW AS NNN
FOR EACH ROW MODE DB2SQL
WITH temp (pkey, ckey) AS
(VALUES (NNN.pkey
,NNN.ckey)
UNION ALL
SELECT TTT.pkey

|AAA |DDD |
|CCC |EEE |
|DDD |AAA |
|DDD |FFF |
|DDD |EEE |
|FFF |GGG |
+---------+

TROUBLE
+---------+
|PKEY|CKEY|
|----|----|
|AAA |BBB |
|AAA |CCC |
|AAA |DDD |
|CCC |EEE |
|DDD |AAA |
|DDD |FFF |
|DDD |EEE |
|FFF |GGG |
+---------+

,CASE
WHEN TTT.ckey = TBL.pkey
THEN RAISE_ERROR('70001','LOOP FOUND')
ELSE TBL.ckey
END
FROM
trouble TBL
,temp
TTT
WHERE TTT.ckey = TBL.pkey
)
SELECT *
FROM
temp;
Figure 851, UPDATE trigger

INSERT INTO trouble VALUES('GGG','AAA');


UPDATE trouble SET ckey = 'AAA' WHERE pkey = 'FFF';
UPDATE trouble SET pkey = 'GGG' WHERE ckey = 'DDD';
Figure 852, Invalid DML statements

EXPLODED#1
+-------------+
|PKEY|CKEY|LVL|
|----|----|---|
|AAA |AAA | 0|
|AAA |BBB | 1|
|AAA |CCC | 2|
|AAA |DDD | 3|
|AAA |EEE | 2|
|BBB |BBB | 0|
|BBB |CCC | 1|
|BBB |DDD | 2|
|BBB |EEE | 1|
|CCC |CCC | 0|
|CCC |DDD | 1|
|DDD |DDD | 0|
|EEE |EEE | 0|
+-------------+
Figure 853, Data Hierarchy, with normalized and exploded representations
AAA
|
BBB
|
+-----+
|
|
CCC
EEE
|
DDD

HIERARCHY#1
+--------------------+
|KEYY|PKEY|DATA
|
|----|----|----------|
|AAA |AAA |SOME DATA |
|BBB |AAA |MORE DATA |
|CCC |BBB |MORE JUNK |
|DDD |CCC |MORE JUNK |
|EEE |BBB |JUNK DATA |
+--------------------+

CREATE TABLE hierarchy#1


(keyy
CHAR(3) NOT NULL
,pkey
CHAR(3) NOT NULL
,data
VARCHAR(10)
,CONSTRAINT hierarchy11 PRIMARY KEY(keyy)
,CONSTRAINT hierarchy12 FOREIGN KEY(pkey)
REFERENCES hierarchy#1 (keyy) ON DELETE CASCADE);
CREATE TRIGGER HIR#1_UPD

NO CASCADE BEFORE UPDATE OF pkey ON hierarchy#1


REFERENCING NEW AS NNN
OLD AS OOO
FOR EACH ROW MODE DB2SQL
WHEN (NNN.pkey <> OOO.pkey)
SIGNAL SQLSTATE '70001' ('CAN NOT UPDATE pkey');
Figure 854, Hierarchy table that does not allow updates to PKEY

CREATE TABLE exploded#1


(pkey CHAR(4)
NOT NULL
,ckey CHAR(4)
NOT NULL
,lvl SMALLINT
NOT NULL
,PRIMARY KEY(pkey,ckey));
Figure 855, Exploded table CREATE statement

CREATE TRIGGER EXP#1_DEL


AFTER DELETE ON hierarchy#1
REFERENCING OLD AS OOO
FOR EACH ROW MODE DB2SQL
DELETE
FROM
exploded#1
WHERE ckey = OOO.keyy;
Figure 856, Trigger to maintain exploded table after delete in hierarchy table

CREATE TRIGGER EXP#1_INS


HIERARCHY#1
EXPLODED#1
AFTER INSERT ON hierarchy#1
+--------------+ +-------------+
REFERENCING NEW AS NNN
|KEYY|PKEY|DATA| |PKEY|CKEY|LVL|
FOR EACH ROW MODE DB2SQL
|----|----|----| |----|----|---|
INSERT
|AAA |AAA |S...| |AAA |AAA | 0|
INTO exploded#1
|BBB |AAA |M...| |AAA |BBB | 1|
WITH temp(pkey, ckey, lvl) AS
|CCC |BBB |M...| |AAA |CCC | 2|
(VALUES (NNN.keyy
|DDD |CCC |M...| |AAA |DDD | 3|
,NNN.keyy
|EEE |BBB |J...| |AAA |EEE | 2|
,0)
+--------------+ |BBB |BBB | 0|
UNION ALL
|BBB |CCC | 1|
SELECT N.pkey
|BBB |DDD | 2|
,NNN.keyy
|BBB |EEE | 1|
,T.lvl +1
|CCC |CCC | 0|
FROM
temp
T
|CCC |DDD | 1|
,hierarchy#1 N
|DDD |DDD | 0|
WHERE
N.keyy = T.pkey
|EEE |EEE | 0|
AND
N.keyy <> N.pkey
+-------------+
)
SELECT *
FROM
temp;
Figure 857, Trigger to maintain exploded table after insert in hierarchy table

SELECT
FROM
WHERE
ORDER BY

*
exploded#1
pkey = :host-var
pkey
,ckey
,lvl;
Figure 858, Querying the exploded table

CREATE TABLE hierarchy#2


(keyy
CHAR(3) NOT NULL
,pkey
CHAR(3) NOT NULL
,data
VARCHAR(10)
,CONSTRAINT NO_loopS21 PRIMARY KEY(keyy)
,CONSTRAINT NO_loopS22 FOREIGN KEY(pkey)
REFERENCES hierarchy#2 (keyy) ON DELETE CASCADE
ON UPDATE RESTRICT);
Figure 859, Hierarchy table that allows updates to PKEY

CREATE TRIGGER HIR#2_UPD


HIERARCHY#2
NO CASCADE BEFORE UPDATE OF pkey ON hierarchy#2
+--------------+
REFERENCING NEW AS NNN
|KEYY|PKEY|DATA|
OLD AS OOO
|----|----|----|
FOR EACH ROW MODE DB2SQL
|AAA |AAA |S...|
WHEN (NNN.pkey <> OOO.pkey
|BBB |AAA |M...|
AND NNN.pkey <> NNN.keyy)
|CCC |BBB |M...|
WITH temp (keyy, pkey) AS
|DDD |CCC |M...|
(VALUES (NNN.keyy
|EEE |BBB |J...|
,NNN.pkey)
+--------------+
UNION ALL
SELECT LP2.keyy
,CASE
WHEN LP2.keyy = NNN.keyy
THEN RAISE_ERROR('70001','LOOP FOUND')
ELSE LP2.pkey
END
FROM
hierarchy#2 LP2
,temp
TMP
WHERE TMP.pkey = LP2.keyy
AND TMP.keyy <> TMP.pkey
)
SELECT *
FROM
temp;
Figure 860, Trigger to check for recursive data structures before update of PKEY

CREATE TABLE exploded#2


(pkey CHAR(4)
NOT NULL
,ckey CHAR(4)
NOT NULL
,lvl
SMALLINT NOT NULL
,PRIMARY KEY(pkey,ckey));
Figure 861, Exploded table CREATE statement

CREATE TRIGGER EXP#2_DEL


AFTER DELETE ON hierarchy#2
REFERENCING OLD AS OOO
FOR EACH ROW MODE DB2SQL
DELETE
FROM
exploded#2
WHERE ckey = OOO.keyy;
Figure 862, Trigger to maintain exploded table after delete in hierarchy table

CREATE TRIGGER EXP#2_INS


HIERARCHY#2
EXPLODED#2
AFTER INSERT ON hierarchy#2
+--------------+ +-------------+
REFERENCING NEW AS NNN
|KEYY|PKEY|DATA| |PKEY|CKEY|LVL|
FOR EACH ROW MODE DB2SQL
|----|----|----| |----|----|---|
INSERT
|AAA |AAA |S...| |AAA |AAA | 0|
INTO
exploded#2
|BBB |AAA |M...| |AAA |BBB | 1|
WITH temp(pkey, ckey, lvl) AS
|CCC |BBB |M...| |AAA |CCC | 2|
(SELECT NNN.keyy
|DDD |CCC |M...| |AAA |DDD | 3|
,NNN.keyy
|EEE |BBB |J...| |AAA |EEE | 2|
,0
+--------------+ |BBB |BBB | 0|
FROM
hierarchy#2
|BBB |CCC | 1|
WHERE
keyy = NNN.keyy
|BBB |DDD | 2|
UNION ALL
|BBB |EEE | 1|
SELECT N.pkey
|CCC |CCC | 0|
,NNN.keyy
|CCC |DDD | 1|
,T.lvl +1
|DDD |DDD | 0|
FROM
temp
T
|EEE |EEE | 0|
,hierarchy#2 N
+-------------+
WHERE
N.keyy = T.pkey
AND
N.keyy <> N.pkey
)
SELECT *
FROM
temp;
Figure 863, Trigger to maintain exploded table after insert in hierarchy table

CREATE TRIGGER EXP#2_UPD


AFTER UPDATE OF pkey ON hierarchy#2
REFERENCING OLD AS OOO
NEW AS NNN
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
DELETE

FROM
WHERE

exploded#2
ckey IN
(SELECT ckey
FROM
exploded#2
WHERE pkey = OOO.keyy);

INSERT
INTO
exploded#2
WITH temp1(ckey) AS
(VALUES (NNN.keyy)
UNION ALL
SELECT N.keyy
FROM
temp1
T
,hierarchy#2 N
WHERE
N.pkey = T.ckey
AND
N.pkey <> N.keyy
)
Figure 864, Trigger to run after update of PKEY in hierarchy table (part 1 of 2)

,temp2(pkey, ckey, lvl) AS


(SELECT ckey
,ckey
,0
FROM
temp1
UNION ALL
SELECT N.pkey
,T.ckey
,T.lvl +1
FROM
temp2
T
,hierarchy#2 N
WHERE
N.keyy = T.pkey
AND
N.keyy <> N.pkey
)
SELECT *
FROM
temp2;

END
Figure 865, Trigger to run after update of PKEY in hierarchy table (part 2 of 2)

SELECT
FROM
WHERE
ORDER BY

*
exploded#2
pkey = :host-var
pkey
,ckey
,lvl;
Figure 866, Querying the exploded table

Figure 867, Create Trigger syntax

CREATE TABLE cust_balance


(cust#
INTEGER
GENERATED ALWAYS
,status
CHAR(2)
,balance
DECIMAL(18,2)
,num_trans
INTEGER
,cur_ts
TIMESTAMP
,PRIMARY KEY (cust#));
CREATE TABLE
(cust#
,trans#
,balance
,bgn_ts
,end_ts
,PRIMARY KEY

NOT NULL
AS IDENTITY
NOT NULL
NOT NULL
NOT NULL
NOT NULL

cust_history
INTEGER
NOT
INTEGER
NOT
DECIMAL(18,2)
NOT
TIMESTAMP
NOT
TIMESTAMP
NOT
(cust#, bgn_ts));

CREATE TABLE cust_trans


(min_cust#
INTEGER
,max_cust#
INTEGER
,rows_tot
INTEGER
,change_val DECIMAL(18,2)
,change_type CHAR(1)
,cur_ts
TIMESTAMP
,PRIMARY KEY (cur_ts));
Figure 868, Sample Tables

NULL
NULL
NULL
NULL
NULL

NOT NULL
NOT NULL
NOT NULL

CREATE TRIGGER cust_bal_ins1


NO CASCADE BEFORE INSERT
ON cust_balance
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
SET nnn.cur_ts
= CURRENT TIMESTAMP
,nnn.num_trans = 1;
Figure 869, Before insert trigger - set values

CREATE TRIGGER cust_bal_upd1


NO CASCADE BEFORE UPDATE
ON cust_balance
REFERENCING NEW AS nnn
OLD AS ooo
FOR EACH ROW
MODE DB2SQL
SET nnn.cur_ts
= CURRENT TIMESTAMP
,nnn.num_trans = ooo.num_trans + 1;
Figure 870, Before update trigger - set values

CREATE TRIGGER cust_bal_upd2


NO CASCADE BEFORE UPDATE OF balance
ON cust_balance
REFERENCING NEW AS nnn
OLD AS ooo
FOR EACH ROW
MODE DB2SQL
WHEN (ooo.balance - nnn.balance > 1000)
SIGNAL SQLSTATE VALUE '71001'
SET MESSAGE_TEXT = 'Cannot withdraw > 1000';
Figure 871, Before Trigger - flag error

CREATE TRIGGER cust_his_ins1


AFTER INSERT
ON cust_balance
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
INSERT INTO cust_history VALUES
(nnn.cust#
,nnn.num_trans
,nnn.balance
,nnn.cur_ts
,'9999-12-31-24.00.00');
Figure 872, After Trigger - record insert

CREATE TRIGGER cust_his_upd1


AFTER UPDATE
ON cust_balance
REFERENCING OLD AS ooo
NEW AS nnn
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
UPDATE cust_history
SET
end_ts = CURRENT TIMESTAMP
WHERE cust#
= ooo.cust#
AND bgn_ts = ooo.cur_ts;
INSERT INTO cust_history VALUES
(nnn.cust#
,nnn.num_trans
,nnn.balance
,nnn.cur_ts
,'9999-12-31-24.00.00');
END
Figure 873, After Trigger - record update

CREATE TRIGGER cust_his_del1


AFTER DELETE
ON cust_balance
REFERENCING OLD AS ooo
FOR EACH ROW
MODE DB2SQL
UPDATE cust_history
SET
end_ts = CURRENT TIMESTAMP
WHERE cust#
= ooo.cust#
AND bgn_ts = ooo.cur_ts;
Figure 874, After Trigger - record delete

CREATE TRIGGER trans_his_ins1


AFTER INSERT
ON cust_balance
REFERENCING NEW_TABLE AS newtab
FOR EACH STATEMENT
MODE DB2SQL
INSERT INTO cust_trans
SELECT MIN(cust#)
,MAX(cust#)
,COUNT(*)
,SUM(balance)
,'I'
,CURRENT TIMESTAMP
FROM
newtab;
Figure 875, After Trigger - record insert

CREATE TRIGGER trans_his_upd1


AFTER UPDATE
ON cust_balance
REFERENCING OLD_TABLE AS oldtab
NEW_TABLE AS newtab
FOR EACH STATEMENT
MODE DB2SQL
INSERT INTO cust_trans
SELECT MIN(nt.cust#)
,MAX(nt.cust#)
,COUNT(*)
,SUM(nt.balance - ot.balance)
,'U'
,CURRENT TIMESTAMP
FROM
oldtab ot
,newtab nt
WHERE
ot.cust# = nt.cust#;
Figure 876, After Trigger - record update

CREATE TRIGGER trans_his_del1


AFTER DELETE
ON cust_balance
REFERENCING OLD_TABLE AS oldtab
FOR EACH STATEMENT
MODE DB2SQL
INSERT INTO cust_trans
SELECT MIN(cust#)
,MAX(cust#)
,COUNT(*)
,SUM(balance)
,'D'
,CURRENT TIMESTAMP
FROM
oldtab;
Figure 877, After Trigger - record delete

INSERT INTO cust_balance (status, balance) VALUES ('C',123.45);


INSERT INTO cust_balance (status, balance) VALUES ('C',000.00);
INSERT INTO cust_balance (status, balance) VALUES ('D', -1.00);
UPDATE cust_balance
SET
balance = balance + 123
WHERE cust# <= 2;
UPDATE cust_balance
SET
balance = balance * -1
WHERE cust#
= -1;
UPDATE cust_balance
SET
balance = balance - 123
WHERE cust#
= 1;
DELETE
FROM
cust_balance
WHERE cust# = 3;
Figure 878, Sample DML statements

Figure 879, Customer-balance table rows

Figure 880, Customer-history table rows

Figure 881, Customer-transaction table rows

CREATE TABLE customer_balance


(cust_id
INTEGER
,cust_name
VARCHAR(20)
,cust_sex
CHAR(1)
,num_sales
SMALLINT
,total_sales
DECIMAL(12,2)
,master_cust_id
INTEGER
,cust_insert_ts
TIMESTAMP
,cust_update_ts
TIMESTAMP);
CREATE TABLE us_sales
(invoice#
INTEGER
,cust_id
INTEGER
,sale_value
DECIMAL(18,2)
,sale_insert_ts
TIMESTAMP
,sale_update_ts
TIMESTAMP);
Figure 882, Sample Views used in Join Examples

CREATE DISTINCT TYPE us_dollars AS decimal(18,2) WITH COMPARISONS;


Figure 883, Create US-dollars data type

CREATE TABLE customer_balance


(cust_id
INTEGER
NOT NULL
GENERATED ALWAYS AS IDENTITY
(START WITH 1
,INCREMENT BY 1
,NO CYCLE
,NO CACHE)
,cust_name
VARCHAR(20)
NOT NULL
,cust_sex
CHAR(1)
NOT NULL
,num_sales
SMALLINT
NOT NULL
,total_sales
us_dollars
NOT NULL
,master_cust_id
INTEGER
,cust_insert_ts
TIMESTAMP
NOT NULL
,cust_update_ts
TIMESTAMP
NOT NULL
,PRIMARY KEY
(cust_id)
,CONSTRAINT c1 CHECK (cust_name
<> '')
,CONSTRAINT c2 CHECK (cust_sex
= 'F'
OR cust_sex
= 'M')
,CONSTRAINT c3 FOREIGN KEY (master_cust_id)
REFERENCES customer_balance (cust_id)
ON DELETE CASCADE);
Figure 884, Customer-Balance table DDL

CREATE TABLE us_sales


(invoice#
INTEGER
NOT NULL
,cust_id
INTEGER
NOT NULL
,sale_value
us_dollars
NOT NULL
,sale_insert_ts
TIMESTAMP
NOT NULL
,sale_update_ts
TIMESTAMP
NOT NULL
,PRIMARY KEY
(invoice#)
,CONSTRAINT u1 CHECK (sale_value > us_dollars(0))
,CONSTRAINT u2 FOREIGN KEY (cust_id)
REFERENCES customer_balance
ON DELETE RESTRICT);
CREATE INDEX us_sales_cust ON us_sales (cust_id);
Figure 885, US-Sales table DDL

CREATE TRIGGER cust_balance_ins1


NO CASCADE BEFORE INSERT
ON customer_balance
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
SET nnn.num_sales
= 0
,nnn.total_sales
= 0
,nnn.cust_insert_ts = CURRENT TIMESTAMP
,nnn.cust_update_ts = CURRENT TIMESTAMP;
Figure 886, Set values during insert

CREATE TRIGGER cust_balance_upd1


NO CASCADE BEFORE UPDATE OF cust_update_ts
ON customer_balance
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
SET nnn.cust_update_ts = CURRENT TIMESTAMP;
Figure 887, Set update-timestamp during update

CREATE TRIGGER cust_balance_upd2


NO CASCADE BEFORE UPDATE OF cust_insert_ts
ON customer_balance
FOR EACH ROW
MODE DB2SQL
SIGNAL SQLSTATE VALUE '71001'
SET MESSAGE_TEXT = 'Cannot update CUST insert-ts';
Figure 888, Prevent update of insert-timestamp

CREATE TRIGGER cust_balance_upd3


NO CASCADE BEFORE UPDATE OF num_sales, total_sales
ON customer_balance
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
WHEN (CURRENT TIMESTAMP NOT IN
(SELECT sss.sale_update_ts
FROM
us_sales sss
WHERE nnn.cust_id = sss.cust_id))
SIGNAL SQLSTATE VALUE '71001'
SET MESSAGE_TEXT = 'Feilds only updated via US-Sales';
Figure 889, Prevent update of sales fields

CREATE SEQUENCE us_sales_seq


AS INTEGER
START WITH 1
INCREMENT BY 1
NO CYCLE
NO CACHE
ORDER;
Figure 890, Define sequence

CREATE TRIGGER us_sales_ins1


NO CASCADE BEFORE INSERT
ON us_sales
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
SET nnn.invoice#
= NEXTVAL FOR us_sales_seq
,nnn.sale_insert_ts = CURRENT TIMESTAMP
,nnn.sale_update_ts = CURRENT TIMESTAMP;
Figure 891, Insert trigger

CREATE TRIGGER sales_to_cust_ins1


AFTER INSERT
ON us_sales
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
UPDATE customer_balance ccc
SET
ccc.num_sales
= ccc.num_sales + 1
,ccc.total_sales
= DECIMAL(ccc.total_sales) +

DECIMAL(nnn.sale_value)
WHERE ccc.cust_id
= nnn.cust_id;
Figure 892, Propagate change to Customer-Balance table

CREATE TRIGGER us_sales_upd1


NO CASCADE BEFORE UPDATE OF sale_value
ON us_sales
REFERENCING NEW AS nnn
OLD AS ooo
FOR EACH ROW
MODE DB2SQL
SET nnn.sale_update_ts = CURRENT TIMESTAMP;
Figure 893, Maintain update-timestamp

CREATE TRIGGER us_sales_upd2


NO CASCADE BEFORE UPDATE OF cust_id, sale_insert_ts
ON us_sales
FOR EACH ROW
MODE DB2SQL
SIGNAL SQLSTATE VALUE '71001'
SET MESSAGE_TEXT = 'Can only update sale_value';
Figure 894, Prevent updates to selected columns

CREATE TRIGGER sales_to_cust_upd1


AFTER UPDATE OF sale_value
ON us_sales
REFERENCING NEW AS nnn
OLD AS ooo
FOR EACH ROW
MODE DB2SQL
UPDATE customer_balance ccc
SET ccc.total_sales = DECIMAL(ccc.total_sales) DECIMAL(ooo.sale_value) +
DECIMAL(nnn.sale_value)
WHERE ccc.cust_id
= nnn.cust_id;
Figure 895, Propagate change to Customer-Balance table

CREATE TABLE customer


(cust#
INTEGER
,cust_name
CHAR(10)
,cust_mgr
CHAR(10)
,PRIMARY KEY(cust#));
Figure 896, Customer table

NOT NULL

CREATE TABLE customer_his


(cust#
INTEGER
NOT
,cust_name
CHAR(10)
,cust_mgr
CHAR(10)
,cur_ts
TIMESTAMP
NOT
,cur_actn
CHAR(1)
NOT
,cur_user
VARCHAR(10)
NOT
,prv_cust#
INTEGER
,prv_ts
TIMESTAMP
,PRIMARY KEY(cust#,cur_ts));

NULL
NULL
NULL
NULL

CREATE UNIQUE INDEX customer_his_x1 ON customer_his


(cust#, prv_ts, cur_ts);
Figure 897, Customer-history table

CREATE TRIGGER customer_ins


AFTER
INSERT ON customer
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
INSERT INTO customer_his VALUES
(nnn.cust#
,nnn.cust_name
,nnn.cust_mgr
,CURRENT TIMESTAMP
,'I'
,USER
,NULL
,NULL);
Figure 898, Insert trigger

CREATE TRIGGER customer_upd


AFTER
UPDATE ON customer
REFERENCING NEW AS nnn
OLD AS ooo
FOR EACH ROW
MODE DB2SQL
INSERT INTO customer_his VALUES
(nnn.cust#
,nnn.cust_name
,nnn.cust_mgr
,CURRENT TIMESTAMP
,'U'
,USER
,ooo.cust#

,(SELECT
FROM
WHERE
Figure 899,

MAX(cur_ts)
customer_his hhh
ooo.cust# = hhh.cust#));
Update trigger

CREATE TRIGGER customer_del


AFTER
DELETE ON customer
REFERENCING OLD AS ooo
FOR EACH ROW
MODE DB2SQL
INSERT INTO customer_his VALUES
(ooo.cust#
,NULL
,NULL
,CURRENT TIMESTAMP
,'D'
,USER
,ooo.cust#
,(SELECT MAX(cur_ts)
FROM
customer_his hhh
WHERE ooo.cust# = hhh.cust#));
Figure 900, Delete trigger

CREATE TABLE profile


(user_id
VARCHAR(10)
,bgn_ts
TIMESTAMP
,PRIMARY KEY(user_id));
Figure 901, Profile table

NOT NULL
NOT NULL DEFAULT '9999-12-31-24.00.00'

CREATE VIEW customer_vw AS


SELECT hhh.*
,ppp.bgn_ts
FROM
customer_his hhh
,profile
ppp
WHERE
ppp.user_id
= USER
AND
hhh.cur_ts
<= ppp.bgn_ts
AND
hhh.cur_actn <> 'D'
AND
NOT EXISTS
(SELECT *
FROM
customer_his nnn
WHERE nnn.prv_cust# = hhh.cust#
AND nnn.prv_ts
= hhh.cur_ts
AND nnn.cur_ts
<= ppp.bgn_ts);
Figure 902, View of Customer history

CREATE TABLE version


(vrsn
INTEGER
NOT NULL
,vrsn_bgn_ts TIMESTAMP
NOT NULL
,CONSTRAINT version1 CHECK(vrsn >= 0)
,CONSTRAINT version2 CHECK(vrsn < 1000000000)
,PRIMARY KEY(vrsn));
Figure 903, Version table

CREATE TABLE profile


(user_id
VARCHAR(10)
NOT NULL
,vrsn
INTEGER
NOT NULL
,vrsn_bgn_ts TIMESTAMP
NOT NULL
,CONSTRAINT profile1 FOREIGN KEY(vrsn)
REFERENCES version(vrsn)
ON DELETE RESTRICT
,PRIMARY KEY(user_id));
Figure 904, Profile table

CREATE TABLE customer_his


(cust#
INTEGER
NOT NULL
,cust_name
CHAR(10)
NOT NULL
,cust_mgr
CHAR(10)
,cur_ts
TIMESTAMP
NOT NULL
,cur_vrsn
INTEGER
NOT NULL
,cur_actn
CHAR(1)
NOT NULL
,cur_user
VARCHAR(10)
NOT NULL
,prv_cust#
INTEGER
,prv_ts
TIMESTAMP
,prv_vrsn
INTEGER
,CONSTRAINT customer1 FOREIGN KEY(cur_vrsn)
REFERENCES version(vrsn)
ON DELETE RESTRICT
,CONSTRAINT customer2 CHECK(cur_actn IN ('I','U','D'))
,PRIMARY KEY(cust#,cur_vrsn,cur_ts));
CREATE INDEX customer_x2 ON customer_his
(prv_cust#
,prv_ts
,prv_vrsn);
Figure 905, Customer table

CREATE VIEW customer_vw AS


SELECT *
FROM
customer_his hhh
,profile
ppp

WHERE
ppp.user_id
= USER
AND
hhh.cur_actn <> 'D'
AND ((ppp.vrsn
= 0
AND
hhh.cur_vrsn
= 0)
OR (ppp.vrsn
> 0
AND
hhh.cur_vrsn
= 0
AND
hhh.cur_ts
< ppp.vrsn_bgn_ts)
OR (ppp.vrsn
> 0
AND
hhh.cur_vrsn
= ppp.vrsn))
AND
NOT EXISTS
(SELECT *
FROM
customer_his nnn
WHERE
nnn.prv_cust# = hhh.cust#
AND
nnn.prv_ts
= hhh.cur_ts
AND
nnn.prv_vrsn
= hhh.cur_vrsn
AND ((ppp.vrsn
= 0
AND
nnn.cur_vrsn
= 0)
OR (ppp.vrsn
> 0
AND
nnn.cur_vrsn
= 0
AND
nnn.cur_ts
< ppp.vrsn_bgn_ts)
OR (ppp.vrsn
> 0
AND
nnn.cur_vrsn
= ppp.vrsn)));
Figure 906, Customer view - 1 of 2

CREATE VIEW customer AS


SELECT cust#
,cust_name
,cust_mgr
FROM
customer_vw;
Figure 907, Customer view - 2 of 2

CREATE TRIGGER customer_ins


INSTEAD OF
INSERT ON customer_vw
REFERENCING NEW AS nnn
FOR EACH ROW
MODE DB2SQL
INSERT INTO customer_his VALUES
(nnn.cust#
,nnn.cust_name
,nnn.cust_mgr
,CURRENT TIMESTAMP
,(SELECT vrsn
FROM
profile
WHERE user_id = USER)
,CASE
WHEN 0 < (SELECT COUNT(*)
FROM
customer
WHERE cust# = nnn.cust#)
THEN RAISE_ERROR('71001','ERROR: Duplicate cust#')
ELSE 'I'
END
,USER

,NULL
,NULL
,NULL);
Figure 908, Insert trigger

CREATE TRIGGER customer_upd


INSTEAD OF
UPDATE ON customer_vw
REFERENCING NEW AS nnn
OLD AS ooo
FOR EACH ROW
MODE DB2SQL
INSERT INTO customer_his VALUES
(nnn.cust#
,nnn.cust_name
,nnn.cust_mgr
,CURRENT TIMESTAMP
,ooo.vrsn
,CASE
WHEN nnn.cust# <> ooo.cust#
THEN RAISE_ERROR('72001','ERROR: Cannot change cust#')
ELSE 'U'
END
,ooo.user_id
,ooo.cust#
,ooo.cur_ts
,ooo.cur_vrsn);
Figure 909, Update trigger

CREATE TRIGGER customer_del


INSTEAD OF
DELETE ON customer_vw
REFERENCING OLD AS ooo
FOR EACH ROW
MODE DB2SQL
INSERT INTO customer_his VALUES
(ooo.cust#
,ooo.cust_name
,ooo.cust_mgr
,CURRENT TIMESTAMP
,ooo.vrsn
,'D'
,ooo.user_id
,ooo.cust#
,ooo.cur_ts
,ooo.cur_vrsn);
Figure 910, Delete trigger

SELECT

'SELECT COUNT(*) FROM ' CONCAT


RTRIM(tabschema)
CONCAT
'.'
CONCAT
tabname
CONCAT
';'
FROM
syscat.tables
WHERE
tabschema
= 'SYSCAT'
AND
tabname
LIKE 'N%'
ORDER BY tabschema
ANSWER
,tabname;
=========================================
SELECT COUNT(*) FROM SYSCAT.NAMEMAPPINGS;
SELECT COUNT(*) FROM SYSCAT.NODEGROUPDEF;
SELECT COUNT(*) FROM SYSCAT.NODEGROUPS;
Figure 911, Generate SQL to count rows

EXPORT TO C:\FRED.TXT OF DEL


MODIFIED BY NOCHARDEL
SELECT 'SELECT COUNT(*) FROM ' CONCAT
RTRIM(tabschema)
CONCAT
'.'
CONCAT
tabname
CONCAT
';'
FROM
syscat.tables
WHERE
tabschema
= 'SYSCAT'
AND
tabname
LIKE 'N%'
ORDER BY tabschema
,tabname;
Figure 912, Export generated SQL statements

SELECT

'SELECT '''
CONCAT
tabname
CONCAT
''', COUNT(*) FROM '
CONCAT
RTRIM(tabschema)
CONCAT
'.'
CONCAT
tabname
CONCAT
';'
FROM
syscat.tables
WHERE
tabschema
= 'SYSCAT'
AND
tabname
LIKE 'N%'
ORDER BY tabschema
,tabname;

ANSWER
==========================================================
SELECT 'NAMEMAPPINGS', COUNT(*) FROM SYSCAT.NAMEMAPPINGS;
SELECT 'NODEGROUPDEF', COUNT(*) FROM SYSCAT.NODEGROUPDEF;
SELECT 'NODEGROUPS', COUNT(*) FROM SYSCAT.NODEGROUPS;
Figure 913, Generate SQL to count rows

WITH temp1 (num) AS


(VALUES (1),(2),(3),(4))
SELECT
CASE num
WHEN 1 THEN 'SELECT '''
|| tabname
|| ''' AS tname'
WHEN 2 THEN '
,COUNT(*)'
|| ' AS #rows'
WHEN 3 THEN 'FROM
'
|| RTRIM(tabschema)
|| '.'
ANSWER
|| tabname
==============================
|| ';'
SELECT 'NAMEMAPPINGS' AS tname
WHEN 4 THEN ''
,COUNT(*) AS #rows
END
FROM
SYSCAT.NAMEMAPPINGS;
FROM
syscat.tables
,temp1
SELECT 'NODEGROUPDEF' AS tname
WHERE
tabschema
= 'SYSCAT'
,COUNT(*) AS #rows
AND
tabname
LIKE 'N%'
FROM
SYSCAT.NODEGROUPDEF;
ORDER BY tabschema
,tabname
SELECT 'NODEGROUPS' AS tname
,num;
,COUNT(*) AS #rows
FROM
SYSCAT.NODEGROUPS;
Figure 914, Generate SQL to count rows

WITH temp1 (num) AS


(VALUES (1),(2),(3),(4))
SELECT
CASE num
WHEN 1 THEN 'SELECT SUM(C1)'
when 2 then 'FROM ('
WHEN 3 THEN '
SELECT COUNT(*) AS C1 FROM ' CONCAT
RTRIM(tabschema)
CONCAT
'.'
CONCAT
tabname
CONCAT
CASE dd
WHEN 1 THEN ''
ELSE
' UNION ALL'
END
WHEN 4 THEN ') AS xxx;'
END
FROM
(SELECT
tab.*
,ROW_NUMBER() OVER(ORDER BY tabschema ASC
,tabname
ASC) AS aa
,ROW_NUMBER() OVER(ORDER BY tabschema DESC
,tabname
DESC) AS dd
FROM
syscat.tables tab
WHERE
tabschema
= 'SYSCAT'
AND
tabname
LIKE 'N%'
)AS xxx
,temp1
WHERE
(num <= 2 AND aa = 1)
OR
(num = 3)
OR
(num = 4 AND dd = 1)
ORDER BY tabschema ASC
,tabname
ASC
,num
ASC;
ANSWER
===========================================================

SELECT SUM(C1)
FROM (
SELECT COUNT(*) AS C1 FROM SYSCAT.NAMEMAPPINGS UNION ALL
SELECT COUNT(*) AS C1 FROM SYSCAT.NODEGROUPDEF UNION ALL
SELECT COUNT(*) AS C1 FROM SYSCAT.NODEGROUPS
) AS xxx;
Figure 915, Generate SQL to count rows (all tables)

CREATE PROCEDURE CountRows(IN in_tabschema VARCHAR(128)


,in_tabname
VARCHAR(128))
NOT DETERMINISTIC
DYNAMIC RESULT SETS 1
BEGIN ATOMIC
DECLARE stmt CLOB(1M) DEFAULT '';
DECLARE c1 CURSOR WITH RETURN FOR s1;
SET stmt = 'SELECT 0 FROM sysibm.sysdummy1';
FOR c2 AS
SELECT

tabschema
,tabname
,ROW_NUMBER() OVER(ORDER BY tabschema
,tabname
,ROW_NUMBER() OVER(ORDER BY tabschema
,tabname
FROM
syscat.tables
WHERE
tabschema LIKE in_tabschema
AND
tabname
LIKE in_tabname
ORDER BY tabschema ASC
,tabname
ASC
WITH UR

ASC
ASC) AS aa
DESC
DESC) AS dd

DO
IF aa = 1 THEN
SET stmt = 'SELECT SUM(c1) FROM (';
END IF;
SET stmt = stmt || 'SELECT COUNT(*) AS c1 FROM '
|| RTRIM(tabschema)
|| '.'
|| tabname;
IF dd > 1 THEN
SET stmt = stmt || ' UNION ALL ';
ELSE
SET stmt = stmt || ' ) AS xxx WITH UR ';
END IF;
END FOR;
PREPARE s1 FROM stmt;
OPEN c1;
END
Figure 916, Count rows in all matching tables

ANSWERS
=======
9848
5
0

CALL CountRows('SYSCAT%','%');
CALL CountRows('SYSCAT%','N%');
CALL CountRows('SYSCAT%','Z%');
Figure 917, Run procedure

CREATE PROCEDURE CountRows(IN in_tabschema VARCHAR(128)


,in_tabname
VARCHAR(128))
NOT DETERMINISTIC
DYNAMIC RESULT SETS 1
BEGIN ATOMIC
DECLARE temp_rows, num_rows, num_tables INTEGER DEFAULT 0;
DECLARE stmt VARCHAR(200);
DECLARE c1 CURSOR FOR s1;
DECLARE c2 CURSOR WITH RETURN FOR s2;
FOR c3 AS
SELECT

tabschema
,tabname
FROM
syscat.tables
WHERE
tabschema LIKE
AND
tabname
LIKE
ORDER BY tabschema ASC
,tabname
ASC
WITH UR

in_tabschema
in_tabname

DO

SET stmt = 'SELECT COUNT(*) AS c1 FROM '


||
RTRIM(tabschema)
||
'.'
||
tabname;
PREPARE s1 FROM stmt;
OPEN c1;
FETCH c1 INTO temp_rows;
CLOSE c1;
SET num_rows
= num_rows
+ temp_rows;
SET num_tables = num_tables + 1;
END FOR;
SET stmt =
||
||
||
PREPARE s2
OPEN c2;

'WITH temp1 (c1) AS (VALUES (1)) '


'SELECT ' || CHAR(num_rows)
|| ' AS num_rows '
'
, ' || CHAR(num_tables) || ' AS num_tables '
'FROM
temp1';
FROM stmt;

END
Figure 918, Count rows in all matching tables

ANSWERS
===================
NUM_ROWS NUM_TABLES

-------- ---------9867
100
5
3
0
0

CALL CountRows('SYSCAT%','%');
CALL CountRows('SYSCAT%','N%');
CALL CountRows('SYSCAT%','Z%');
Figure 919, Run procedure

CREATE PROCEDURE CountRows(IN in_tabschema VARCHAR(128)


,in_tabname
VARCHAR(128))
NOT DETERMINISTIC
DYNAMIC RESULT SETS 1
BEGIN ATOMIC
DECLARE stmt VARCHAR(1000);
DECLARE GLOBAL TEMPORARY TABLE session.tab_list
(tabschema
VARCHAR(128)
NOT NULL
,tabname
VARCHAR(128)
NOT NULL
,tabcard
BIGINT
NOT NULL
,num_rows
BIGINT
NOT NULL)
ON COMMIT DELETE ROWS
WITH REPLACE;
INSERT INTO session.tab_list
(SELECT
tabschema
,tabname
,card
,0
FROM
syscat.tables
WHERE
tabschema LIKE
AND
tabname
LIKE
ORDER BY tabschema ASC
,tabname
ASC);
FOR f1 AS
SELECT
DO

FROM

in_tabschema
in_tabname

tabschema
,tabname
session.tab_list

SET stmt = 'UPDATE session.tab_list '


'SET
num_rows = '
'
(SELECT COUNT(*) '
'
FROM
'
tabschema
'.'
tabname
')'
'WHERE tabschema = '''
' AND tabname
= '''
PREPARE s1 FROM stmt;
EXECUTE s1;
END FOR;
BEGIN
DECLARE c1 CURSOR WITH RETURN FOR
SELECT
*
FROM
session.tab_list
ORDER BY tabschema
,tabname;

||
||
||
||
||
||
||
||
|| tabschema || '''' ||
|| tabname
|| '''' ;

OPEN c1;
END;
END
Figure 920, Count rows in each matching table

WITH temp1 (col1) AS


(VALUES
0
UNION ALL
SELECT col1 + 1
FROM
temp1
WHERE col1 + 1 < 100
)
SELECT *
FROM
temp1;
Figure 921, Use recursion to get list of 100 numbers

ANSWER
======
COL1
---0
1
2
3
etc

SELECT *
FROM
TABLE(NumList(100)) AS xxx;
Figure 922, Use user-defined-function to get list of 100 numbers

WITH temp1 (s1, r1) AS


(VALUES (0, RAND(1))
UNION ALL
SELECT s1+1, RAND()
FROM
temp1
WHERE
s1+1 < 5
)
SELECT SMALLINT(s1)
AS seq#
,DECIMAL(r1,5,3) AS ran1
FROM
temp1;
Figure 923, Use RAND to create pseudo-random numbers

WITH temp1 (s1, r1) AS


(VALUES (0, RAND(2))
UNION ALL
SELECT s1+1, RAND()
FROM
temp1
WHERE
s1+1 < 5
)
SELECT SMALLINT(s1)
AS seq#
,SMALLINT(r1*10000) AS ran2
,DECIMAL(r1,6,4)
AS ran1

ANSWER
============
SEQ#
RAN1
---- ----0 0.001
1 0.563
2 0.193
3 0.808
4 0.585

ANSWER
========================
SEQ# RAN2 RAN1
RAN3
---- ---- ------ ---0
13 0.0013
0
1 8916 0.8916
8
2 7384 0.7384
7
3 5430 0.5430
5
4 8998 0.8998
8

,SMALLINT(r1*10)
AS ran3
FROM
temp1;
Figure 924, Make differing ranges of random numbers

ANSWER
=======================
S#
RAN1
RAN2
RAN3
-- ------ ------ -----0
1251 365370 114753
1 350291 280730 88106
2 710501 149549 550422
3 147312 33311
2339
4
8911
556 73091

WITH
temp1 (s1) AS
(VALUES (0)
UNION ALL
SELECT s1 + 1
FROM
temp1
WHERE s1 + 1
< 5
)
SELECT SMALLINT(s1)
AS s#
,INTEGER((RAND(1))
* 1E6) AS ran1
,INTEGER((RAND() * RAND())
* 1E6) AS ran2
,INTEGER((RAND() * RAND()* RAND()) * 1E6) AS ran3
FROM
temp1;
Figure 925, Create RAND data with different distributions

WITH temp1 (s1, r1) AS


(VALUES (0, RAND(2))
UNION ALL
SELECT s1+1, RAND()
FROM
temp1
WHERE
s1+1 < 5
)
SELECT SMALLINT(s1)
AS
,SMALLINT(r1*26+65)
AS
,CHR(SMALLINT(r1*26+65)) AS
,CHAR(SMALLINT(r1*26)+65) AS
FROM
temp1;
Figure 926, Converting RAND output

seq#
ran2
ran3
ran4

ANSWER
===================
SEQ# RAN2 RAN3 RAN4
---- ---- ---- ---0
65 A
65
1
88 X
88
2
84 T
84
3
79 O
79
4
88 X
88

from number to character

CREATE TABLE personnel


(emp#
INTEGER
NOT NULL
,socsec#
CHAR(11)
NOT NULL
,job_ftn
CHAR(4)
NOT NULL
,dept
SMALLINT
NOT NULL
,salary
DECIMAL(7,2)
NOT NULL
,date_bn
DATE
NOT NULL WITH DEFAULT
,fst_name
VARCHAR(20)
,lst_name
VARCHAR(20)
,CONSTRAINT pex1 PRIMARY KEY (emp#)
,CONSTRAINT pe01 CHECK (emp#
>
,CONSTRAINT pe02 CHECK (LOCATE(' ',socsec#)
=

0)
0)

,CONSTRAINT
,CONSTRAINT
,CONSTRAINT
,CONSTRAINT
,CONSTRAINT
,CONSTRAINT
,CONSTRAINT
,CONSTRAINT

pe03
pe04
pe05
pe06
pe07
pe08
pe09
pe10

CHECK
CHECK
CHECK
CHECK
CHECK
CHECK
CHECK
CHECK

(LOCATE('-',socsec#,1) = 4)
(LOCATE('-',socsec#,5) = 7)
(job_ftn
<> '')
(dept
BETWEEN 1 AND
99)
(salary BETWEEN 0 AND 99999)
(fst_name
<> '')
(lst_name
<> '')
(date_bn >= '1900-01-01' ));

CREATE UNIQUE INDEX PEX2 ON PERSONNEL (SOCSEC#);


CREATE UNIQUE INDEX PEX3 ON PERSONNEL (DEPT, EMP#);
Figure 927, Production-like test table DDL

INSERT INTO personnel


WITH temp1 (s1,r1,r2,r3,r4) AS
(VALUES (0
,RAND(2)
,RAND()+(RAND()/1E5)
,RAND()* RAND()
,RAND()* RAND()* RAND())
UNION ALL
SELECT s1 + 1
,RAND()
,RAND()+(RAND()/1E5)
,RAND()* RAND()
,RAND()* RAND()* RAND()
FROM
temp1
WHERE s1 < 10000)
SELECT 100000 + s1
,SUBSTR(DIGITS(INT(r2*988+10)),8) || '-' ||
SUBSTR(DIGITS(INT(r1*88+10)),9) || '-' ||
TRANSLATE(SUBSTR(DIGITS(s1),7),'9873450126','0123456789')
,CASE
WHEN INT(r4*9) > 7 THEN 'MGR'
WHEN INT(r4*9) > 5 THEN 'SUPR'
WHEN INT(r4*9) > 3 THEN 'PGMR'
WHEN INT(R4*9) > 1 THEN 'SEC'
ELSE 'WKR'
END
,INT(r3*98+1)
,DECIMAL(r4*99999,7,2)
,DATE('1930-01-01') + INT(50-(r4*50)) YEARS
+ INT(r4*11) MONTHS
+ INT(r4*27) DAYS
,CHR(INT(r1*26+65))|| CHR(INT(r2*26+97))|| CHR(INT(r3*26+97))||
CHR(INT(r4*26+97))|| CHR(INT(r3*10+97))|| CHR(INT(r3*11+97))
,CHR(INT(r2*26+65))||
TRANSLATE(CHAR(INT(r2*1E7)),'aaeeiibmty','0123456789')
FROM
temp1;
Figure 928, Production-like test table INSERT

EMP#
------

SOCSEC#
JOB_ DEPT SALARY
DATE_BN
F_NME
L_NME
----------- ---- ---- --------- ---------- --------- ---------

100000 484-10-9999 WKR


47
13.63
100001 449-38-9998 SEC
53 35758.87
100002 979-90-9997 WKR
1
8155.23
100003 580-50-9993 WKR
31 16643.50
100004 264-87-9994 WKR
21
962.87
100005 661-84-9995 WKR
19
4648.38
100006 554-53-9990 WKR
8
375.42
100007 482-23-9991 SEC
36 23170.09
100008 536-41-9992 WKR
6 10514.11
Figure 929, Production-like test table,

1979-01-01 Ammaef
1962-04-10 Ilojff
1975-01-03 Xzacaa
1971-02-05 Lpiedd
1979-01-01 Wgfacc
1977-01-02 Wrebbc
1979-01-01 Mobaaa
1968-03-07 Emjgdd
1974-02-03 Jnbcaa
Sample Output

Mimytmbi
Liiiemea
Zytaebma
Pimmeeat
Geimteei
Rbiybeet
Oiiaiaia
Mimtmamb
Nieebayt

CREATE TABLE time_series


(KYY
CHAR(03)
NOT NULL
,bgn_dt
DATE
NOT NULL
,end_dt
DATE
NOT NULL
,CONSTRAINT tsc1 CHECK (kyy <> '')
,CONSTRAINT tsc2 CHECK (bgn_dt <= end_dt));
COMMIT;
INSERT INTO TIME_series values
('AAA','1995-10-01','1995-10-04'),
('AAA','1995-10-06','1995-10-06'),
('AAA','1995-10-07','1995-10-07'),
('AAA','1995-10-15','1995-10-19'),
('BBB','1995-10-01','1995-10-01'),
('BBB','1995-10-03','1995-10-03');
Figure 930, Sample Table DDL - Time Series

Figure 931, Overlapping Time-Series rows - Definition

SELECT kyy
,bgn_dt
,end_dt
FROM
time_series a
WHERE EXISTS
(SELECT *
FROM
time_series b
WHERE a.kyy
= b.kyy
AND a.bgn_dt <> b.bgn_dt
AND (a.bgn_dt BETWEEN b.bgn_dt AND b.end_dt
OR b.bgn_dt BETWEEN a.bgn_dt AND a.end_dt))
ORDER BY 1,2;
Figure 932, Find overlapping rows in time-series

ANSWER
=========

SELECT a.kyy
,a.bgn_dt
,a.end_dt
,b.bgn_dt
,b.end_dt
,DAYS(b.bgn_dt) DAYS(A.end_dt)
as diff
FROM
time_series a
,time_series b
WHERE a.kyy
= b.kyy
AND a.end_dt < b.bgn_dt - 1 DAY
AND NOT EXISTS
(SELECT *
FROM
time_series z
WHERE z.kyy
= a.kyy
AND z.kyy
= b.kyy
AND z.bgn_dt > a.bgn_dt
AND z.bgn_dt < b.bgn_dt)
ORDER BY 1,2;
Figure 933, Find gap in Time-Series, SQL

TIME_SERIES
+-------------------------+
|KYY|BGN_DT
|END_DT
|
|---|----------|----------|
|AAA|1995-10-01|1995-10-04|
|AAA|1995-10-06|1995-10-06|
|AAA|1995-10-07|1995-10-07|
|AAA|1995-10-15|1995-10-19|
|BBB|1995-10-01|1995-10-01|
|BBB|1995-10-03|1995-10-03|
+-------------------------+

KEYCOL BGN_DT
END_DT
BGN_DT
------ ---------- ---------- ---------AAA
1995-10-01 1995-10-04 1995-10-06
AAA
1995-10-07 1995-10-07 1995-10-15
BBB
1995-10-01 1995-10-01 1995-10-03
Figure 934, Find gap in Time-Series, Answer

SELECT a.kyy
AS kyy
,a.end_dt + 1 DAY
AS bgn_gap
,b.bgn_dt - 1 DAY
AS end_gap
,(DAYS(b.bgn_dt) DAYS(a.end_dt) - 1) AS sz
FROM
time_series a
,time_series b
WHERE a.kyy
= b.kyy
AND a.end_dt < b.bgn_dt - 1 DAY
AND NOT EXISTS
(SELECT *
FROM
time_series z
WHERE z.kyy
= a.kyy
AND z.kyy
= b.kyy
AND z.bgn_dt > a.bgn_dt
AND z.bgn_dt < b.bgn_dt)
ORDER BY 1,2;
Figure 935, Find gap in Time-Series

END_DT
---------1995-10-06
1995-10-19
1995-10-03

DIFF
---2
8
2

TIME_SERIES
+-------------------------+
|KYY|BGN_DT
|END_DT
|
|---|----------|----------|
|AAA|1995-10-01|1995-10-04|
|AAA|1995-10-06|1995-10-06|
|AAA|1995-10-07|1995-10-07|
|AAA|1995-10-15|1995-10-19|
|BBB|1995-10-01|1995-10-01|
|BBB|1995-10-03|1995-10-03|
+-------------------------+
ANSWER
============================
KYY BGN_GAP
END_GAP
SZ
--- ---------- ---------- -AAA 1995-10-05 1995-10-05 1
AAA 1995-10-08 1995-10-14 7
BBB 1995-10-02 1995-10-02 1

WITH temp
TIME_SERIES
(kyy, gap_dt, gsize) AS
+-------------------------+
(SELECT a.kyy
|KYY|BGN_DT
|END_DT
|
,a.end_dt + 1 DAY
|---|----------|----------|
,(DAYS(b.bgn_dt) |AAA|1995-10-01|1995-10-04|
DAYS(a.end_dt) - 1)
|AAA|1995-10-06|1995-10-06|
FROM
time_series a
|AAA|1995-10-07|1995-10-07|
,time_series b
|AAA|1995-10-15|1995-10-19|
WHERE a.kyy
= b.kyy
|BBB|1995-10-01|1995-10-01|
AND a.end_dt < b.bgn_dt - 1 DAY
|BBB|1995-10-03|1995-10-03|
AND NOT EXISTS
+-------------------------+
(SELECT *
FROM
time_series z
WHERE z.kyy
= a.kyy
AND z.kyy
= b.kyy
ANSWER
AND z.bgn_dt > a.bgn_dt
=======================
AND z.bgn_dt < b.bgn_dt)
KEYCOL GAP_DT
GSIZE
UNION ALL
------ ---------- ----SELECT kyy
AAA
1995-10-05
1
,gap_dt + 1 DAY
AAA
1995-10-08
7
,gsize - 1
AAA
1995-10-09
6
FROM
temp
AAA
1995-10-10
5
WHERE gsize > 1
AAA
1995-10-11
4
)
AAA
1995-10-12
3
SELECT
*
AAA
1995-10-13
2
FROM
temp
AAA
1995-10-14
1
ORDER BY 1,2;
BBB
1995-10-02
1
Figure 936, Show each day in Time-Series gap

Figure 937, TABLESAMPLE Syntax

SELECT
*
FROM
staff TABLESAMPLE BERNOULLI(5) REPEATABLE(1234)
ORDER BY id;
Figure 938, Sample rows in STAFF table

SELECT
FROM

*
employee ee TABLESAMPLE BERNOULLI(18)
,emp_act ea TABLESAMPLE BERNOULLI(25)
WHERE
ee.empno = ea.empno
ORDER BY ee.empno;
Figure 939, Sample rows in two tables

DECLARE GLOBAL TEMPORARY TABLE session.nyc_staff


LIKE
staff;
SELECT
*
FROM
session.nyc_staff TABLESAMPLE SYSTEM(34.55)
WHERE
id
< 100
AND
salary > 100
ORDER BY id;
Figure 940, Sample Views used in Join Examples

WITH temp1 (c1) AS


ANSWER (numbers shortened)
(VALUES '123 ',' 345 ',' 567')
=================================
SELECT c1
C1
DBL
DEC
SML INT
,DOUBLE(c1)
AS dbl
----- ----------- ----- ---- ---,DECIMAL(c1,3) AS dec
123
+1.2300E+2 123. 123 123
,SMALLINT(c1) AS sml
345
+3.4500E+2 345. 345 345
,INTEGER(c1)
AS int
567 +5.6700E+2 567. 567 567
FROM
temp1;
Figure 941, Convert Character to Numeric - SQL

INPUT STRING
COMPATIBLE FUNCTIONS
============
==========================================
"
1234"
DOUBLE, DECIMAL, INTEGER, SMALLINT, BIGINT
"
12.4"
DOUBLE, DECIMAL
"
12E4"
DOUBLE
Figure 942, Acceptable conversion values

WITH temp1 (c1) AS (VALUES ' 123','456 ',' 1 2',' 33%',NULL)


SELECT c1
,TRANSLATE(c1,'
','1234567890')
AS c2
,LENGTH(LTRIM(TRANSLATE(c1,'
','1234567890'))) AS c3
FROM
temp1;
ANSWER
============
C1
C2
C3
---- ---- -123
0
456
0
1 2
0
33%
% 1
Figure 943, Checking for non-digits

--#SET DELIMITER !

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

CREATE FUNCTION isnumeric(instr VARCHAR(40))


RETURNS CHAR(1)
BEGIN ATOMIC
DECLARE is_number CHAR(1) DEFAULT 'Y';
DECLARE bgn_blank CHAR(1) DEFAULT 'Y';
DECLARE found_num CHAR(1) DEFAULT 'N';
DECLARE found_pos CHAR(1) DEFAULT 'N';
DECLARE found_neg CHAR(1) DEFAULT 'N';
DECLARE found_dot CHAR(1) DEFAULT 'N';
DECLARE ctr
SMALLINT DEFAULT 1;
IF instr IS NULL THEN
RETURN NULL;
END IF;
wloop:
WHILE ctr
<= LENGTH(instr) AND
is_number = 'Y'
DO
------------------------------- ERROR CHECKS
------------------------------IF SUBSTR(instr,ctr,1) NOT IN (' ','.','+','-','0','1','2'
,'3','4','5','6','7','8','9') THEN
SET is_number = 'N';
ITERATE wloop;
END IF;
IF SUBSTR(instr,ctr,1) = ' ' AND
bgn_blank
= 'N' THEN
SET is_number = 'N';
ITERATE wloop;
END IF;
IF SUBSTR(instr,ctr,1) = '.' AND
found_dot
= 'Y' THEN
SET is_number = 'N';
ITERATE wloop;
END IF;
IF SUBSTR(instr,ctr,1) = '+' AND
(found_neg
= 'Y' OR
bgn_blank
= 'N') THEN
SET is_number = 'N';
ITERATE wloop;
END IF;
IF SUBSTR(instr,ctr,1) = '-' AND
(found_neg
= 'Y' OR
bgn_blank
= 'N') THEN
SET is_number = 'N';
ITERATE wloop;
END IF;
------------------------------- MAINTAIN FLAGS & CTR ------------------------------IF SUBSTR(instr,ctr,1) IN ('0','1','2','3','4'
,'5','6','7','8','9') THEN
SET found_num = 'Y';
END IF;
IF SUBSTR(instr,ctr,1) = '.' THEN
SET found_dot = 'Y';
END IF;
IF SUBSTR(instr,ctr,1) = '+' THEN

SET found_pos = 'Y';


END IF;
IF SUBSTR(instr,ctr,1) = '-' THEN
SET found_neg = 'Y';
END IF;
Figure 944, Check Numeric function, part 1 of 2

IF SUBSTR(instr,ctr,1) <> ' ' THEN


SET bgn_blank = 'N';
END IF;
SET ctr = ctr + 1;
END WHILE wloop;
IF found_num = 'N' THEN
SET is_number = 'N';
END IF;
RETURN is_number;
END!
WITH TEMP1 (C1) AS
(VALUES '
123'
,'+123.45'
,'456
'
,' 10 2 '
,'
-.23'
,'++12356'
,'.012349'
,'
33%'
,'
'
,NULL)
SELECT
C1
AS C1
,isnumeric(C1)
AS C2
,CASE
WHEN isnumeric(C1) = 'Y'
THEN DECIMAL(C1,10,6)
ELSE NULL
END
AS C3
FROM
TEMP1!
Figure 945, Check Numeric function, part 2 of 2

SELECT

ANSWER
====================
C1
C2 C3
------- -- --------123 Y 123.00000
+123.45 Y 123.45000
456
N
10 2
N
-.23 Y
-0.23000
++12356 N
.012349 Y
0.01234
33% N
N
-

d_sal
,CHAR(d_sal)
AS d_chr
,DIGITS(d_sal) AS d_dgt
,i_sal
,CHAR(i_sal)
AS i_chr
,DIGITS(i_sal) AS i_dgt
FROM
(SELECT DEC(salary - 11000,6,2) AS d_sal
,SMALLINT(salary - 11000) AS i_sal
FROM
staff
WHERE
salary > 10000
AND
salary < 12200
)AS xxx
ANSWER
ORDER BY d_sal;
=========================================
D_SAL
D_CHR
D_DGT I_SAL I_CHR I_DGT

-------494.10
-12.00
508.60
1009.75
Figure 946, CHAR and DIGITS function

--------0494.10
-0012.00
0508.60
1009.75
usage

------ ----- ----049410 -494 -494


001200
-12 -12
050860
508 508
100975 1009 1009

----00494
00012
00508
01009

CREATE FUNCTION char_right(inval SMALLINT)


RETURNS CHAR(06)
RETURN RIGHT(CHAR('',06) CONCAT RTRIM(CHAR(inval)),06);
CREATE FUNCTION char_right(inval INTEGER)
RETURNS CHAR(11)
RETURN RIGHT(CHAR('',11) CONCAT RTRIM(CHAR(inval)),11);
CREATE FUNCTION char_right(inval BIGINT)
RETURNS CHAR(20)
RETURN RIGHT(CHAR('',20) CONCAT RTRIM(CHAR(inval)),20);
Figure 947, User-defined functions - convert integer to character

SELECT

i_sal
,char_right(i_sal) AS i_chr
FROM
(SELECT SMALLINT(salary - 11000) AS i_sal
FROM
staff
WHERE
salary > 10000
AND
salary < 12200
)AS xxx
ORDER BY i_sal;
Figure 948, Convert SMALLINT to CHAR

ANSWER
===========
I_SAL I_CHR
----- -----494 -494
-12
-12
508
508
1009 1009

CREATE FUNCTION char_right(inval DECIMAL(22,2))


RETURNS CHAR(23)
RETURN RIGHT(CHAR('',20) CONCAT RTRIM(CHAR(BIGINT(inval))),20)
CONCAT '.'
CONCAT SUBSTR(DIGITS(inval),21,2);
Figure 949, User-defined function - convert decimal to character

SELECT
FROM

d_sal
,char_right(d_sal)
AS d_chr
(SELECT DEC(salary - 11000,6,2)
FROM
staff

AS d_sal

WHERE
AND
)AS xxx
ORDER BY d_sal;

salary > 10000


salary < 12200

ANSWER
===============
D_SAL
D_CHR
------- -------494.10 -494.10
-12.00 -12.00
508.60 508.60
1009.75 1009.75

Figure 950, Convert DECIMAL to CHAR

CREATE FUNCTION comma_right(inval DECIMAL(20,2))


RETURNS CHAR(27)
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
BEGIN ATOMIC
DECLARE i INTEGER DEFAULT 17;
DECLARE abs_inval BIGINT;
DECLARE out_value CHAR(27);
SET abs_inval = ABS(BIGINT(inval));
SET out_value = RIGHT(CHAR('',19) CONCAT
RTRIM(CHAR(BIGINT(inval))),19)
CONCAT '.'
CONCAT SUBSTR(DIGITS(inval),19,2);
WHILE i > 2 DO
IF SUBSTR(out_value,i-1,1) BETWEEN '0' AND '9' THEN
SET out_value = SUBSTR(out_value,1,i-1) CONCAT
','
CONCAT
SUBSTR(out_value,i);
ELSE
SET out_value = ' ' CONCAT out_value;
END IF;
SET i = i - 3;
END WHILE;
RETURN out_value;
END
Figure 951, User-defined function - convert decimal to character - with commas

WITH
ANSWER
temp1 (num) AS
====================================
(VALUES (DEC(+1,20,2))
INPUT
OUTPUT
,(DEC(-1,20,2))
----------------- -----------------UNION ALL
-975460660753.97 -975,460,660,753.97
SELECT num * 987654.12
-987655.12
-987,655.12
FROM
temp1
-2.00
-2.00
WHERE
ABS(num) < 1E10),
0.00
0.00
temp2 (num) AS
987653.12
987,653.12
(SELECT num - 1
975460660751.97 975,460,660,751.97
FROM
temp1)
SELECT
num
AS input
,comma_right(num) AS output
FROM
temp2
ORDER BY num;

Figure 952, Convert DECIMAL to CHAR with commas

WITH tab1(ts1) AS
(VALUES CAST('1998-11-22-03.44.55.123456' AS TIMESTAMP))
SELECT

ts1
,
HEX(ts1)
,
DEC(HEX(ts1),20)
,FLOAT(DEC(HEX(ts1),20))
,REAL (DEC(HEX(ts1),20))
FROM
tab1;
Figure 953, Convert Timestamp to number

=>
=>
=>
=>
=>

1998-11-22-03.44.55.123456
19981122034455123456
19981122034455123456.
1.99811220344551e+019
1.998112e+019

SELECT

empno
,firstnme
,lastname
,job
FROM
employee
WHERE
empno < '000100'
ORDER BY empno;
Figure 954, Sample query with no column control

SELECT

empno
,CASE :host-var-1
WHEN 1 THEN firstnme
ELSE
''
END
AS firstnme
,CASE :host-var-2
WHEN 1 THEN lastname
ELSE
''
END
AS lastname
,CASE :host-var-3
WHEN 1 THEN VARCHAR(job)
ELSE
''
END
AS job
FROM
employee
WHERE
empno < '000100'
ORDER BY empno;
Figure 955, Sample query with column control

SELECT

id
,salary
,INT(salary / 1500)

AS len

,REPEAT('*',INT(salary / 1500)) AS salary_chart


staff
id > 120
ANSWER
id < 190
===================================
id;
ID
SALARY
LEN SALARY_CHART
--- -------- --- --------------130 10505.90
7 *******
140 21150.00
14 **************
150 19456.50
12 ************
160 22959.20
15 ***************
170 12258.50
8 ********
180 12009.75
8 ********
Figure 956, Make chart using SQL
FROM
WHERE
AND
ORDER BY

ANSWER
===================================
ID
SALARY
SALARY_CHART
--- -------- -------------------130 10505.90 *********
140 21150.00 ******************
150 19456.50 ****************
160 22959.20 ********************
170 12258.50 **********
180 12009.75 **********

WITH
temp1 (id, salary) AS
(SELECT
id
,salary
FROM
staff
WHERE
id > 120
AND
id < 190),
temp2 (max_sal) AS
(SELECT
INT(MAX(salary)) / 20
FROM
temp1)
SELECT
id
,salary
,VARCHAR(REPEAT('*',INT(salary / max_sal)),20) AS salary_chart
FROM
temp1
,temp2
ORDER BY id;
Figure 957, Make chart of fixed length

SELECT

sex
,COUNT(*) AS num
FROM
stats
GROUP BY sex
ORDER BY sex;
Figure 958, Use GROUP BY to get counts

ANSWER >>

WITH f (f) AS (SELECT COUNT(*) FROM stats WHERE sex = 'F')


,m (m) AS (SELECT COUNT(*) FROM stats WHERE sex = 'M')
SELECT f, m
FROM
f, m;
Figure 959, Use Common Table Expression to get counts

SEX
--F
M

NUM
--595
405

SELECT

SUM(CASE sex WHEN 'F' THEN 1 ELSE 0 END) AS female


,SUM(CASE sex WHEN 'M' THEN 1 ELSE 0 END) AS male
FROM
stats;
Figure 960, Use CASE and SUM to get counts

SELECT

COUNT(*) AS total
,SUM(CASE sex WHEN 'F' THEN 1 ELSE 0 END) AS female
,SUM(CASE sex WHEN 'M' THEN 1 ELSE 0 END) AS male
FROM
stats;
Figure 961, Use CASE and SUM to get counts

SELECT

years
,COUNT(*) AS #staff
FROM
staff
WHERE
UCASE(name) LIKE '%E%'
AND
years
<= 5
GROUP BY years;
Figure 962, Count staff joined per year

WITH list_years (year#) AS


(VALUES (0),(1),(2),(3),(4),(5)
)
SELECT
year#
AS years
,COALESCE(#stff,0) AS #staff
FROM
list_years
LEFT OUTER JOIN
(SELECT
years
,COUNT(*) AS #stff
FROM
staff
WHERE
UCASE(name) LIKE '%E%'
AND
years
<= 5
GROUP BY years
)AS xxx
ON
year# = years
ORDER BY 1;
Figure 963, Count staff joined per year, all years

ANSWER
=============
YEARS #STAFF
----- -----1
1
4
2
5
3

ANSWER
============
YEARS #STAFF
----- -----0
0
1
1
2
0
3
0
4
2
5
3

WITH list_years (year#) AS


(VALUES SMALLINT(0)
UNION
ALL
SELECT year# + 1
FROM
list_years
WHERE
year# < 5)
SELECT
year#
AS years
,COALESCE(#stff,0) AS #staff
FROM
list_years
LEFT OUTER JOIN
(SELECT
years
,COUNT(*) AS #stff
FROM
staff
WHERE
UCASE(name) LIKE '%E%'
AND
years
<= 5
GROUP BY years
)AS xxx
ON
year# = years
ORDER BY 1;
Figure 964, Count staff joined per year, all years

WITH list_years (year#) AS


(VALUES SMALLINT(0)
UNION
ALL
SELECT year# + 1
FROM
list_years
WHERE
year# < 5)
SELECT
year#
FROM
list_years y
WHERE
NOT EXISTS
(SELECT *
FROM
staff s
WHERE UCASE(s.name) LIKE '%E%'
AND s.years
= y.year#)
ORDER BY 1;
Figure 965, List years when no staff joined

WITH category (cat,subcat,dept) AS


(VALUES ('1ST','ROWS IN TABLE ','')
,('2ND','SALARY > $20K ','')
,('3RD','NAME LIKE ABC%','')
,('4TH','NUMBER MALES ','')
UNION
SELECT '5TH',deptname,deptno
FROM
department
)
SELECT
xxx.cat
AS "category"
,xxx.subcat
AS "subcategory/dept"
,SUM(xxx.found) AS "#rows"
FROM
(SELECT
cat.cat
,cat.subcat
,CASE
WHEN emp.empno IS NULL THEN 0

ANSWER
============
YEARS #STAFF
----- -----0
0
1
1
2
0
3
0
4
2
5
3

ANSWER
======
YEAR#
----0
2
3

ELSE
1
END AS found
FROM
category cat
LEFT OUTER JOIN
employee emp
ON
cat.subcat
= 'ROWS IN TABLE'
OR
(cat.subcat
= 'NUMBER MALES'
AND
emp.sex
= 'M')
OR
(cat.subcat
= 'SALARY > $20K'
AND
emp.salary
> 20000)
OR
(cat.subcat
= 'NAME LIKE ABC%'
AND
emp.firstnme LIKE 'ABC%')
OR
(cat.dept
<> ''
AND
cat.dept
= emp.workdept)
)AS xxx
GROUP BY xxx.cat
,xxx.subcat
ORDER BY 1,2;
Figure 966, Multiple counts in one pass, SQL

CATEGORY SUBCATEGORY/DEPT
#ROWS
-------- ----------------------------- ----1ST
ROWS IN TABLE
32
2ND
SALARY > $20K
25
3RD
NAME LIKE ABC%
0
4TH
NUMBER MALES
19
5TH
ADMINISTRATION SYSTEMS
6
5TH
DEVELOPMENT CENTER
0
5TH
INFORMATION CENTER
3
5TH
MANUFACTURING SYSTEMS
9
5TH
OPERATIONS
5
5TH
PLANNING
1
5TH
SOFTWARE SUPPORT
4
5TH
SPIFFY COMPUTER SERVICE DIV.
3
5TH
SUPPORT SERVICES
1
Figure 967, Multiple counts in one pass, Answer

WITH
temp1 (id, data) AS
(VALUES (01,'SOME TEXT TO PARSE.')
,(02,'MORE SAMPLE TEXT.')
,(03,'ONE-WORD.')
,(04,'')
),
temp2 (id, word#, word, data_left) AS
(SELECT id
,SMALLINT(1)
,SUBSTR(data,1,
CASE LOCATE(' ',data)
WHEN 0 THEN LENGTH(data)
ELSE
LOCATE(' ',data)
END)
,LTRIM(SUBSTR(data,

CASE LOCATE(' ',data)


WHEN 0 THEN LENGTH(data) + 1
ELSE
LOCATE(' ',data)
END))
FROM
temp1
WHERE
data <> ''
UNION ALL
SELECT id
,word# + 1
,SUBSTR(data_left,1,
CASE LOCATE(' ',data_left)
WHEN 0 THEN LENGTH(data_left)
ELSE
LOCATE(' ',data_left)
END)
,LTRIM(SUBSTR(data_left,
CASE LOCATE(' ',data_left)
WHEN 0 THEN LENGTH(data_left) + 1
ELSE
LOCATE(' ',data_left)
END))
FROM
temp2
WHERE
data_left <> ''

)
SELECT
*
FROM
temp2
ORDER BY 1,2;
Figure 968, Break text into words - SQL

ID WORD# WORD
DATA_LEFT
-- ----- --------- -------------1
1 SOME
TEXT TO PARSE.
1
2 TEXT
TO PARSE.
1
3 TO
PARSE.
1
4 PARSE.
2
1 MORE
SAMPLE TEXT.
2
2 SAMPLE
TEXT.
2
3 TEXT.
3
1 ONE-WORD.
Figure 969, Break text into words - Answer

WITH temp1 (dept,w#,name,all_names) AS


(SELECT
dept
,SMALLINT(1)
,MIN(name)
,VARCHAR(MIN(name),50)
FROM
staff a
GROUP BY dept
UNION ALL
SELECT
a.dept
,SMALLINT(b.w#+1)
,a.name
,b.all_names || ' ' || a.name
FROM
staff a
,temp1 b

WHERE
AND
AND

)
SELECT

a.dept
a.name
a.name
(SELECT
FROM
WHERE
AND

= b.dept
> b.name
=
MIN(c.name)
staff c
c.dept = b.dept
c.name > b.name)

dept
,w#
,name AS max_name
,all_names
FROM
temp1 d
WHERE
w# =
(SELECT MAX(w#)
FROM
temp1 e
WHERE d.dept = e.dept)
ORDER BY dept;
Figure 970, Denormalize Normalized Data - SQL

DEPT W# MAX_NAME ALL_NAMES


---- -- --------- ------------------------------------------10 4 Molinare Daniels Jones Lu Molinare
15 4 Rothman
Hanes Kermisch Ngan Rothman
20 4 Sneider
James Pernal Sanders Sneider
38 5 Quigley
Abrahams Marenghi Naughton O'Brien Quigley
42 4 Yamaguchi Koonitz Plotz Scoutten Yamaguchi
51 5 Williams Fraye Lundquist Smith Wheeler Williams
66 5 Wilson
Burke Gonzales Graham Lea Wilson
84 4 Quill
Davis Edwards Gafney Quill
Figure 971, Denormalize Normalized Data - Answer

CREATE FUNCTION list_names(indept SMALLINT)


RETURNS VARCHAR(50)
BEGIN ATOMIC
DECLARE outstr VARCHAR(50) DEFAULT '';
FOR list_names AS
SELECT
name
FROM
staff
WHERE
dept = indept
ORDER BY name
DO
SET outstr = outstr || name || ' ';
END FOR;
SET outstr = rtrim(outstr);
RETURN outstr;
END!
SELECT

FROM

dept
,SMALLINT(cnt)
,mxx
,list_names(dept)
(SELECT
dept

AS
AS
AS
AS

DEPT
W#
MAX_NAME
ALL_NAMES

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

,COUNT(*) as cnt
,MAX(name) AS mxx
FROM
staff
GROUP BY dept
)as ddd
ORDER BY dept!
Figure 972, Creating a function to denormalize names

CREATE FUNCTION num_to_char(inval SMALLINT)


RETURNS CHAR(06)
RETURN RIGHT(CHAR('',06) CONCAT RTRIM(CHAR(inval)),06);
CREATE FUNCTION num_to_char(inval DECIMAL(9,2))
RETURNS CHAR(10)
RETURN RIGHT(CHAR('',7) CONCAT RTRIM(CHAR(BIGINT(inval))),7)
CONCAT '.'
CONCAT SUBSTR(DIGITS(inval),8,2);
CREATE FUNCTION right_justify(inval CHAR(5))
RETURNS CHAR(10)
RETURN RIGHT(CHAR('',10) || RTRIM(inval),10);
Figure 973, Data Transformation Functions

WITH
data_input AS
(SELECT
dept
,job
,SUM(salary) AS sum_sal
FROM
staff
WHERE
id
< 200
AND
name
<> 'Sue'
AND
salary
> 10000
GROUP BY dept
,job),
jobs_list AS
(SELECT
job
,ROW_NUMBER() OVER(ORDER BY job ASC) AS job#A
,ROW_NUMBER() OVER(ORDER BY job DESC) AS job#D
FROM
data_input
GROUP BY job),
dept_list AS
(SELECT
dept
FROM
data_input
GROUP BY dept),
dept_jobs_list AS
(SELECT
dpt.dept
,job.job
,job.job#A
,job.job#D
FROM
jobs_list job
FULL OUTER JOIN
dept_list dpt
ON
1 = 1),

data_all_jobs AS
(SELECT
djb.dept
,djb.job
,djb.job#A
,djb.job#D
,COALESCE(dat.sum_sal,0) AS sum_sal
FROM
dept_jobs_list djb
LEFT OUTER JOIN
data_input
dat
ON
djb.dept = dat.dept
AND
djb.job = dat.job),
data_transform (dept, job#A, job#D, outvalue) AS
(SELECT
dept
,job#A
,job#D
,VARCHAR(num_to_char(sum_sal),250)
FROM
data_all_jobs
WHERE
job#A = 1
UNION ALL
SELECT
dat.dept
,dat.job#A
,dat.job#D
,trn.outvalue || ',' || num_to_char(dat.sum_sal)
FROM
data_transform trn
,data_all_jobs dat
WHERE
trn.dept = dat.dept
AND
trn.job#A = dat.job#A - 1),
data_last_row AS
(SELECT
dept
,num_to_char(dept) AS dept_char
,outvalue
FROM
data_transform
WHERE
job#D = 1),
Figure 974, Transform numeric data - part 1 of 2

jobs_transform (job#A, job#D, outvalue) AS


(SELECT
job#A
,job#D
,VARCHAR(right_justify(job),250)
FROM
jobs_list
WHERE
job#A = 1
UNION ALL
SELECT
job.job#A
,job.job#D
,trn.outvalue || ',' || right_justify(job.job)
FROM
jobs_transform trn
,jobs_list
job
WHERE
trn.job#A = job.job#A - 1),
jobs_last_row AS
(SELECT
0
AS dept
,' DEPT' AS dept_char
,outvalue
FROM
jobs_transform
WHERE
job#D = 1),
data_and_jobs AS
(SELECT
dept
,dept_char
,outvalue

FROM
jobs_last_row
UNION ALL
SELECT
dept
,dept_char
,outvalue
FROM
data_last_row)
SELECT
dept_char || ',' ||
outvalue AS output
FROM
data_and_jobs
ORDER BY dept;
Figure 975, Transform numeric data - part 2 of 2

DATA_INPUT
OUTPUT
===================
=====================================
DEPT JOB
SUM_SAL
DEPT,
Clerk,
Mgr,
Sales
---- ----- -------10,
0.00, 22959.20,
0.00
10 Mgr
22959.20
15, 24766.70, 20659.80, 16502.83
15 Clerk 24766.70
20, 27757.35, 18357.50, 18171.25
15 Mgr
20659.80
38, 24964.50, 17506.75, 34814.30
15 Sales 16502.83
42, 10505.90, 18352.80, 18001.75
20 Clerk 27757.35
51,
0.00, 21150.00, 19456.50
20 Mgr
18357.50
20 Sales 18171.25
38 Clerk 24964.50
38 Mgr
17506.75
38 Sales 34814.30
42 Clerk 10505.90
42 Mgr
18352.80
42 Sales 18001.75
51 Mgr
21150.00
51 Sales 19456.50
Figure 976, Contents of first temporary table and final output

--#SET DELIMITER !

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

CREATE FUNCTION reverse(instr VARCHAR(50))


RETURNS VARCHAR(50)
BEGIN ATOMIC
DECLARE outstr VARCHAR(50) DEFAULT '';
DECLARE curbyte SMALLINT
DEFAULT 0;
SET curbyte = LENGTH(RTRIM(instr));
WHILE curbyte >= 1 DO
SET outstr = outstr || SUBSTR(instr,curbyte,1);
SET curbyte = curbyte - 1;
END WHILE;
RETURN outstr;
END!
ANSWER
SELECT
id
AS ID
====================
,name
AS NAME1
ID NAME1
NAME2
,reverse(name) AS NAME2
-- -------- ------FROM
staff
10 Sanders srednaS
WHERE
id < 40
20 Pernal
lanreP

ORDER BY id!
Figure 977, Reversing character field

30 Marenghi ihgneraM

SELECT

id
AS ID
,salary
AS SALARY1
,DEC(reverse(CHAR(salary)),7,4) AS SALARY2
FROM
staff
ANSWER
WHERE
id < 40
===================
ORDER BY id;
ID SALARY1 SALARY2
-- -------- ------10 18357.50 5.7538
20 18171.25 52.1718
30 17506.75 57.6057
Figure 978, Reversing numeric field

WITH temp (txt) AS


ANSWER
(VALUES ('
HAS LEADING BLANKS')
=======================
,('HAS TRAILING BLANKS ')
TXT2
LEN
,(' BLANKS BOTH ENDS
'))
------------------- --SELECT LTRIM(RTRIM(txt))
AS txt2
HAS LEADING BLANKS
18
,LENGTH(LTRIM(RTRIM(txt))) AS len
HAS TRAILING BLANKS 19
FROM
temp;
BLANKS BOTH ENDS
16
Figure 979, Stripping leading and trailing blanks

--#SET DELIMITER !
CREATE FUNCTION strp(in_val VARCHAR(20),in_strip VARCHAR(1))
RETURNS VARCHAR(20)
BEGIN ATOMIC
DECLARE cur_pos SMALLINT;
DECLARE stp_flg CHAR(1);
DECLARE out_val VARCHAR(20);
IF in_strip = '' THEN
SIGNAL SQLSTATE '75001'
SET MESSAGE_TEXT = 'Strip char is zero length';
END IF;
SET cur_pos = 1;
SET stp_flg = 'Y';
WHILE stp_flg = 'Y' AND cur_pos <= length(in_val) DO
IF SUBSTR(in_val,cur_pos,1) <> in_strip THEN
SET stp_flg = 'N';
ELSE
SET cur_pos = cur_pos + 1;
END IF;
END WHILE;
SET out_val = SUBSTR(in_val,cur_pos);
SET cur_pos = length(out_val);
SET stp_flg = 'Y';

WHILE stp_flg = 'Y' AND cur_pos >= 1 DO


IF SUBSTR(out_val,cur_pos,1) <> in_strip THEN
SET stp_flg = 'N';
ELSE
SET cur_pos = cur_pos - 1;
END IF;
END WHILE;
SET out_val = SUBSTR(out_val,1,cur_pos);
RETURN out_val;
END!
Figure 980, Define strip function

WITH word1 (w#, word_val) AS


(VALUES(1,'00 abc 000')
,(2,'0 0 abc')
,(3,' sdbs')
,(4,'000 0')
,(5,'0000')
,(6,'0')
,(7,'a')
,(8,''))
SELECT
w#
,word_val
,strp(word_val,'0')
AS stp
,length(strp(word_val,'0')) AS len
FROM
word1
ORDER BY w#;
Figure 981, Use strip function

IMPORTANT
============
This example
uses an "!"
as the stmt
delimiter.

ANSWER
========================
W# WORD_VAL
STP
LEN
-- ---------- ------ --1 00 abc 000 abc
5
2 0 0 abc
0 abc
6
3 sdbs
sdbs
5
4 000 0
1
5 0000
0
6 0
0
7 a
a
1
8
0

WITH temp1 (num,ts1,ts2) AS


(VALUES (INT(1)
,TIMESTAMP(GENERATE_UNIQUE())
,TIMESTAMP(GENERATE_UNIQUE()))
UNION ALL
SELECT num + 1
,ts1
,TIMESTAMP(GENERATE_UNIQUE())
FROM
temp1
WHERE
TIMESTAMPDIFF(2,CHAR(ts2-ts1)) < 4
)
SELECT MAX(num) AS #loops
,MIN(ts2) AS bgn_timestamp
,MAX(ts2) AS end_timestamp
FROM
temp1;
ANSWER
============================================================
#LOOPS BGN_TIMESTAMP
END_TIMESTAMP
------ -------------------------- -------------------------58327 2001-08-09-22.58.12.754579 2001-08-09-22.58.16.754634
Figure 982, Run query for four seconds

CREATE FUNCTION pause(inval INT)


RETURNS INTEGER
NOT DETERMINISTIC
EXTERNAL ACTION
RETURN
WITH ttt (num, strt, stop) AS
(VALUES (1
,TIMESTAMP(GENERATE_UNIQUE())
,TIMESTAMP(GENERATE_UNIQUE()))
UNION ALL
SELECT num + 1
,strt
,TIMESTAMP(GENERATE_UNIQUE())
FROM
ttt
WHERE
TIMESTAMPDIFF(2,CHAR(stop - strt)) < inval
)
SELECT MAX(num)
FROM
ttt;
Figure 983, Function that pauses for "n" seconds

SELECT

id
,SUBSTR(CHAR(TIMESTAMP(GENERATE_UNIQUE())),18) AS ss_mmmmmm
,pause(id / 10)
AS #loops
,SUBSTR(CHAR(TIMESTAMP(GENERATE_UNIQUE())),18) AS ss_mmmmmm
FROM
staff
WHERE
id < 31;
ANSWER
=============================
ID SS_MMMMMM #LOOPS SS_MMMMMM
-- --------- ------ --------10 50.068593 76386 50.068587
20 52.068744 144089 52.068737
30 55.068930 206101 55.068923
Figure 984, Query that uses pause function

--#SET DELIMITER !
CREATE FUNCTION sort_char(in_val VARCHAR(20),sort_dir VARCHAR(1))
RETURNS VARCHAR(20)
BEGIN ATOMIC
DECLARE cur_pos SMALLINT;
DECLARE do_sort CHAR(1);
DECLARE out_val VARCHAR(20);
IF UCASE(sort_dir) NOT IN ('A','D') THEN
SIGNAL SQLSTATE '75001'
SET MESSAGE_TEXT = 'Sort order not ''A'' or ''D''';
END IF;
SET out_val = in_val;
SET do_sort = 'Y';
WHILE do_sort = 'Y' DO

SET do_sort = 'N';


IMPORTANT
SET cur_pos = 1;
============
WHILE cur_pos < length(in_val) DO
This example
IF (UCASE(sort_dir)
= 'A'
uses an "!"
AND SUBSTR(out_val,cur_pos+1,1) <
as the stmt
SUBSTR(out_val,cur_pos,1))
delimiter.
OR (UCASE(sort_dir)
= 'D'
AND SUBSTR(out_val,cur_pos+1,1) >
SUBSTR(out_val,cur_pos,1)) THEN
SET do_sort = 'Y';
SET out_val = CASE
WHEN cur_pos = 1
THEN ''
ELSE SUBSTR(out_val,1,cur_pos-1)
END
CONCAT SUBSTR(out_val,cur_pos+1,1)
CONCAT SUBSTR(out_val,cur_pos ,1)
CONCAT
CASE
WHEN cur_pos = length(in_val) - 1
THEN ''
ELSE SUBSTR(out_val,cur_pos+2)
END;
END IF;
SET cur_pos = cur_pos + 1;
END WHILE;
END WHILE;
RETURN out_val;
END!
Figure 985, Define sort-char function

WITH word1 (w#, word_val) AS


(VALUES(1,'12345678')
,(2,'ABCDEFG')
,(3,'AaBbCc')
,(4,'abccb')
,(5,'''%#.')
,(6,'bB')
,(7,'a')
,(8,''))
SELECT
w#
,word_val
,sort_char(word_val,'a') sa
,sort_char(word_val,'D') sd
FROM
word1
ORDER BY w#;
Figure 986, Use sort-char function

ANSWER
=============================
W# WORD_VAL SA
SD
-- --------- ------- -------1 12345678 12345678 87654321
2 ABCDEFG ABCDEFG GFEDCBA
3 AaBbCc
aAbBcC
CcBbAa
4 abccb
abbcc
ccbba
5 '%#.
.'#%
%#'.
6 bB
bB
Bb
7 a
a
a
8

WITH numbered_rows AS
(SELECT
s.*
,ROW_NUMBER() OVER(PARTITION BY job
ORDER
BY salary, id) AS row#
FROM
staff s

WHERE
comm
> 0
AND
name LIKE '%e%'),
median_row_num AS
(SELECT
job
,(MAX(row# + 1.0) / 2) - 0.5 AS med_lo
,(MAX(row# + 1.0) / 2) + 0.5 AS med_hi
FROM
numbered_rows
GROUP BY job)
SELECT
nn.job
,DEC(AVG(nn.salary),7,2) AS med_sal
FROM
numbered_rows
nn
,median_row_num mr
WHERE
nn.job
= mr.job
AND
nn.row# BETWEEN mr.med_lo AND mr.med_hi
GROUP BY nn.job
ORDER BY nn.job;
Figure 987, Calculating the median

ANSWER
==============
JOB
MED_SAL
----- -------Clerk 13030.50
Sales 17432.10

WITH numbered_rows AS
(SELECT
s.*
,ROW_NUMBER() OVER(PARTITION BY job
ORDER
BY salary, id) AS row#
FROM
staff s
WHERE
comm
> 0
AND
name LIKE '%e%'),
median_row_num AS
(SELECT
job
,(MAX(row# + 1.0) / 2) - 0.5 AS med_lo
,(MAX(row# + 1.0) / 2) + 0.5 AS med_hi
,DEC(AVG(salary),7,2)
AS avg_sal
,COUNT(*)
AS #rows
FROM
numbered_rows
GROUP BY job)
SELECT
nn.job
,DEC(AVG(nn.salary),7,2) AS med_sal
,MAX(mr.avg_sal)
AS avg_sal
,MAX(mr.#rows)
AS #r
FROM
numbered_rows
nn
,median_row_num mr
ANSWER
WHERE
nn.job
= mr.job
==========================
AND
nn.row# BETWEEN mr.med_lo
JOB
MED_SAL AVG_SAL #R
AND mr.med_hi
----- -------- -------- -GROUP BY nn.job
Clerk 13030.50 12857.56 7
ORDER BY nn.job;
Sales 17432.10 17460.93 4
Figure 988, Get median plus average

WITH numbered_rows AS
(SELECT
s.*
,ROW_NUMBER() OVER(PARTITION BY job
ORDER
BY salary, id) AS row#
FROM
staff s
WHERE
comm
> 0
AND
name LIKE '%e%'),

median_row_num AS
(SELECT
job
,MAX(row# + 1) / 2 AS med_row#
FROM
numbered_rows
GROUP BY job)
SELECT
nn.job
,nn.salary AS med_sal
FROM
numbered_rows
nn
,median_row_num mr
WHERE
nn.job = mr.job
AND
nn.row# = mr.med_row#
ORDER BY nn.job;
Figure 989, Calculating the median

ANSWER
==============
JOB
MED_SAL
----- -------Clerk 13030.50
Sales 16858.20

WITH numbered_rows AS
(SELECT
s.*
,ROW_NUMBER() OVER(PARTITION BY job
ORDER
BY salary, id) AS row#
FROM
staff s
WHERE
comm
> 0
AND
name LIKE '%e%')
SELECT
job
,salary AS med_sal
FROM
numbered_rows
WHERE
(job,row#) IN
ANSWER
(SELECT
job
==============
,MAX(row# + 1) / 2
JOB
MED_SAL
FROM
numbered_rows
----- -------GROUP BY job)
Clerk 13030.50
ORDER BY job;
Sales 16858.20
Figure 990, Calculating the median

WITH numbered_rows AS
(SELECT
s.*
,ROW_NUMBER() OVER(PARTITION BY job
ORDER
BY salary, id) AS row#
FROM
staff s
WHERE
comm
> 0
AND
name LIKE '%e%')
SELECT
r1.*
,(SELECT r2.salary
FROM
numbered_rows r2
WHERE
r2.job = r1.job
AND
r2.row# = (SELECT MAX(r3.row# + 1) / 2
FROM
numbered_rows r3
WHERE
r2.job = r3.job)) AS med_sal
FROM
numbered_rows r1
ORDER BY job
,salary;
Figure 991, List matching rows and median

WITH temp1 (c1,t1,t2) AS (VALUES


('A'
,TIMESTAMP('1996-05-01-24.00.00.000000')
,TIMESTAMP('1996-05-02-00.00.00.000000') ))
SELECT c1
FROM
temp1
WHERE t1 = t2;
Figure 992, Timestamp comparison - Incorrect

WITH temp1 (c1,t1,t2) AS (VALUES


('A'
,TIMESTAMP('1996-05-01-24.00.00.000000')
,TIMESTAMP('1996-05-02-00.00.00.000000') ))
SELECT c1
FROM
temp1
WHERE t1 + 0 MICROSECOND = t2 + 0 MICROSECOND;
Figure 993, Timestamp comparison - Correct

CREATE TABLE supermarket_sales


(sales_ts
TIMESTAMP
NOT NULL
,sales_val DECIMAL(8,2)
NOT NULL
,PRIMARY KEY(sales_ts));
Figure 994, Sample Table

INSERT INTO supermarket_sales VALUES


('2003-08-01-24.00.00.000000',123.45);
Figure 995, Insert row

SELECT
*
FROM
supermarket_sales
WHERE
DATE(sales_ts) = '2003-08-01'
ORDER BY sales_ts;
Figure 996, Select rows for given date

SELECT

ANSWER
=========

ANSWER
======
C1
-A

FROM
WHERE

supermarket_sales
sales_ts BETWEEN '2003-08-01-00.00.00'
AND '2003-08-01-24.00.00'
ORDER BY sales_ts;
Figure 997, Select rows for given date

SELECT
creator
FROM
sysibm.systables
WHERE
creator = 'ZZZ';
Figure 998, Query with no matching rows (1 of 8)

ANSWER
========

SELECT
MAX(creator)
FROM
sysibm.systables
WHERE
creator = 'ZZZ';
Figure 999, Query with no matching rows (2 of 8)

ANSWER
======

SELECT
MAX(creator)
FROM
sysibm.systables
WHERE
creator = 'ZZZ'
HAVING
MAX(creator) IS NOT NULL;
Figure 1000, Query with no matching rows (3 of 8)

ANSWER
========

SELECT
MAX(creator)
FROM
sysibm.systables
WHERE
creator
= 'ZZZ'
HAVING
MAX(creator) = 'ZZZ';
Figure 1001, Query with no matching rows (4 of 8)

ANSWER
========

SELECT
MAX(creator)
FROM
sysibm.systables
WHERE
creator = 'ZZZ'
GROUP BY creator;
Figure 1002, Query with no matching rows (5 of 8)

ANSWER
========

SELECT
creator
FROM
sysibm.systables
WHERE
creator = 'ZZZ'
GROUP BY creator;
Figure 1003, Query with no matching rows (6 of 8)

ANSWER
========

SELECT
COUNT(*)
FROM
sysibm.systables
WHERE
creator = 'ZZZ'
GROUP BY creator;
Figure 1004, Query with no matching rows (7 of 8)

ANSWER
========

SELECT
COUNT(*)
FROM
sysibm.systables
WHERE
creator = 'ZZZ';
Figure 1005, Query with no matching rows (8 of 8)

ANSWER
======
0

SELECT

COALESCE(name,noname) AS nme
,COALESCE(salary,nosal) AS sal
FROM
(SELECT
'NO NAME' AS noname
,0
AS nosal
FROM
sysibm.sysdummy1
)AS nnn
LEFT OUTER JOIN
(SELECT
*
FROM
staff
WHERE
id < 5
)AS xxx
ON
1 = 1
ORDER BY name;
Figure 1006, Always get a row, example 1 of 2

ANSWER
============
NME
SAL
------- ---NO NAME 0.00

WITH nnn (noname, nosal) AS


(VALUES ('NO NAME',0))
SELECT
COALESCE(name,noname) AS nme
,COALESCE(salary,nosal) AS sal
FROM
nnn
LEFT OUTER JOIN
(SELECT
*
FROM
staff
WHERE
id < 5
)AS xxx

ANSWER
============
NME
SAL
------- ---NO NAME 0.00

ON
1 = 1
ORDER BY NAME;
Figure 1007, Always get a row, example 2 of 2

SELECT
FROM

DATE('2001-09-22')
sysibm.sysdummy1;

ANSWER
==========
2001-09-22

Figure 1008, Convert value to DB2 date, right

SELECT
FROM

DATE(2001-09-22)
sysibm.sysdummy1;

ANSWER
==========
0006-05-24

Figure 1009, Convert value to DB2 date, wrong

SELECT

id
,name
FROM
staff
WHERE
id <= 100
AND
id
= (INT(RAND()* 10) * 10) + 10
ORDER BY id;
Figure 1010, Get random rows - Incorrect

WITH temp AS
(SELECT
id
,name
,(INT(RAND(0)* 10) * 10) + 10 AS ran
FROM
staff
WHERE
id <= 100
)
SELECT
t.*
,CASE id
WHEN ran THEN 'Y'
ELSE
' '
END AS eql
FROM
temp t
ORDER BY id;
Figure 1011, Get random rows - Explanation

ANSWER
===========
ID NAME
-- -------30 Marenghi
60 Quigley

ANSWER
====================
ID NAME
RAN EQL
--- -------- --- --10 Sanders
10 Y
20 Pernal
30
30 Marenghi 70
40 O'Brien
10
50 Hanes
30
60 Quigley
40
70 Rothman
30
80 James
100
90 Koonitz
40
100 Plotz
100 Y

WITH
staff_numbered AS
(SELECT s.*
,ROW_NUMBER() OVER() AS row#
FROM
staff s
WHERE
id <= 100
),
count_rows AS
(SELECT MAX(row#) AS #rows
FROM
staff_numbered
),
random_values (RAN#) AS
(VALUES (RAND())
,(RAND())
,(RAND())
),
rows_t0_get AS
(SELECT INT(ran# * #rows) + 1 AS get_row
FROM
random_values
,count_rows
)
SELECT
id
,name
FROM
staff_numbered
,rows_t0_get
WHERE
row# = get_row
ORDER BY id;
Figure 1012, Get random rows - Non-distinct

ANSWER
===========
ID NAME
--- ------10 Sanders
20 Pernal
90 Koonitz

SELECT

ANSWER
===========
ID NAME
-- -------10 Sanders
40 O'Brien
60 Quigley

id
,name
FROM
(SELECT s.*
,ROW_NUMBER() OVER(ORDER BY RAND()) AS r
FROM
staff s
WHERE id <= 100
)AS xxx
WHERE
r <= 3
ORDER BY id;
Figure 1013, Get random rows - Distinct

WITH temp1 (bgn_tstamp, elp_sec) AS


(VALUES (TIMESTAMP('2001-01-15-01.02.03.000000'), 1.234)
,(TIMESTAMP('2001-01-15-01.02.03.123456'), 1.234)
)
SELECT
bgn_tstamp
,elp_sec
,bgn_tstamp + elp_sec SECONDS AS end_tstamp
FROM
temp1;

ANSWER
======

BGN_TSTAMP
ELP_SEC
-------------------------- ------2001-01-15-01.02.03.000000
1.234
2001-01-15-01.02.03.123456
1.234
Figure 1014, Date/Time manipulation - wrong

END_TSTAMP
-------------------------2001-01-15-01.02.04.000000
2001-01-15-01.02.04.123456

WITH temp1 (bgn_tstamp, elp_sec) AS


(VALUES (TIMESTAMP('2001-01-15-01.02.03.000000'), 1.234)
,(TIMESTAMP('2001-01-15-01.02.03.123456'), 1.234)
)
SELECT
bgn_tstamp
,elp_sec
,bgn_tstamp + (elp_sec *1E6) MICROSECONDS AS end_tstamp
FROM
temp1;

ANSWER
======
BGN_TSTAMP
ELP_SEC
-------------------------- ------2001-01-15-01.02.03.000000
1.234
2001-01-15-01.02.03.123456
1.234
Figure 1015, Date/Time manipulation - right

END_TSTAMP
-------------------------2001-01-15-01.02.04.234000
2001-01-15-01.02.04.357456

WITH temp1 (c0,c1,v1) AS (VALUES


('A',CHAR(' ',1),VARCHAR(' ',1)),
('B',CHAR(' ',1),VARCHAR('' ,1)))
SELECT c0
FROM
temp1
WHERE c1 = v1
AND c1 LIKE ' ';
Figure 1016, Use LIKE on CHAR field

ANSWER
======
C0
-A
B

WITH temp1 (c0,c1,v1) AS (VALUES


('A',CHAR(' ',1),VARCHAR(' ',1)),
('B',CHAR(' ',1),VARCHAR('' ,1)))
SELECT c0
FROM
temp1
WHERE c1 = v1
AND v1 LIKE ' ';
Figure 1017, Use LIKE on VARCHAR field

ANSWER
======
C0
-A

WITH temp1 (c0,c1,v1) AS (VALUES


('A',CHAR(' ',1),VARCHAR(' ',1)),
('B',CHAR(' ',1),VARCHAR('' ,1)))
SELECT c0
FROM
temp1
WHERE c1 = v1
AND RTRIM(v1) LIKE '';
Figure 1018, Use RTRIM to remove trailing blanks

ANSWER
======
C0
-A
B

WITH temp1 (yymmdd) AS


ANSWER
(VALUES DATE('2000-01-01')
==========================
UNION ALL
YEAR MIN_DT
MAX_DT
SELECT yymmdd + 1 DAY
---- ---------- ---------FROM
temp1
2000 2000-08-06 2000-08-12
WHERE yymmdd < '2010-12-31'
2001 2001-08-12 2001-08-18
)
2002 2002-08-11 2002-08-17
SELECT
yy
AS year
2003 2003-08-10 2003-08-16
,CHAR(MIN(yymmdd),ISO) AS min_dt
2004 2004-08-08 2004-08-14
,CHAR(MAX(yymmdd),ISO) AS max_dt
2005 2005-08-07 2005-08-13
FROM
(SELECT yymmdd
2006 2006-08-13 2006-08-19
,YEAR(yymmdd) yy
2007 2007-08-12 2007-08-18
,WEEK(yymmdd) wk
2008 2008-08-10 2008-08-16
FROM
temp1
2009 2009-08-09 2009-08-15
WHERE WEEK(yymmdd) = 33
2010 2010-08-08 2010-08-14
)AS xxx
GROUP BY yy
,wk;
Figure 1019, Comparing week 33 over 10 years

SELECT
FROM

SUM(INTEGER(salary)) AS s1
,INTEGER(SUM(salary)) AS s2
staff;

ANSWER
=============
S1
S2
------ -----583633 583647

Figure 1020, DB2 data truncation

SELECT
FROM

SUM(INTEGER(ROUND(salary,-1))) AS s1
,INTEGER(SUM(salary)) AS s2
staff;

Figure 1021, DB2 data rounding

ANSWER
=============
S1
S2
------ -----583640 583647

SELECT

lastname
,sex
,CASE
WHEN sex >=
WHEN sex >=
END AS sxx
FROM
employee
WHERE
lastname LIKE
ORDER BY 1;
Figure 1022, Case WHEN

lastname
,sex
,CASE
WHEN sex >=
WHEN sex >=
END AS sxx
FROM
employee
WHERE
lastname LIKE
ORDER BY 1;
Figure 1023, Case WHEN

ANSWER
=================
LASTNAME
SX SXX
---------- -- --JEFFERSON M FEM
JOHNSON
F FEM
JONES
M FEM

'F' THEN 'FEM'


'M' THEN 'MAL'
'J%'
Processing - Incorrect

SELECT

'M' THEN 'MAL'


'F' THEN 'FEM'
'J%'
Processing - Correct

SELECT

AVG(salary) / AVG(comm) AS a1
,AVG(salary / comm)
AS a2
FROM
staff;
Figure 1024, Division and Average

SELECT
FROM
WHERE
ORDER BY

ANSWER
=================
LASTNAME
SX SXX
---------- -- --JEFFERSON M MAL
JOHNSON
F FEM
JONES
M MAL

ANSWER >>>

hiredate
employee
hiredate < '1960-01-01'
1;

Figure 1025, DATE output in year, month, day order

SELECT
FROM
WHERE
ORDER BY

CHAR(hiredate,USA)
employee
hiredate < '1960-01-01'
1;

Figure 1026, DATE output in month, day, year order

A1
-32

A2
----61.98

ANSWER
==========
1947-05-05
1949-08-17
1958-05-16

ANSWER
==========
05/05/1947
05/16/1958
08/17/1949

EXEC-SQL
DECLARE fred CURSOR FOR
SELECT
*
FROM
staff
WHERE
id < 1000
ORDER BY id;
END-EXEC;
EXEC-SQL
OPEN fred
END-EXEC;
DO UNTIL SQLCODE = 100;
EXEC-SQL
FETCH fred
INTO :HOST-VARS
END-EXEC;
IF SQLCODE <> 100 THEN DO;
SET HOST-VAR.ID = HOST-VAR.ID + 500;
EXEC-SQL
INSERT INTO staff VALUES (:HOST-VARS)
END-EXEC;
END-DO;
END-DO;
EXEC-SQL
CLOSE fred
END-EXEC;
Figure 1027, Ambiguous Cursor

SELECT

region_code
AS region
,product_type AS ptype
,order_number AS order#
,order_value
AS value
FROM
order_table
WHERE
order_date = '2005-12-22'
ORDER BY region_code
,product_type
WITH CS;
Figure 1028, Select from ORDER table

REGION
-----EAST
EAST
EAST
EAST

PTYPE
----GOOD
JUNK
NICE
NICE

ORDER#
-----111
222
333
444

VALUE
----4.66
6.33
123.45
123.45

<----- Same ORDER#


|
|
|

EAST
TRASH
111
4.66
Figure 1029, Sample query output

<---+

SAME RESULT
CURSOR "WITH" OPTION
IF RUN TWICE
===================== ============
RR - Repeatable Read
Yes
RS - Read Stability
No (inserts)
CS - Cusor Stability
No (all DML)
UR - Uncommitted Read No (all DML)
Figure 1030, WITH Option vs. Actions

FETCH SAME
ROW > ONCE
==========
Never
Never
Maybe
Maybe

UNCOMMITTED
ROWS SEEN
===========
Never
Never
Never
Yes

ROWS
LOCKED
========
Many/All
Many/All
Current
None

WITH temp (f1) AS


(VALUES FLOAT(1.23456789)
UNION ALL
SELECT f1 * 10
FROM
temp
WHERE f1 < 1E18
)
SELECT f1
AS float1
,DEC(f1,19) AS decimal1
,BIGINT(f1) AS bigint1
FROM
temp;
Figure 1031, Multiply floating-point number by ten, SQL

FLOAT1
DECIMAL1
BIGINT1
------------------------ -------------------- ------------------+1.23456789000000E+000
1.
1
+1.23456789000000E+001
12.
12
+1.23456789000000E+002
123.
123
+1.23456789000000E+003
1234.
1234
+1.23456789000000E+004
12345.
12345
+1.23456789000000E+005
123456.
123456
+1.23456789000000E+006
1234567.
1234567
+1.23456789000000E+007
12345678.
12345678
+1.23456789000000E+008
123456789.
123456788
+1.23456789000000E+009
1234567890.
1234567889
+1.23456789000000E+010
12345678900.
12345678899
+1.23456789000000E+011
123456789000.
123456788999
+1.23456789000000E+012
1234567890000.
1234567889999
+1.23456789000000E+013
12345678900000.
12345678899999
+1.23456789000000E+014
123456789000000.
123456788999999
+1.23456789000000E+015
1234567890000000.
1234567889999999
+1.23456789000000E+016
12345678900000000.
12345678899999998
+1.23456789000000E+017
123456789000000000.
123456788999999984
+1.23456789000000E+018 1234567890000000000. 1234567889999999744
Figure 1032, Multiply floating-point number by ten, answer

WITH temp (f1,f2) AS


(VALUES (FLOAT(1.23456789E1 * 10 * 10 * 10 * 10 * 10 * 10 * 10)
,FLOAT(1.23456789E8)))
SELECT f1
,f2
FROM
temp
ANSWER
WHERE f1 <> f2;
=============================================
F1
F2
---------------------- ---------------------+1.23456789000000E+008 +1.23456789000000E+008
Figure 1033, Two numbers that look equal, but aren't equal

WITH temp (f1,f2) AS


(VALUES (FLOAT(1.23456789E1 * 10 * 10 * 10 * 10 * 10 * 10 * 10)
,FLOAT(1.23456789E8)))
SELECT HEX(f1) AS hex_f1
,HEX(f2) AS hex_f2
FROM
temp
ANSWER
WHERE f1 <> f2;
=================================
HEX_F1
HEX_F2
---------------- ---------------FFFFFF53346F9D41 00000054346F9D41
Figure 1034, Two numbers that look equal, but aren't equal, shown in HEX

WITH
temp1 (dec1, dbl1) AS
(VALUES (DECIMAL(1),DOUBLE(1)))
,temp2 (dec1, dec2, dbl1, dbl2) AS
(SELECT dec1
,dec1 / 3 AS dec2
,dbl1
ANSWER (1 row returned)
,dbl1 / 3 AS dbl2
==============================
FROM
temp1)
DEC1 = 1.0
SELECT *
DEC2 = 0.33333333333333333333
FROM
temp2
DBL1 = +1.00000000000000E+000
WHERE dbl2 <> dec2;
DBL2 = +3.33333333333333E-001
Figure 1035, Comparing float and decimal division

WITH temp (f1, d1) AS


(VALUES (FLOAT(1.23456789)
,DEC(1.23456789,20,10))
UNION ALL
SELECT f1 * 10

FROM
WHERE

,d1 * 10
temp
f1 < 1E9

)
SELECT f1
,d1
,CASE
WHEN d1 = f1 THEN 'SAME'
ELSE
'DIFF'
END AS compare
FROM
temp;
Figure 1036, Comparing float and decimal multiplication, SQL

F1
D1
COMPARE
---------------------- --------------------- ------+1.23456789000000E+000
1.2345678900 SAME
+1.23456789000000E+001
12.3456789000 SAME
+1.23456789000000E+002
123.4567890000 DIFF
+1.23456789000000E+003
1234.5678900000 DIFF
+1.23456789000000E+004
12345.6789000000 DIFF
+1.23456789000000E+005
123456.7890000000 DIFF
+1.23456789000000E+006
1234567.8900000000 SAME
+1.23456789000000E+007
12345678.9000000000 DIFF
+1.23456789000000E+008
123456789.0000000000 DIFF
+1.23456789000000E+009 1234567890.0000000000 DIFF
Figure 1037, Comparing float and decimal multiplication, answer

WITH temp (f1) AS


ANSWER
(VALUES FLOAT(0.1))
=======================================
SELECT f1
F1
HEX_F1
,HEX(f1) AS hex_f1
---------------------- ---------------FROM
temp;
+1.00000000000000E-001 9A9999999999B93F
Figure 1038, Internal representation of "one tenth" in floating-point

You might also like