Author: Graeme Birchall ©
Address: 1 River Court, Apt 1706
Jersey City NJ 07310-2007
Ph/Fax: (201)-963-0071
Email: Graeme_Birchall@compuserve.com
Web: http://ourworld.compuserve.com/homepages/Graeme_Birchall
Title: DB2 UDB V7.2 SQL Cookbook ©
Print: 11 March, 2002
Fname: BOOK08.DOC
#pages: 177
CREATE TABLE EMPLOYEE
(EMPNO CHARACTER (00006) NOT NULL
,FIRSTNME VARCHAR (00012) NOT NULL
,MIDINIT CHARACTER (00001) NOT NULL
,LASTNAME VARCHAR (00015) NOT NULL
,WORKDEPT CHARACTER (00003)
,PHONENO CHARACTER (00004)
,HIREDATE DATE
,JOB CHARACTER (00008)
,EDLEVEL SMALLINT NOT NULL
,SEX CHARACTER (00001)
,BIRTHDATE DATE
,SALARY DECIMAL (00009,02)
,BONUS DECIMAL (00009,02)
,COMM DECIMAL (00009,02)
)
DATA CAPTURE NONE;
Figure 2, 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 3, 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 4, Define a view using a VALUES clause
SELECT C1, C2, C3 ANSWER
FROM SILLY ===========
ORDER BY C1 ASC; C1 C2 C3
-- --- --
13 AAA 22
12 BBB 33
11 CCC -
Figure 5, 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 6, Define a view that creates data on the fly
CREATE ALIAS EMPLOYEE_AL1 FOR EMPLOYEE;
COMMIT;
CREATE ALIAS EMPLOYEE_AL2 FOR EMPLOYEE_AL1;
COMMIT;
CREATE ALIAS EMPLOYEE_AL3 FOR EMPLOYEE_AL2;
COMMIT;
Figure 7, Define three aliases, the latter on the earlier
Figure 8, SELECT Statement Syntax (general)
Figure 9, SELECT Statement Syntax
SELECT DEPTNO ANSWER
,ADMRDEPT ===================
,'ABC' AS ABC DEPTNO ADMRDEPT ABC
FROM DEPARTMENT ------ -------- ---
WHERE DEPTNAME LIKE '%ING%' B01 A00 ABC
ORDER BY 1; D11 D01 ABC
Figure 10, Sample SELECT statement
SELECT * ANSWER (part of)
FROM DEPARTMENT ================
WHERE DEPTNAME LIKE '%ING%' DEPTNO etc...
ORDER BY 1; ------ ------>>>
B01 PLANNING
D11 MANUFACTU
Figure 11, Use "*" to select all columns in table
SELECT DEPTNO ANSWER (part of)
,DEPARTMENT.* =======================
FROM DEPARTMENT DEPTNO DEPTNO etc...
WHERE DEPTNAME LIKE '%ING%' ------ ------ ------>>>
ORDER BY 1; B01 B01 PLANNING
D11 D11 MANUFACTU
Figure 12, 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 13, Select all columns twice
Figure 14, Fetch First clause Syntax
SELECT YEARS ANSWER
,NAME =====================
,ID YEARS NAME ID
FROM STAFF ------ --------- ----
FETCH FIRST 3 ROWS ONLY; 7 Sanders 10
8 Pernal 20
5 Marenghi 30
Figure 15, FETCH FIRST without ORDER BY, gets random rows
SELECT YEARS ANSWER
,NAME =====================
,ID YEARS NAME ID
FROM STAFF ------ --------- ----
WHERE YEARS IS NOT NULL 13 Graham 310
ORDER BY YEARS DESC 12 Jones 260
FETCH FIRST 3 ROWS ONLY; 10 Hanes 50
Figure 16, FETCH FIRST with ORDER BY, gets wrong answer
SELECT YEARS ANSWER
,NAME =====================
,ID YEARS NAME ID
FROM STAFF ------ --------- ----
WHERE YEARS IS NOT NULL 13 Graham 310
ORDER BY YEARS DESC 12 Jones 260
,ID DESC 10 Quill 290
FETCH FIRST 3 ROWS ONLY;
Figure 17, FETCH FIRST with ORDER BY, gets right answer
SELECT A.EMPNO ANSWER
,A.LASTNAME =================
FROM EMPLOYEE A EMPNO LASTNAME
,(SELECT MAX(EMPNO)AS EMPNO ------ ----------
FROM EMPLOYEE) AS B 000340 GOUNOT
WHERE A.EMPNO = B.EMPNO;
Figure 18, Correlation Name usage example
SELECT A.EMPNO ANSWER
,A.LASTNAME ======================
,B.DEPTNO AS DEPT EMPNO LASTNAME DEPT
FROM EMPLOYEE A ------ ---------- ----
,DEPARTMENT B 000090 HENDERSON E11
WHERE A.WORKDEPT = B.DEPTNO 000280 SCHNEIDER E11
AND A.JOB <> 'SALESREP' 000290 PARKER E11
AND B.DEPTNAME = 'OPERATIONS' 000300 SMITH E11
AND A.SEX IN ('M','F') 000310 SETRIGHT E11
AND B.LOCATION IS NULL
ORDER BY 1;
Figure 19, Correlation Name usage example
SELECT EMPNO AS E_NUM ANSWER
,MIDINIT AS "M INT" ===================
,PHONENO AS "..." E_NUM M INT ...
FROM EMPLOYEE ------ ----- ----
WHERE EMPNO < '000030' 000010 I 3978
ORDER BY 1; 000020 L 3476
Figure 20, Renaming fields using AS
CREATE VIEW EMP2 AS
SELECT EMPNO AS E_NUM
,MIDINIT AS "M INT"
,PHONENO AS "..."
FROM EMPLOYEE; ANSWER
===================
SELECT * E_NUM M INT ...
FROM EMP2 ------ ----- ----
WHERE "..." = '3978'; 000010 I 3978
Figure 21, View field names defined using AS
SELECT AVG(COMM) AS A1 ANSWER
,SUM(COMM) / COUNT(*) AS A2 ===============
FROM STAFF A1 A2
WHERE ID < 100; ------- ------
796.025 530.68
Figure 22, AVG of data containing null values
SELECT COUNT(*) AS NUM ANSWER
,MAX(LASTNAME) AS MAX ========
FROM EMPLOYEE NUM MAX
WHERE FIRSTNME = 'FRED'; --- ---
0 -
Figure 23, Getting a NULL value from a field defined NOT NULL
SELECT AVG(COMM) AS A1 ANSWER
,SUM(COMM) / COUNT(*) AS A2 ===============
FROM STAFF A1 A2
WHERE ID < 100 ------- ------
AND COMM IS NOT NULL; 796.025 796.02
Figure 24, AVG of those rows that are not null
Figure 25, Basic Predicate syntax
SELECT ID, JOB, DEPT ANSWER
FROM STAFF ===============
WHERE JOB = 'Mgr' ID JOB DEPT
AND NOT JOB <> 'Mgr' --- ---- ----
AND NOT JOB = 'Sales' 10 Mgr 20
AND ID <> 100 30 Mgr 38
AND ID >= 0 50 Mgr 15
AND ID <= 150 140 Mgr 51
AND NOT DEPT = 50
ORDER BY ID;
Figure 26, Basic Predicate examples
Figure 27, Quantified Predicate syntax,1 of 2
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 28, Quantified Predicate example, two single-value sub-queries
SELECT ID, DEPT, JOB ANSWER
FROM STAFF ==============
WHERE (ID,DEPT) = ANY ID DEPT JOB
(SELECT DEPT, ID --- ---- -----
FROM STAFF) 20 20 Sales
ORDER BY 1;
Figure 29, Quantified Predicate example, multi-value sub-query
Figure 30, Quantified Predicate syntax, 2 of 2
SELECT ID, DEPT, JOB ANSWER
FROM STAFF ===========
WHERE (ID,DEPT) = (30,28) ID DEPT JOB
OR (ID,YEARS) = (90, 7) -- ---- ---
OR (DEPT,JOB) = (38,'Mgr') 30 38 Mgr
ORDER BY 1;
Figure 31, Quantified Predicate example, multi-value check
SELECT ID, DEPT, JOB ANSWER
FROM STAFF ===========
WHERE (ID = 30 AND DEPT = 28) ID DEPT JOB
OR (ID = 90 AND YEARS = 7) -- ---- ---
OR (DEPT = 38 AND JOB = 'Mgr') 30 38 Mgr
ORDER BY 1;
Figure 32, Same query as prior, using individual predicates
Figure 33, BETWEEN Predicate syntax
SELECT ID, JOB ANSWER
FROM STAFF =========
WHERE ID BETWEEN 10 AND 30 ID JOB
AND ID NOT BETWEEN 30 AND 10 --- -----
AND NOT ID NOT BETWEEN 10 AND 30 10 Mgr
ORDER BY ID; 20 Sales
30 Mgr
Figure 34, BETWEEN Predicate examples
Figure 35, EXISTS Predicate syntax
SELECT ID, JOB ANSWER
FROM STAFF A =========
WHERE EXISTS ID JOB
(SELECT * --- -----
FROM STAFF B 10 Mgr
WHERE B.ID = A.ID 20 Sales
AND B.ID < 50) 30 Mgr
ORDER BY ID; 40 Sales
Figure 36, EXISTS Predicate example
Figure 37, IN Predicate syntax
SELECT ID, JOB ANSWER
FROM STAFF A =========
WHERE ID IN (10,20,30) ID JOB
AND ID IN (SELECT ID --- -----
FROM STAFF) 10 Mgr
AND ID NOT IN 99 20 Sales
ORDER BY ID; 30 Mgr
Figure 38, IN Predicate examples, single values
SELECT EMPNO, LASTNAME ANSWER
FROM EMPLOYEE ===============
WHERE (EMPNO, 'AD3113') IN EMPNO LASTNAME
(SELECT EMPNO, PROJNO ------ -------
FROM EMP_ACT 000260 JOHNSON
WHERE EMPTIME > 0.5) 000270 PEREZ
ORDER BY 1;
Figure 39, IN Predicate example, multi-value
Figure 40, LIKE Predicate syntax
SELECT ID, NAME ANSWER
FROM STAFF ==============
WHERE NAME LIKE 'S%n' ID NAME
OR NAME LIKE '_a_a%' --- ---------
OR NAME LIKE '%r_%a' 130 Yamaguchi
ORDER BY ID; 200 Scoutten
Figure 41, LIKE Predicate examples
LIKE STATEMENT TEXT WHAT VALUES MATCH
=========================== ======================
LIKE 'AB%' Finds AB, any string
LIKE 'AB%' ESCAPE '+' Finds AB, any string
LIKE 'AB+%' ESCAPE '+' Finds AB%
LIKE 'AB++' ESCAPE '+' Finds AB+
LIKE 'AB+%%' ESCAPE '+' Finds AB%, any string
LIKE 'AB++%' ESCAPE '+' Finds AB+, any string
LIKE 'AB+++%' ESCAPE '+' Finds AB+%
LIKE 'AB+++%%' ESCAPE '+' Finds AB+%, any string
LIKE 'AB+%+%%' ESCAPE '+' Finds AB%%, any string
LIKE 'AB++++' ESCAPE '+' Finds AB++
LIKE 'AB+++++%' ESCAPE '+' Finds AB++%
LIKE 'AB++++%' ESCAPE '+' Finds AB++, any string
LIKE 'AB+%++%' ESCAPE '+' Finds AB%+, any string
Figure 42, LIKE and ESCAPE examples
SELECT ID ANSWER
FROM STAFF ======
WHERE ID = 10 ID
AND 'ABC' LIKE 'AB%' ---
AND 'A%C' LIKE 'A/%C' ESCAPE '/' 10
AND 'A_C' LIKE 'A\_C' ESCAPE '\'
AND 'A_$' LIKE 'A$_$$' ESCAPE '$';
Figure 43, LIKE and ESCAPE examples
Figure 44, NULL Predicate syntax
SELECT ID, COMM ANSWER
FROM STAFF =========
WHERE ID < 100 ID COMM
AND ID IS NOT NULL --- ----
AND COMM IS NULL 10 -
AND NOT COMM IS NOT NULL 30 -
ORDER BY ID; 50 -
Figure 45, NULL Predicate examples
Example: 555 + -22 / (12 - 3) * 66 ANSWER
======
^ ^ ^ ^ ^ 423
5th 2nd 3rd 1st 4th
Figure 46, Precedence rules example
SELECT (12 - 3) AS INT1
, -22 / (12 - 3) AS INT2
, -22 / (12 - 3) * 66 AS INT3
,555 + -22 / (12 - 3) * 66 AS INT4
FROM SYSIBM.SYSDUMMY1; ANSWER
===================
INT1 INT2 INT3 INT4
---- ---- ---- ----
9 -2 -132 423
Figure 47, Precedence rules, integer example
SELECT (12.0 - 3) AS DEC1
, -22 / (12.0 - 3) AS DEC2
, -22 / (12.0 - 3) * 66 AS DEC3
,555 + -22 / (12.0 - 3) * 66 AS DEC4
FROM SYSIBM.SYSDUMMY1; ANSWER
===========================
DEC1 DEC2 DEC3 DEC4
------ ------ ------ ------
9.0 -2.4 -161.3 393.6
Figure 48, Precedence rules, decimal example
SELECT * ANSWER>> COL1 COL2 TABLE1
FROM TABLE1 ---- ---- +---------+
WHERE COL1 = 'C' A AA |COL1|COL2|
AND COL1 >= 'A' B BB |----|----|
OR COL2 >= 'AA'; C CC |A |AA |
|B |BB |
SELECT * |C |CC |
FROM TABLE1 ANSWER>> COL1 COL2 +---------+
WHERE COL1 = 'C' ---- ----
AND (COL1 >= 'A' C CC
OR COL2 >= 'AA');
Figure 49, Use of OR and parenthesis
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 50, Identical query (1 of 3) - using Common Table Expression
SELECT ID ANSWER
,DEPT ==========================
,SALARY ID DEPT SALARY MAX_SAL
,MAX_SAL --- ---- -------- --------
FROM STAFF 10 20 18357.50 18357.50
LEFT OUTER JOIN 190 20 14252.75 18357.50
(SELECT DEPT AS DEPT# 200 42 11508.60 18352.80
,MAX(SALARY) AS MAX_SAL 220 51 17654.50 -
FROM STAFF
WHERE DEPT < 50
GROUP BY DEPT
)AS STAFF_DEPT
ON DEPT = DEPT#
WHERE NAME LIKE 'S%'
ORDER BY ID;
Figure 51, Identical query (2 of 3) - using full-select in FROM
SELECT ID ANSWER
,DEPT ==========================
,SALARY ID DEPT SALARY MAX_SAL
,(SELECT MAX(SALARY) --- ---- -------- --------
FROM STAFF S2 10 20 18357.50 18357.50
WHERE S1.DEPT = S2.DEPT 190 20 14252.75 18357.50
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 52, Identical query (3 of 3) - using full-select in SELECT
Figure 53, 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 54, 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 55, Common Table Expression, using unnamed fields
WITH ANSWER
TEMP1 AS ==========
(SELECT DEPT MAX_AVG
,AVG(SALARY) AS AVG_SAL ----------
FROM STAFF 20865.8625
GROUP BY DEPT),
TEMP2 AS
(SELECT MAX(AVG_SAL) AS MAX_AVG
FROM TEMP1)
SELECT *
FROM TEMP2;
Figure 56, Query with two common table expressions
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 57, Same as prior example, but using nested table expressions
WITH TEMP1 AS ANSWER
(SELECT ID ==========================
,NAME ID DEPT SALARY MAX_SAL
,DEPT --- ---- -------- --------
,SALARY 10 20 18357.50 18357.50
FROM STAFF 190 20 14252.75 18357.50
WHERE ID < 300 200 42 11508.60 11508.60
AND DEPT <> 55 220 51 17654.50 17654.50
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 58, Deriving second temporary table 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 59, Insert using common table expression
INSERT INTO STAFF
SELECT MAX(ID) + 1
,'A',1,'B',2,3,4
FROM STAFF;
Figure 60, 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 61, Nested column function usage
SELECT ID ANSWER
FROM (SELECT * ======
FROM (SELECT ID, YEARS, SALARY ID
FROM (SELECT * ---
FROM (SELECT * 170
FROM STAFF 180
WHERE DEPT < 77 230
)AS T1
WHERE ID < 300
)AS T2
WHERE JOB LIKE 'C%'
)AS T3
WHERE SALARY < 18000
)AS T4
WHERE YEARS < 5;
Figure 62, Nested full-selects
SELECT A.ID ANSWER
,A.DEPT =========================
,A.SALARY ID DEPT SALARY AVG_DEPT
,DEC(B.AVGSAL,7,2) AS AVG_DEPT -- ---- -------- --------
FROM STAFF A 10 20 18357.50 16071.52
LEFT OUTER JOIN 20 20 18171.25 16071.52
(SELECT DEPT AS DEPT 30 38 17506.75 -
,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 63, Join full-select to real table
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 64, 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 65, Full-select without external table reference
SELECT ID ANSWER
,SALARY ====================
,(SELECT MAX(SALARY) ID SALARY MAXSAL
FROM STAFF -- -------- --------
) AS MAXSAL 10 18357.50 22959.20
FROM STAFF A 20 18171.25 22959.20
WHERE ID < 60 30 17506.75 22959.20
ORDER BY ID; 40 18006.00 22959.20
50 20659.80 22959.20
Figure 66, Use an uncorrelated Full-Select in a SELECT list
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 67, 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 68, 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 69, Full-select in INSERT
UPDATE STAFF A ANSWER: SALARY
SET SALARY = ======= =================
(SELECT AVG(SALARY)+ 2000 ID DEPT BEFORE AFTER
FROM STAFF) -- ---- -------- --------
WHERE ID < 60; 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 70, Use uncorrelated Full-Select to give workers company AVG salary (+$2000)
UPDATE STAFF A ANSWER: SALARY
SET SALARY = ======= =================
(SELECT AVG(SALARY) + 2000 ID DEPT BEFORE AFTER
FROM STAFF B -- ---- -------- --------
WHERE A.DEPT = B.DEPT ) 10 20 18357.50 18071.52
WHERE ID < 60; 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 71, Use correlated Full-Select to give workers department AVG salary (+$2000)
Figure 72, CAST expression syntax
SELECT ID ANSWER
,SALARY =================
,CAST(SALARY AS INTEGER) AS SAL2 ID SALARY SAL2
FROM STAFF -- -------- -----
WHERE ID < 30 10 18357.50 18357
ORDER BY ID; 20 18171.25 18171
Figure 73, Use CAST expression to convert Decimal to Integer
SELECT ID ANSWER
,JOB =============
,CAST(JOB AS CHAR(3)) AS JOB2 ID JOB JOB2
FROM STAFF -- ----- ----
WHERE ID < 30 10 Mgr Mgr
ORDER BY ID; 20 Sales Sal
Figure 74, Use CAST expression to truncate Char field
SELECT ID ANSWER
,CAST(NULL AS SMALLINT) AS JUNK =======
FROM STAFF ID JUNK
WHERE ID < 30 -- ----
ORDER BY ID; 10 -
20 -
Figure 75, Use CAST expression to define SMALLINT field with null values
Figure 76, VALUES expression syntax
VALUES 6 <= 1 row, 1 column
VALUES (6) <= 1 row, 1 column
VALUES 6, 7, 8 <= 1 row, 3 columns
VALUES (6), (7), (8) <= 3 rows, 1 column
VALUES (6,66), (7,77), (8,NULL) <= 3 rows, 2 columns
Figure 77, VALUES usage examples
WITH TEMP1 (COL1, COL2) AS ANSWER
(VALUES ( 0, 'AA') =========
,( 1, 'BB') COL1 COL2
,( 2, NULL) ---- ----
) 0 AA
SELECT * 1 BB
FROM TEMP1; 2 -
Figure 78, Use VALUES to define a temporary table (1 of 4)
WITH TEMP1 (COL1, COL2) AS ANSWER
(VALUES (DECIMAL(0 ,3,1), 'AA') =========
,(DECIMAL(1 ,3,1), 'BB') COL1 COL2
,(DECIMAL(2 ,3,1), NULL) ---- ----
) 0.0 AA
SELECT * 1.0 BB
FROM TEMP1; 2.0 -
Figure 79, Use VALUES to define a temporary table (2 of 4)
WITH TEMP1 (COL1, COL2) AS ANSWER
(VALUES ( 0, CAST('AA' AS CHAR(1))) =========
,( 1, CAST('BB' AS CHAR(1))) COL1 COL2
,( 2, CAST(NULL AS CHAR(1))) ---- ----
) 0 A
SELECT * 1 B
FROM TEMP1; 2 -
Figure 80, Use VALUES to define a temporary table (3 of 4)
WITH TEMP1 (COL1, COL2) AS ANSWER
(VALUES ( 0, CHAR('AA',1)) =========
,( 1, CHAR('BB',1)) COL1 COL2
,( 2, NULL) ---- ----
) 0 A
SELECT * 1 B
FROM TEMP1; 2 -
Figure 81, Use VALUES to define a temporary table (4 of 4)
WITH TEMP1 (COL1, COL2, COL3) AS ANSWER
(VALUES ( 0, 'AA', 0.00) ==========
,( 1, 'BB', 1.11) COL1B COLX
,( 2, 'CC', 2.22) ----- ----
) 0 0.00
,TEMP2 (COL1B, COLX) AS 1 2.11
(SELECT COL1 2 4.22
,COL1 + COL3
FROM TEMP1
)
SELECT *
FROM TEMP2;
Figure 82, Derive one temporary table from another
CREATE VIEW SILLY (C1, C2, C3)
AS VALUES (11, 'AAA', SMALLINT(22))
,(12, 'BBB', SMALLINT(33))
,(13, 'CCC', NULL);
COMMIT;
Figure 83, Define a view using a VALUES clause
WITH TEMP1 (COL1) AS ANSWER
(VALUES 0 ======
UNION ALL COL1
SELECT COL1 + 1 ----
FROM TEMP1 0
WHERE COL1 + 1 < 100 1
) 2
SELECT * 3
FROM TEMP1; etc
Figure 84, Use VALUES defined data to seed a recursive SQL statement
Figure 85, CASE expression syntax
SELECT LASTNAME ANSWER
,SEX AS SX ====================
,CASE SEX LASTNAME SX SEXX
WHEN 'F' THEN 'FEMALE' ---------- -- ------
WHEN 'M' THEN 'MALE' JEFFERSON M MALE
ELSE NULL JOHNSON F FEMALE
END AS SEXX JONES M MALE
FROM EMPLOYEE
WHERE LASTNAME LIKE 'J%'
ORDER BY 1;
Figure 86, Use CASE (type 1) to expand a value
SELECT LASTNAME ANSWER
,SEX AS SX ====================
,CASE LASTNAME SX SEXX
WHEN SEX = 'F' THEN 'FEMALE' ---------- -- ------
WHEN SEX = 'M' THEN 'MALE' JEFFERSON M MALE
ELSE NULL JOHNSON F FEMALE
END AS SEXX JONES M MALE
FROM EMPLOYEE
WHERE LASTNAME LIKE 'J%'
ORDER BY 1;
Figure 87, Use CASE (type 2) 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 88, Use CASE to display the higher of two values
SELECT COUNT(*) AS TOT ANSWER
,SUM(CASE SEX WHEN 'F' THEN 1 ELSE 0 END) AS #F =========
,SUM(CASE SEX WHEN 'M' THEN 1 ELSE 0 END) AS #M TOT #F #M
FROM EMPLOYEE --- -- --
WHERE LASTNAME LIKE 'J%'; 3 1 2
Figure 89, Use CASE to get multiple counts in one pass
SELECT LASTNAME ANSWER
,SEX ==============
FROM EMPLOYEE LASTNAME SEX
WHERE LASTNAME LIKE 'J%' ---------- ---
AND CASE SEX JEFFERSON M
WHEN 'F' THEN '' JOHNSON F
WHEN 'M' THEN '' JONES M
ELSE NULL
END IS NOT NULL
ORDER BY 1;
Figure 90, Use CASE in a predicate
SELECT LASTNAME ANSWER
,LENGTH(RTRIM(LASTNAME)) AS LEN =====================
,SUBSTR(LASTNAME,1, LASTNAME LEN LASTNM
CASE ---------- --- ------
WHEN LENGTH(RTRIM(LASTNAME)) JEFFERSON 9 JEFFER
> 6 THEN 6 JOHNSON 7 JOHNSO
ELSE LENGTH(RTRIM(LASTNAME)) JONES 5 JONES
END ) AS LASTNM
FROM EMPLOYEE
WHERE LASTNAME LIKE 'J%'
ORDER BY 1;
Figure 91, Use CASE inside a function
UPDATE STAFF
SET COMM = CASE DEPT
WHEN 15 THEN COMM * 1.1
WHEN 20 THEN COMM * 1.2
WHEN 38 THEN
CASE
WHEN YEARS < 5 THEN COMM * 1.3
WHEN YEARS >= 5 THEN COMM * 1.4
ELSE NULL
END
ELSE COMM
END
WHERE COMM IS NOT NULL
AND DEPT < 50;
Figure 92, UPDATE statement with nested CASE expressions
WITH TEMP1 (C1,C2) AS ANSWER
(VALUES (88,9),(44,3),(22,0),(0,1)) ========
SELECT C1 C1 C2 C3
,C2 -- -- --
,CASE C2 88 9 9
WHEN 0 THEN NULL 44 3 14
ELSE C1/C2 22 0 -
END AS C3 0 1 0
FROM TEMP1;
Figure 93, Use CASE to avoid divide by zero
SELECT NAME ANSWER
,CASE ============
WHEN NAME = LCASE(NAME) THEN NULL NAME DUMB
ELSE CAST(NULL AS CHAR(1)) ------- ----
END AS DUMB Sanders -
FROM STAFF Pernal -
WHERE ID < 30;
Figure 94, Silly CASE expression that always returns NULL
SELECT LASTNAME ANSWER
,SEX =================
,CASE LASTNAME SX SXX
WHEN SEX >= 'M' THEN 'MAL' ---------- -- ---
WHEN SEX >= 'F' THEN 'FEM' JEFFERSON M MAL
END AS SXX JOHNSON F FEM
FROM EMPLOYEE JONES M MAL
WHERE LASTNAME LIKE 'J%'
ORDER BY 1;
Figure 95, Use CASE to derive a value (correct)
SELECT LASTNAME ANSWER
,SEX =================
,CASE LASTNAME SX SXX
WHEN SEX >= 'F' THEN 'FEM' ---------- -- ---
WHEN SEX >= 'M' THEN 'MAL' JEFFERSON M FEM
END AS SXX JOHNSON F FEM
FROM EMPLOYEE JONES M FEM
WHERE LASTNAME LIKE 'J%'
ORDER BY 1;
Figure 96, Use CASE to derive a value (incorrect)
Figure 97, AVG function syntax
SELECT AVG(DEPT) AS A1 ANSWER
,AVG(ALL DEPT) AS A2 ==============
,AVG(DISTINCT DEPT) AS A3 A1 A2 A3 A4 A5
,AVG(DEPT/10) AS A4 -- -- -- -- --
,AVG(DEPT)/10 AS A5 41 41 40 3 4
FROM STAFF
HAVING AVG(DEPT) > 40;
Figure 98, AVG function examples
SELECT AVG(SALARY) AS SALARY ANSWER
,AVG(COMM) AS COMM1 ===================
,AVG(CASE COMM SALARY COMM1 COMM2
WHEN 0 THEN NULL ------- ----- -----
ELSE COMM 16675.6 351.9 513.3
END) AS COMM2
FROM STAFF;
Figure 99, Convert zero to null before doing AVG
SELECT COUNT(*) AS C1 ANSWER
,AVG(SALARY) AS A1 ===========
,COALESCE(AVG(SALARY),0) AS A2 C1 A1 A2 A3
,CASE -- -- -- --
WHEN AVG(SALARY) IS NULL THEN 0 0 - 0 0
ELSE AVG(SALARY)
END AS A3
FROM STAFF
WHERE ID < 10;
Figure 100, Convert null output (from AVG) to zero
SELECT AVG(DAYS(BIRTHDATE)) ANSWER
,DATE(AVG(DAYS(BIRTHDATE))) =================
FROM EMPLOYEE; 1 2
------ ----------
709113 06/27/1942
Figure 101, AVG of date column
SELECT AVG(AVG_SAL) AS AVG_AVG ANSWER
FROM (SELECT DEPT ================
,AVG(SALARY) AS AVG_SAL
FROM STAFF
GROUP BY DEPT
)AS XXX;
Figure 102, Select average of average
Figure 103, CORRELATION function syntax
WITH TEMP1(COL1, COL2, COL3, COL4) AS ANSWER
(VALUES (0 ===========================
,0 COR11 COR12 COR23 COR34
,0 ------ ------ ------ ------
,RAND(1)) 1.000 -1.000 -0.017 -0.005
UNION ALL
SELECT COL1 + 1
,COL2 - 1
,RAND()
,RAND()
FROM TEMP1
WHERE COL1 <= 1000
)
SELECT DEC(CORRELATION(COL1,COL1),5,3) AS COR11
,DEC(CORRELATION(COL1,COL2),5,3) AS COR12
,DEC(CORRELATION(COL2,COL3),5,3) AS COR23
,DEC(CORRELATION(COL3,COL4),5,3) AS COR34
FROM TEMP1;
Figure 104, CORRELATION function examples
Figure 105, COUNT function syntax
SELECT COUNT(*) AS C1 ANSWER
,COUNT(INT(COMM/10)) AS C2 =================
,COUNT(ALL INT(COMM/10)) AS C3 C1 C2 C3 C4 C5 C6
,COUNT(DISTINCT INT(COMM/10)) AS C4 -- -- -- -- -- --
,COUNT(DISTINCT INT(COMM)) AS C5 35 24 24 19 24 2
,COUNT(DISTINCT INT(COMM))/10 AS C6
FROM STAFF;
Figure 106, COUNT function examples
SELECT 'NO GP-BY' AS C1 ANSWER
,COUNT(*) AS C2 ============
FROM STAFF C1 C2
WHERE ID = -1 -------- --
UNION NO GP-BY 0
SELECT 'GROUP-BY' AS C1
,COUNT(*) AS C2
FROM STAFF
WHERE ID = -1
GROUP BY DEPT;
Figure 107, COUNT function with and without GROUP BY
Figure 108, COUNT_BIG function syntax
SELECT COUNT_BIG(*) AS C1 ANSWER
,COUNT_BIG(DEPT) AS C2 ===================
,COUNT_BIG(DISTINCT DEPT) AS C3 C1 C2 C3 C4 C5
,COUNT_BIG(DISTINCT DEPT/10) AS C4 --- --- --- --- ---
,COUNT_BIG(DISTINCT DEPT)/10 AS C5 35. 35. 8. 7. 0.
FROM STAFF;
Figure 109, COUNT_BIG function examples
Figure 110, COVARIANCE function syntax
WITH TEMP1(C1, C2, C3, C4) AS ANSWER
(VALUES (0 ===============================
,0 COV11 COV12 COV23 COV34
,0 ------- ------- ------- -------
,RAND(1)) 83666. -83666. -1.4689 -0.0004
UNION ALL
SELECT C1 + 1
,C2 - 1
,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 111, COVARIANCE function examples
Figure 112, GROUPING function syntax
SELECT DEPT ANSWER
,AVG(SALARY) AS SALARY ================
,GROUPING(DEPT) AS DF DEPT SALARY DF
FROM STAFF ---- -------- --
GROUP BY ROLLUP(DEPT) 10 20865.86 0
ORDER BY DEPT; 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
Figure 113, GROUPING function example
Figure 114, MAX function syntax
SELECT MAX(DEPT) ANSWER
,MAX(ALL DEPT) ===============
,MAX(DISTINCT DEPT) 1 2 3 4
,MAX(DISTINCT DEPT/10) --- --- --- ---
FROM STAFF; 84 84 84 8
Figure 115, MAX function examples
SELECT MAX(HIREDATE) ANSWER
,CHAR(MAX(HIREDATE),USA) ================================
,MAX(CHAR(HIREDATE,USA)) 1 2 3
FROM EMPLOYEE; ---------- ---------- ----------
09/30/1980 09/30/1980 12/15/1976
Figure 116, MAX function with dates
SELECT MAX(ID) AS ID ANSWER
,MAX(CHAR(ID)) AS CHR ===================
,MAX(DIGITS(ID)) AS DIG ID CHR DIG
FROM STAFF; ------ ------ -----
350 90 00350
Figure 117, MAX function with numbers, 1 of 2
SELECT MAX(ID - 250) AS ID ANSWER
,MAX(CHAR(ID - 250)) AS CHR =====================
,MAX(DIGITS(ID - 250)) AS DIG ID CHR DIG
FROM STAFF; ----- ---- ----------
100 90 0000000240
Figure 118, MAX function with numbers, 2 of 2
Figure 119, MIN function syntax
SELECT MIN(DEPT) ANSWER
,MIN(ALL DEPT) ===============
,MIN(DISTINCT DEPT) 1 2 3 4
,MIN(DISTINCT DEPT/10) --- --- --- ---
FROM STAFF; 10 10 10 1
Figure 120, MIN function examples
Figure 121, REGRESSION functions syntax
ANSWERS
==========
SELECT DEC(REGR_SLOPE(BONUS,SALARY) ,7,5) AS R_SLOPE 0.01710
,DEC(REGR_INTERCEPT(BONUS,SALARY),7,3) AS R_ICPT 100.871
,INT(REGR_COUNT(BONUS,SALARY) ) AS R_COUNT 3
,INT(REGR_AVGX(BONUS,SALARY) ) AS R_AVGX 42833
,INT(REGR_AVGY(BONUS,SALARY) ) AS R_AVGY 833
,INT(REGR_SXX(BONUS,SALARY) ) AS R_SXX 296291666
,INT(REGR_SXY(BONUS,SALARY) ) AS R_SXY 5066666
,INT(REGR_SYY(BONUS,SALARY) ) AS R_SYY 86666
FROM EMPLOYEE
WHERE WORKDEPT = 'A00';
Figure 122, REGRESSION functions examples
Figure 123, STDDEV function syntax
ANSWER
===============================
A1 S1 S2 S3 S4
-- ------------- ---- ---- ----
SELECT AVG(DEPT) AS A1 41 +2.3522355E+1 23.5 23.5 24.1
,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 124, STDDEV function examples
Figure 125, SUM function syntax
SELECT SUM(DEPT) AS S1 ANSWER
,SUM(ALL DEPT) AS S2 ========================
,SUM(DISTINCT DEPT) AS S3 S1 S2 S3 S4 S5
,SUM(DEPT/10) AS S4 ---- ---- ---- ---- ----
,SUM(DEPT)/10 AS S5 1459 1459 326 134 145
FROM STAFF;
Figure 126, SUM function examples
Figure 127, VARIANCE function syntax
ANSWER
==============================
A1 V1 V2 V3 V4
-- --------------- --- --- ---
SELECT AVG(DEPT) AS A1 41 +5.533012244E+2 553 553 582
,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 128, VARIANCE function examples
SELECT S1.JOB, S1.ID, S1.SALARY ANSWER
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 129, Select rows from STAFF table
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 ANSWER
WHERE S1.NAME LIKE '%s%' ============================
AND S1.ID < 90 JOB ID SALARY SUMSAL R
ORDER BY S1.JOB ----- -- -------- -------- -
,S1.ID; Clerk 80 13504.60 13504.60 1
Mgr 10 18357.50 31862.10 2
Mgr 50 20659.80 52521.90 3
Figure 130, Using OLAP functions to get additional fields
SELECT S1.JOB, S1.ID, S1.SALARY
,XX.SUMSAL, XX.#ROWS
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 ANSWER
AND S2.ID <= S1.ID)) ============================
)AS XX JOB ID SALARY SUMSAL R
WHERE S1.NAME LIKE '%s%' ----- -- -------- -------- -
AND S1.ID < 90 Clerk 80 13504.60 13504.60 1
ORDER BY S1.JOB Mgr 10 18357.50 31862.10 2
,S1.ID; Mgr 50 20659.80 52521.90 3
Figure 131, Using Nested Table Expression 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 132, 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 133, 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) AS SUMSAL
,ROW_NUMBER() OVER(ORDER BY DPT.DEPTNAME ASC
,EMP.SALARY DESC
,EMP.EMPNO ASC) AS ROW#
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 134, Complicated query using OLAP functions
Figure 135, 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#
FROM STAFF
WHERE ID < 100
AND YEARS IS NOT NULL ANSWER
ORDER BY YEARS; ===================================
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 136, 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 137, ORDER BY usage
SELECT ID
,YEARS AS YR
,SALARY
,DENSE_RANK() OVER(ORDER BY YEARS ASC) AS A
,DENSE_RANK() OVER(ORDER BY YEARS ASC NULLS FIRST) AS AF
,DENSE_RANK() OVER(ORDER BY YEARS ASC NULLS LAST ) AS AL
,DENSE_RANK() OVER(ORDER BY YEARS DESC) AS D
,DENSE_RANK() OVER(ORDER BY YEARS DESC NULLS FIRST) AS DF
,DENSE_RANK() OVER(ORDER BY YEARS DESC NULLS LAST ) AS DL
FROM STAFF
WHERE ID < 100
ORDER BY YEARS ANSWER
,SALARY; ==================================
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 138, 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 ANSWER
ORDER BY 1; =======
Y#1 Y#2
--- ---
5 6
Figure 139, Counting distinct values - comparison
SELECT ID ANSWER
,YEARS AS YR =================
,SALARY ID YR SALARY R1
,RANK() OVER(PARTITION BY YEARS -- -- -------- --
ORDER BY SALARY) AS R1 30 5 17506.75 1
FROM STAFF 40 6 18006.00 1
WHERE ID < 80 70 7 16502.83 1
AND YEARS IS NOT NULL 10 7 18357.50 2
ORDER BY YEARS 20 8 18171.25 1
,SALARY; 50 0 20659.80 1
Figure 140, Values ranked by subset of rows
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 141, Multiple rankings in same query
SELECT ID
,YEARS
,NAME
,SALARY
,SMALLINT(RANK() OVER(ORDER BY SUBSTR(NAME,3,2))) AS DUMB1
,SMALLINT(RANK() OVER(ORDER BY SALARY / 1000)) AS DUMB2
,SMALLINT(RANK() OVER(ORDER BY YEARS * ID)) AS DUMB3
,SMALLINT(RANK() OVER(ORDER BY RAND())) AS DUMB4
,SMALLINT(RANK() OVER(ORDER BY 1)) AS DUMB5
FROM STAFF
WHERE ID < 40
AND YEARS IS NOT NULL
ORDER BY 1;
Figure 142, Dumb rankings, SQL
ID YEARS NAME SALARY DUMB1 DUMB2 DUMB3 DUMB4 DUMB5
-- ----- -------- -------- ----- ----- ----- ----- -----
10 7 Sanders 18357.50 1 3 1 1 1
20 8 Pernal 18171.25 3 2 3 3 1
30 5 Marenghi 17506.75 2 1 2 2 1
Figure 143, Dumb ranking, Answer
SELECT XXX.* ANSWER
,RANK()OVER(ORDER BY ID) AS R2 ================
FROM (SELECT ID ID NAME R1 R2
,NAME -- ------- -- --
,RANK() OVER(ORDER BY ID) AS R1 40 O'Brien 4 1
FROM STAFF 50 Hanes 5 2
WHERE ID < 100 70 Rothman 6 3
AND YEARS IS NOT NULL 90 Koonitz 7 4
)AS XXX
WHERE ID > 30
ORDER BY ID;
Figure 144, 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 145, Ordering rows by rank, using RANK function
SELECT ID ANSWER
,(SELECT COUNT(*) =================
FROM STAFF S2 ID R1 SALARY DP
WHERE S2.ID < 80 -- -- -------- --
AND S2.YEARS IS NOT NULL 50 1 20659.80 15
AND S2.DEPT = S1.DEPT 10 1 18357.50 20
AND S2.SALARY >= S1.SALARY) AS R1 40 1 18006.00 38
,SALARY 20 2 18171.25 20
,DEPT AS DP 30 2 17506.75 38
FROM STAFF S1 70 2 16502.83 15
WHERE ID < 80
AND YEARS IS NOT NULL
ORDER BY R1 ASC
,SALARY DESC;
Figure 146, Ordering rows by rank, using sub-query
SELECT 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 147, 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 148, 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 149, Get highest salary in each department, use uncorrelated sub-query
Figure 150, Numbering Function syntax
SELECT ID ANSWER
,NAME =================
,ROW_NUMBER() OVER() AS R1 ID NAME R1 R2
,ROW_NUMBER() OVER(ORDER BY ID) AS R2 -- -------- -- --
FROM STAFF 10 Sanders 1 1
WHERE ID < 50 20 Pernal 2 2
AND YEARS IS NOT NULL 30 Marenghi 3 3
ORDER BY ID; 40 O'Brien 4 4
Figure 151, ORDER BY example, 1 of 3
SELECT ID ANSWER
,NAME =================
,ROW_NUMBER() OVER() AS R1 ID NAME R1 R2
,ROW_NUMBER() OVER(ORDER BY NAME) AS R2 -- -------- -- --
FROM STAFF 10 Sanders 4 4
WHERE ID < 50 20 Pernal 3 3
AND YEARS IS NOT NULL 30 Marenghi 2 2
ORDER BY ID; 40 O'Brien 1 1
Figure 152, ORDER BY example, 2 of 3
SELECT ID ANSWER
,NAME ====================
,ROW_NUMBER() OVER() AS R1 ID NAME R1 R2 R3
,ROW_NUMBER() OVER(ORDER BY ID) AS R2 -- -------- -- -- --
,ROW_NUMBER() OVER(ORDER BY NAME) AS R3 10 Sanders 1 1 4
FROM STAFF 20 Pernal 2 2 3
WHERE ID < 50 30 Marenghi 3 3 1
AND YEARS IS NOT NULL 40 O'Brien 4 4 2
ORDER BY ID;
Figure 153, 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 154, Use of PARTITION phrase
SELECT * ANSWER
FROM (SELECT ID =============
,NAME ID NAME R
,ROW_NUMBER() OVER(ORDER BY ID) AS R -- -------- -
FROM STAFF 10 Sanders 1
WHERE ID < 100 20 Pernal 2
AND YEARS IS NOT NULL 30 Marenghi 3
)AS XXX
WHERE R <= 3
ORDER BY ID;
Figure 155, 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 156, Select first 3 rows, using FETCH FIRST notation
SELECT * ANSWER
FROM (SELECT ID =============
,NAME ID NAME R
,ROW_NUMBER() OVER(ORDER BY ID) AS R -- -------- -
FROM STAFF 30 Marenghi 3
WHERE ID < 200 40 O'Brien 4
AND YEARS IS NOT NULL 50 Hanes 5
)AS XXX 70 Rothman 6
WHERE R BETWEEN 3 AND 6
ORDER BY ID;
Figure 157, Select 3rd through 6th rows
SELECT * ANSWER
FROM (SELECT ID ==============
,NAME ID NAME R
,ROW_NUMBER() OVER(ORDER BY ID) AS R --- ------- --
FROM STAFF 10 Sanders 1
WHERE ID < 200 70 Rothman 6
AND YEARS IS NOT NULL 140 Fraye 11
)AS XXX 190 Sneider 16
WHERE (R - 1) = ((R - 1) / 5) * 5
ORDER BY ID;
Figure 158, 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 159, 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 160, 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 161, 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 < 100000
)
SELECT N AS INV#
,INT(M * 1000) AS CUSTOMER#
,DATE('2000-11-01') + (M*40) DAYS AS SALE_DATE
,DECIMAL((M * M * 100),8,2) AS SALE_VALUE
FROM TEMP;
Figure 162, Performance test table - insert 100,000 rows
SELECT S.*
,ROW_NUMBER() OVER() AS ROW#
FROM INVOICE S
ORDER BY INV#
FETCH FIRST 5 ROWS ONLY;
Figure 163, Fetch first 5 rows - 2.837 elapsed seconds
SELECT S.*
,ROW_NUMBER() OVER() AS ROW#
FROM INVOICE S
ORDER BY INV#
FETCH FIRST 5 ROWS ONLY
OPTIMIZE FOR 5 ROWS;
Figure 164, Fetch first 5 rows - 0.003 elapsed seconds
SELECT *
FROM (SELECT S.*
,ROW_NUMBER() OVER() AS ROW#
FROM INVOICE S
)XXX
WHERE ROW# <= 5
ORDER BY INV#;
Figure 165, Fetch first 5 rows - 0.691 elapsed seconds
SELECT *
FROM (SELECT S.*
,ROW_NUMBER() OVER() AS ROW#
FROM INVOICE S
)XXX
WHERE ROW# <= 5
ORDER BY INV#
OPTIMIZE FOR 5 ROWS;
Figure 166, Fetch first 5 rows - 2.363 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 167, Fetch first 5 rows - 0.005 elapsed seconds
Figure 168, 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 169, Aggregation function, basic usage, SQL
ID NAME SALARY SUM_SAL AVG_SAL MIN_SAL MAX_SAL #ROWS
-- -------- -------- -------- -------- -------- -------- -----
10 Sanders 18357.50 92701.30 18540.26 17506.75 20659.80 5
20 Pernal 18171.25 92701.30 18540.26 17506.75 20659.80 5
30 Marenghi 17506.75 92701.30 18540.26 17506.75 20659.80 5
40 O'Brien 18006.00 92701.30 18540.26 17506.75 20659.80 5
50 Hanes 20659.80 92701.30 18540.26 17506.75 20659.80 5
Figure 170, Aggregation function, basic usage, Answer
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 171, Select detailed data, plus summary data
SELECT ID
,NAME
,SALARY
,SUM(SALARY) OVER() AS SUM1
,SUM(SALARY) OVER(ORDER BY ID * 0) AS SUM2
,SUM(SALARY) OVER(ORDER BY 'ABC') AS SUM3
,SUM(SALARY) OVER(ORDER BY 'ABC'
RANGE BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING) AS SUM4
FROM STAFF
WHERE ID < 60
ORDER BY ID;
Figure 172, 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 173, Logically equivalent aggregation functions, Answer
SELECT DEPT
,NAME
,SALARY
,SUM(SALARY) OVER(ORDER BY DEPT) AS SUM1
,SUM(SALARY) OVER(ORDER BY DEPT DESC) AS SUM2
,SUM(SALARY) OVER(ORDER BY DEPT, NAME) AS SUM3
,SUM(SALARY) OVER(ORDER BY DEPT DESC, NAME DESC) AS SUM4
,COUNT(*) OVER(ORDER BY DEPT) AS ROW1
,COUNT(*) OVER(ORDER BY DEPT, NAME) AS ROW2
FROM STAFF
WHERE ID < 60
ORDER BY DEPT
,NAME;
Figure 174, Aggregation function, order by usage, SQL
DEPT NAME SALARY SUM1 SUM2 SUM3 SUM4 ROW1 ROW2
---- -------- -------- -------- -------- -------- -------- ---- ----
15 Hanes 20659.80 20659.80 92701.30 20659.80 92701.30 1 1
20 Pernal 18171.25 57188.55 72041.50 38831.05 72041.50 3 2
20 Sanders 18357.50 57188.55 72041.50 57188.55 53870.25 3 3
38 Marenghi 17506.75 92701.30 35512.75 74695.30 35512.75 5 4
38 O'Brien 18006.00 92701.30 35512.75 92701.30 18006.00 5 5
Figure 175, Aggregation function, order by usage, Answer
SELECT 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 DN3
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS 1 PRECEDING)) AS DN1
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS 0 PRECEDING)) AS DN0
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS CURRENT ROW)) AS DNC
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT DESC, NAME DESC
ROWS 1 PRECEDING)) AS DNX
FROM STAFF
WHERE ID < 100
AND YEARS IS NOT NULL
ORDER BY DEPT
,NAME;
Figure 176, Starting ROWS usage. Implied end is current row, SQL
DEPT NAME YEARS D DN DNU DN3 DN1 DN0 DNC DNX
---- -------- ----- -- -- --- --- --- --- --- ---
15 Hanes 10 17 10 10 10 10 10 10 17
15 Rothman 7 17 17 17 17 17 7 7 15
20 Pernal 8 32 25 25 25 15 8 8 15
20 Sanders 7 32 32 32 32 15 7 7 12
38 Marenghi 5 43 37 37 27 12 5 5 11
38 O'Brien 6 43 43 43 26 11 6 6 12
42 Koonitz 6 49 49 49 24 12 6 6 6
Figure 177, Starting ROWS usage. Implied end is current row, Answer
SELECT DEPT
,NAME
,YEARS
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME)) AS UC1
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS UNBOUNDED PRECEDING)) AS UC2
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)) AS UC3
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS BETWEEN CURRENT ROW
AND CURRENT ROW)) AS CU1
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS BETWEEN 1 PRECEDING
AND 1 FOLLOWING)) AS PF1
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS BETWEEN 2 PRECEDING
AND 2 FOLLOWING)) AS PF2
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS BETWEEN 3 PRECEDING
AND 3 FOLLOWING)) AS PF3
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS BETWEEN CURRENT ROW
AND UNBOUNDED FOLLOWING)) AS CU1
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT, NAME
ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING)) AS UU1
FROM STAFF
WHERE ID < 100
AND YEARS IS NOT NULL
ORDER BY DEPT
,NAME;
Figure 178, ROWS usage, with BETWEEN phrase, SQL
DEPT NAME YEARS UC1 UC2 UC3 CU1 PF1 PF2 PF3 CU1 UU1
---- -------- ----- --- --- --- --- --- --- --- --- ---
15 Hanes 10 10 10 10 10 17 25 32 49 49
15 Rothman 7 17 17 17 7 25 32 37 39 49
20 Pernal 8 25 25 25 8 22 37 43 32 49
20 Sanders 7 32 32 32 7 20 33 49 24 49
38 Marenghi 5 37 37 37 5 18 32 39 17 49
38 O'Brien 6 43 43 43 6 17 24 32 12 49
42 Koonitz 6 49 49 49 6 12 17 24 6 49
Figure 179, ROWS usage, with BETWEEN phrase, Answer
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 180,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 10=10 10+20=30 20+30=40 30+40=70
CURRENT ROW to 1 FOLLOWING 10+20=30 20+30=50 30+40=70 40 =40
DESC ID (40,30,20,10)
READ ROWS, RIGHT to LEFT 1ST-ROW 2ND-ROW 3RD-ROW 4TH-ROW
========================== ======== ======== ======== ========
1 PRECEDING to CURRENT ROW 20+10=30 30+20=50 40+30=70 40 =40
CURRENT ROW to 1 FOLLOWING 10 =10 20+10=30 30+20=50 40+30=70
NOTE: Preceding row is always on LEFT of current row.
Following row is always on RIGHT of current row.
Figure 181, Explanation of query
SELECT DEPT
,NAME
,YEARS
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT
ROWS BETWEEN 1 PRECEDING
AND CURRENT ROW)) AS ROW1
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT
ROWS BETWEEN 2 PRECEDING
AND CURRENT ROW)) AS ROW2
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT
RANGE BETWEEN 1 PRECEDING
AND CURRENT ROW)) AS RG01
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT
RANGE BETWEEN 10 PRECEDING
AND CURRENT ROW)) AS RG10
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT
RANGE BETWEEN 20 PRECEDING
AND CURRENT ROW)) AS RG20
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT
RANGE BETWEEN 10 PRECEDING
AND 20 FOLLOWING)) AS RG11
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT
RANGE BETWEEN CURRENT ROW
AND 20 FOLLOWING)) AS RG99
FROM STAFF
WHERE ID < 100
AND YEARS IS NOT NULL
ORDER BY DEPT
,NAME;
Figure 182, RANGE usage, SQL
DEPT NAME YEARS ROW1 ROW2 RG01 RG10 RG20 RG11 RG99
------ ------- ----- ---- ---- ---- ---- ---- ---- ----
15 Hanes 10 10 10 17 17 17 32 32
15 Rothman 7 17 17 17 17 17 32 32
20 Pernal 8 15 25 15 32 32 43 26
20 Sanders 7 15 22 15 32 32 43 26
38 Marengh 5 12 20 11 11 26 17 17
38 O'Brien 6 11 18 11 11 26 17 17
42 Koonitz 6 12 17 6 17 17 17 6
Figure 183, RANGE usage, Answer
SELECT DEPT
,NAME
,YEARS
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT)) AS X
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT
ROWS 3 PRECEDING)) AS XO3
,SMALLINT(SUM(YEARS) OVER(ORDER BY DEPT
ROWS BETWEEN 1 PRECEDING
AND 1 FOLLOWING)) AS XO11
,SMALLINT(SUM(YEARS) OVER(PARTITION BY DEPT)) AS P
,SMALLINT(SUM(YEARS) OVER(PARTITION BY DEPT
ORDER BY DEPT)) AS PO
,SMALLINT(SUM(YEARS) OVER(PARTITION BY DEPT
ORDER BY DEPT
ROWS 1 PRECEDING)) AS PO1
,SMALLINT(SUM(YEARS) OVER(PARTITION BY DEPT
ORDER BY DEPT
ROWS 3 PRECEDING)) AS PO3
,SMALLINT(SUM(YEARS) OVER(PARTITION BY DEPT
ORDER BY DEPT
ROWS BETWEEN 1 PRECEDING
AND 1 FOLLOWING)) AS PO11
FROM STAFF
WHERE ID BETWEEN 40 AND 120
AND YEARS IS NOT NULL
ORDER BY DEPT
,NAME;
Figure 184, PARTITION usage, SQL
DEPT NAME YEARS X XO3 XO11 P PO PO1 PO3 PO11
----- ------- ----- ---- ---- ---- ---- ---- ---- ---- ----
15 Hanes 10 22 10 15 22 22 10 10 15
15 Ngan 5 22 15 22 22 22 15 15 22
15 Rothman 7 22 22 18 22 22 12 22 12
38 O'Brien 6 28 28 19 6 6 6 6 6
42 Koonitz 6 41 24 19 13 13 6 6 13
42 Plotz 7 41 26 13 13 13 13 13 13
Figure 185, PARTITION usage, Answer
SELECT DEPT ANSWER
,SUM(YEARS) AS SUM ================
,AVG(YEARS) AS AVG DEPT SUM AVG ROW
,COUNT(*) 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
GROUP BY DEPT;
Figure 186, Sample query using GROUP BY
SELECT 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 15 22 7 3
AND YEARS IS NOT NULL 15 22 7 3
ORDER BY DEPT; 38 6 6 1
42 13 6 2
42 13 6 2
Figure 187, 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 188, 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 189, Sample View DDL - Scalar functions
D1 F1 S1 C1 V1 TS1
------ --------- -- ------ ------ --------------------------
-2.4 -2.4e+000 -2 ABCDEF ABCDEF 1996-04-22-23.58.58.123456
0.0 0.0e+000 0 ABCD ABCD 1996-08-15-15.15.15.151515
1.8 1.8e+000 1 AB AB 0001-01-01-00.00.00.000000
DT1 TM1 TC1
---------- -------- --------------------------
04/22/1996 23:58:58 1996-04-22-23.58.58.123456
08/15/1996 15:15:15 1996-08-15-15.15.15.151515
01/01/0001 00:00:00 0001-01-01-00.00.00.000000
Figure 190, SCALAR view, contents (3 rows)
SELECT D1 AS D1 ANSWER (float output shortened)
,ABS(D1) AS D2 ================================
,F1 AS F1 D1 D2 F1 F2
,ABS(F1) AS F2 ---- --- ---------- ---------
FROM SCALAR; -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
Figure 191, ABS function examples
SELECT C1 ANSWER
,ASCII(C1) AS AC1 ================
,ASCII(SUBSTR(C1,2)) AS AC2 C1 AC1 AC2
FROM SCALAR ------ --- ---
WHERE C1 = 'ABCDEF'; ABCDEF 65 66
Figure 192, ASCII function examples
WITH TEMP (BIG) AS ANSWER
(VALUES BIGINT(1) ====================
UNION ALL BIG
SELECT BIG * 256 --------------------
FROM TEMP 1
WHERE BIG < 1E16 256
) 65536
SELECT BIG 16777216
FROM TEMP; 4294967296
1099511627776
281474976710656
72057594037927936
Figure 193, BIGINT function example
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 194, 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 195, Convert FLOAT to DECIMAL and BIGINT, answer
Figure 196, BLOB function syntax
Figure 197, CEILING function syntax
SELECT D1 ANSWER (float output shortened)
,CEIL(D1) =========================================
,F1 D1 2 F1 4
,CEIL(F1) ----- ---------- ---------- ----------
FROM SCALAR; -2.4 -2.000E+0 -2.400E+0 -2.000E+0
0.0 +0.000E+0 +0.000E+0 +0.000E+0
1.8 +2.000E+0 +1.800E+0 +2.000E+0
Figure 198, CEIL function examples
WITH TEMP1(N1) AS
(VALUES (CAST(12345678901234567890.1 AS DECIMAL(20))))
SELECT N1
,DECIMAL(CEIL(N1),20) AS N2
FROM TEMP1;
ANSWER
===========================================
N1 N2
--------------------- ---------------------
12345678901234567890. 12345678901234570000.
Figure 199, CEIL function, example of incorrect result
Figure 200, CHAR function syntax
SELECT C1 ANSWER
,CHAR(C1,3) ==========================================
,S1 C1 2 S1 4 D1 6 7
,CHAR(S1) ------ --- ------ ------ ----- ----- -----
,D1 ABCDEF ABC -2 -2 -2.4 -02.4 -02$4
,CHAR(D1) ABCD ABC 0 0 0.0 00.0 00$0
,CHAR(D1,'$') AB AB 1 1 1.8 01.8 01$8
FROM SCALAR;
Figure 201, CHAR function examples - characters and numbers
SELECT D1 ANSWER
,CHAR(D1) AS D2 ==================
,CASE D1 D2 D3
WHEN D1 < 0 THEN CHAR(D1) ----- ----- ------
ELSE '+' || CHAR(D1) -2.4 -02.4 -02.4
END AS D3 0.0 00.0 +00.0
FROM SCALAR; 1.8 01.8 +01.8
Figure 202, Align CHAR function output
ANSWER (float output shortened)
WITH TEMP1(C1) AS ================================
(VALUES ('12345') C1 C>D C>D>C
,('-23.5') ----- --------------- --------
,('1E+45') 12345 +1.2345000E+004 1.2345E4
,('-2e05')) -23.5 -2.3500000E+001 -2.35E1
SELECT C1 1E+45 +1.0000000E+045 1.0E45
,DOUBLE(C1) AS "C>D" -2e05 -2.0000000E+005 -2.0E5
,CHAR(DOUBLE(C1)) AS "C>D>C"
FROM TEMP1;
Figure 203, CHAR function example - double
SELECT CHAR(HIREDATE,ISO) ANSWER
,CHAR(HIREDATE,USA) ================================
,CHAR(HIREDATE,EUR) 1 2 3
FROM EMPLOYEE ---------- ---------- ----------
WHERE LASTNAME < 'C' 1972-02-12 02/12/1972 12.02.1972
ORDER BY 2; 1966-03-03 03/03/1966 03.03.1966
Figure 204, CHAR function examples - dates
SELECT D1 ANSWER
,CHAR(D1) AS CD1 =================
,DIGITS(D1) AS DD1 D1 CD1 DD1
FROM SCALAR; ----- ----- ---
-2.4 -02.4 024
0.0 00.0 000
1.8 01.8 018
Figure 205, DIGITS vs. CHAR
SELECT 'A' AS "C" ANSWER
,ASCII('A') AS "C>N" =================
,CHR(ASCII('A')) AS "C>N>C" C C>N C>N>C NL
,CHR(333) AS "NL" - --- ----- --
FROM STAFF A 65 A
WHERE ID = 10;
Figure 206, CHR function examples
SELECT C1 ANSWER
,CLOB(C1) AS CC1 ===================
,CLOB(C1,3) AS CC2 C1 CC1 CC2
FROM SCALAR; ------ ------ ---
ABCDEF ABCDEF ABC
ABCD ABCD ABC
AB AB AB
Figure 207, CLOB function examples
SELECT ID ANSWER
,COMM ==================
,COALESCE(COMM,0) ID COMM 3
FROM STAFF -- ------ ------
WHERE ID < 30 10 - 0.00
ORDER BY ID; 20 612.45 612.45
Figure 208, COALESCE function example
WITH TEMP1(C1,C2,C3) AS ANSWER
(VALUES (CAST(NULL AS SMALLINT) ========
,CAST(NULL AS SMALLINT) CC1 CC2
,CAST(10 AS SMALLINT))) --- ---
SELECT COALESCE(C1,C2,C3) AS CC1 10 10
,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 209, COALESCE and equivalent CASE expression
SELECT COUNT(*) AS #ROWS ANSWER
,MIN(ID) AS MIN_ID ===================
,COALESCE(MIN(ID),-1) AS CCC_ID #ROWS MIN_ID CCC_ID
FROM STAFF ----- ------ ------
WHERE ID < 5; 0 - -1
Figure 210, NOT NULL field returning null value
SELECT 'A' || 'B' ANSWER
,'A' CONCAT 'B' ===================
,CONCAT('A','B') 1 2 3 4 5
,'A' || 'B' || 'C' --- --- --- --- ---
,CONCAT(CONCAT('A','B'),'C') AB AB AB ABC ABC
FROM STAFF
WHERE ID = 10;
Figure 211, 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 212, CONCAT used with ORDER BY - wrong output sequence
WITH TEMP1 (COL1, COL2) AS ANSWER
(VALUES ('A' , 'YYY') ===============
,('AE', 'OOO') COL1 COL2 COL3
,('AE', 'YYY') ---- ---- -----
) A YYY A YYY
SELECT COL1 AE OOO AEOOO
,COL2 AE YYY AEYYY
,CHAR(COL1,2) CONCAT
CHAR(COL2,3) AS COL3
FROM TEMP1
ORDER BY COL3;
Figure 213, CONCAT used with ORDER BY - correct output sequence
WITH TEMP1(N1) AS ANSWER
(VALUES (0) =======================
UNION ALL N1 RAN COS SIN
SELECT N1 + 10 -- ----- ----- -----
FROM TEMP1 0 0.000 1.000 0.000
WHERE N1 < 90) 10 0.174 0.984 0.173
SELECT N1 20 0.349 0.939 0.342
,DEC(RADIANS(N1),4,3) AS RAN 30 0.523 0.866 0.500
,DEC(COS(RADIANS(N1)),4,3) AS COS 40 0.698 0.766 0.642
,DEC(SIN(RADIANS(N1)),4,3) AS SIN 50 0.872 0.642 0.766
FROM TEMP1; 60 1.047 0.500 0.866
70 1.221 0.342 0.939
80 1.396 0.173 0.984
90 1.570 0.000 1.000
Figure 214, RADIAN, COS, and SIN functions example
Figure 215, DATE function syntax
SELECT TS1 ANSWER
,DATE(TS1) AS DT1 ======================================
FROM SCALAR; TS1 DT1
-------------------------- ----------
1996-04-22-23.58.58.123456 04/22/1996
1996-08-15-15.15.15.151515 08/15/1996
0001-01-01-00.00.00.000000 01/01/0001
Figure 216, DATE function example - timestamp input
WITH TEMP1(N1) AS ANSWER
(VALUES (000001) ===================
,(728000) N1 D1
,(730120)) ------- ----------
SELECT N1 1 01/01/0001
,DATE(N1) AS D1 728000 03/13/1994
FROM TEMP1; 730120 01/01/2000
Figure 217, DATE function example - numeric input
SELECT DT1 ANSWER
,DAY(DT1) AS DAY1 ================
FROM SCALAR DT1 DAY1
WHERE DAY(DT1) > 10; ---------- ----
04/22/1996 22
08/15/1996 15
Figure 218, DAY function examples
SELECT DT1 ANSWER
,DAY(DT1) AS DAY1 =========================
,DT1 -'1996-04-30' AS DUR2 DT1 DAY1 DUR2 DAY2
,DAY(DT1 -'1996-04-30') AS DAY2 ---------- ---- ---- ----
FROM SCALAR 04/22/1996 22 -8. -8
WHERE DAY(DT1) > 10 08/15/1996 15 315. 15
ORDER BY DT1;
Figure 219, DAY function, using date-duration input
SELECT DT1 ANSWER
,DAYNAME(DT1) AS DY1 ========================
,LENGTH(DAYNAME(DT1)) AS DY2 DT1 DY1 DY2
FROM SCALAR ---------- ------- ---
WHERE DAYNAME(DT1) LIKE '%a%y' 01/01/0001 Monday 6
ORDER BY DT1; 04/22/1996 Monday 6
08/15/1996 Thursday 8
Figure 220, DAYNAME function example
SELECT DT1 ANSWER
,DAYOFWEEK(DT1) AS DWK =========================
,DAYNAME(DT1) AS DNM DT1 DWK DNM
FROM SCALAR ---------- --- --------
ORDER BY DWK 01/01/0001 2 Monday
,DNM; 04/22/1996 2 Monday
08/15/1996 5 Thursday
Figure 221, DAYOFWEEK function example
WITH ANSWER
TEMP1 (N) AS ========================
(VALUES (0) DATE DAY W D WI I
UNION ALL ---------- --- -- - -- -
SELECT N+1 1999-12-25 Sat 52 7 51 6
FROM TEMP1 1999-12-26 Sun 53 1 51 7
WHERE N < 9), 1999-12-27 Mon 53 2 52 1
TEMP2 (DT1) AS 1999-12-28 Tue 53 3 52 2
(VALUES(DATE('1999-12-25')) 1999-12-29 Wed 53 4 52 3
,(DATE('2000-12-24'))), 1999-12-30 Thu 53 5 52 4
TEMP3 (DT2) AS 1999-12-31 Fri 53 6 52 5
(SELECT DT1 + N DAYS 2000-01-01 Sat 1 7 52 6
FROM TEMP1 2000-01-02 Sun 2 1 52 7
,TEMP2) 2000-01-03 Mon 2 2 1 1
SELECT CHAR(DT2,ISO) AS DATE 2000-12-24 Sun 53 1 51 7
,SUBSTR(DAYNAME(DT2),1,3) AS DAY 2000-12-25 Mon 53 2 52 1
,WEEK(DT2) AS W 2000-12-26 Tue 53 3 52 2
,DAYOFWEEK(DT2) AS D 2000-12-27 Wed 53 4 52 3
,WEEK_ISO(DT2) AS WI 2000-12-28 Thu 53 5 52 4
,DAYOFWEEK_ISO(DT2) AS I 2000-12-29 Fri 53 6 52 5
FROM TEMP3 2000-12-30 Sat 53 7 52 6
ORDER BY 1; 2000-12-31 Sun 54 1 52 7
2001-01-01 Mon 1 2 1 1
2001-01-02 Tue 1 3 1 2
Figure 222, DAYOFWEEK_ISO function example
SELECT DT1 ANSWER
,DAYOFYEAR(DT1) AS DYR ===============
FROM SCALAR DT1 DYR
ORDER BY DYR; ---------- ---
01/01/0001 1
04/22/1996 113
08/15/1996 228
Figure 223, DAYOFYEAR function example
SELECT DT1 ANSWER
,DAYS(DT1) AS DY1 ==================
FROM SCALAR DT1 DY1
ORDER BY DY1 ---------- ------
,DT1; 01/01/0001 1
04/22/1996 728771
08/15/1996 728886
Figure 224, DAYS function example
Figure 225, DECIMAL function syntax
WITH TEMP1(N1,N2,C1,C2) AS ANSWER
(VALUES (123 ==========================
,1E2 DEC1 DEC2 DEC3 DEC4
,'123.4' ----- ------ ------ ------
,'567$8')) 123. 100.0 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 226, DECIMAL function examples
Figure 227, 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 228, DECRYPT_CHAR function example
SELECT A.NAME AS N1 ANSWER
,SOUNDEX(A.NAME) AS S1 ==============================
,B.NAME AS N2 N1 S1 N2 S2 DF
,SOUNDEX(B.NAME) AS S2 ------- ---- --------- ---- --
,DIFFERENCE Sanders S536 Sneider S536 4
(A.NAME,B.NAME) AS DF Sanders S536 Smith S530 3
FROM STAFF A Sanders S536 Lundquist L532 2
,STAFF B Sanders S536 Daniels D542 1
WHERE A.ID = 10 Sanders S536 Scoutten S350 1
AND B.ID > 150 Sanders S536 Molinare M456 1
AND B.ID < 250 Sanders S536 Lu L000 0
ORDER BY DF DESC; Sanders S536 Abrahams A165 0
Sanders S536 Kermisch K652 0
Figure 229, DIFFERENCE function example
SELECT S1 ANSWER
,DIGITS(S1) AS DS1 =========================
,D1 S1 DS1 D1 DD1
,DIGITS(D1) AS DD1 ------ ----- ----- ---
FROM SCALAR; -2 00002 -2.4 024
0 00000 0.0 000
1 00001 1.8 018
Figure 230, DIGITS function examples
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 231, DOUBLE function examples
Figure 232, DECRYPT function syntax
SELECT ID
,NAME
,ENCRYPT(NAME,'THAT IDIOT','MY BROTHER') AS NAME2
FROM STAFF
WHERE ID < 30
ORDER BY ID;
Figure 233, ENCRYPT function example
WITH TEMP1(N1) AS ANSWER
(VALUES (0) ==============================
UNION ALL N1 E1 E2
SELECT N1 + 1 -- --------------------- -----
FROM TEMP1 0 +1.00000000000000E+0 1
WHERE N1 < 10) 1 +2.71828182845904E+0 2
SELECT N1 2 +7.38905609893065E+0 7
,EXP(N1) AS E1 3 +2.00855369231876E+1 20
,SMALLINT(EXP(N1)) AS E2 4 +5.45981500331442E+1 54
FROM TEMP1; 5 +1.48413159102576E+2 148
6 +4.03428793492735E+2 403
7 +1.09663315842845E+3 1096
8 +2.98095798704172E+3 2980
9 +8.10308392757538E+3 8103
10 +2.20264657948067E+4 22026
Figure 234, EXP function examples
SELECT D1 ANSWER (float output shortened)
,FLOOR(D1) =========================================
,F1 D1 2 F1 4
,FLOOR(F1) ----- ---------- ---------- ----------
FROM SCALAR; -2.4 -3.000E+0 -2.400E+0 -3.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 235, 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 236, GENERATE_UNIQUE function examples
SELECT U1
,SUBSTR(U1,20,1) CONCAT SUBSTR(U1,19,1) CONCAT
SUBSTR(U1,18,1) CONCAT SUBSTR(U1,17,1) CONCAT
SUBSTR(U1,16,1) CONCAT SUBSTR(U1,15,1) CONCAT
SUBSTR(U1,14,1) CONCAT SUBSTR(U1,13,1) CONCAT
SUBSTR(U1,12,1) CONCAT SUBSTR(U1,11,1) CONCAT
SUBSTR(U1,10,1) CONCAT SUBSTR(U1,09,1) CONCAT
SUBSTR(U1,08,1) CONCAT SUBSTR(U1,07,1) CONCAT
SUBSTR(U1,06,1) CONCAT SUBSTR(U1,05,1) CONCAT
SUBSTR(U1,04,1) CONCAT SUBSTR(U1,03,1) CONCAT
SUBSTR(U1,02,1) CONCAT SUBSTR(U1,01,1) AS U2
FROM (SELECT HEX(GENERATE_UNIQUE()) AS U1
FROM STAFF
WHERE ID < 50) AS XXX
ORDER BY U2;
ANSWER
================================================
U1 U2
-------------------------- --------------------
20000901131649119940000000 04991194613110900002
20000901131649119793000000 39791194613110900002
20000901131649119907000000 70991194613110900002
20000901131649119969000000 96991194613110900002
Figure 237, GENERATE_UNIQUE output, characters reversed to make pseudo-random
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 238, GETHINT function example
WITH TEMP1(N1) AS ANSWER
(VALUES (-3) ===============================
UNION ALL S SHX DHX FHX
SELECT N1 + 1 -- ---- ------ ----------------
FROM TEMP1 -3 FDFF 00003D 00000000000008C0
WHERE N1 < 3) -2 FEFF 00002D 00000000000000C0
SELECT SMALLINT(N1) AS S -1 FFFF 00001D 000000000000F0BF
,HEX(SMALLINT(N1)) AS SHX 0 0000 00000C 0000000000000000
,HEX(DEC(N1,4,0)) AS DHX 1 0100 00001C 000000000000F03F
,HEX(DOUBLE(N1)) AS FHX 2 0200 00002C 0000000000000040
FROM TEMP1; 3 0300 00003C 0000000000000840
Figure 239, HEX function examples, numeric data
SELECT C1 ANSWER
,HEX(C1) AS CHX =======================================
,V1 C1 CHX V1 VHX
,HEX(V1) AS VHX ------ ------------ ------ ------------
FROM SCALAR; ABCDEF 414243444546 ABCDEF 414243444546
ABCD 414243442020 ABCD 41424344
AB 414220202020 AB 4142
Figure 240, HEX function examples, character & varchar
SELECT DT1 ANSWER
,HEX(DT1) AS DTHX ===================================
,TM1 DT1 DTHX TM1 TMHX
,HEX(TM1) AS TMHX ---------- -------- -------- ------
FROM SCALAR; 04/22/1996 19960422 23:58:58 235858
08/15/1996 19960815 15:15:15 151515
01/01/0001 00010101 00:00:00 000000
Figure 241, HEX function examples, date & time
SELECT TM1 ANSWER
,HOUR(TM1) AS HR ============
FROM SCALAR TM1 HR
ORDER BY TM1; -------- --
00:00:00 0
15:15:15 15
23:58:58 23
Figure 242, 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);
ANSWER
WITH TEMP (IDVAL) AS ======
(VALUES (IDENTITY_VAL_LOCAL())) IDVAL
SELECT * -----
FROM TEMP; 1.
Figure 243, IDENTITY_VAL_LOCAL function usage
Figure 244, INSERT function syntax
SELECT NAME ANSWER (4K output fields shortened)
,INSERT(NAME,3,2,'A') ===================================
,INSERT(NAME,3,2,'AB') NAME 2 3 4
,INSERT(NAME,3,2,'ABC') -------- ------- -------- ---------
FROM STAFF Sanders SaAers SaABers SaABCers
WHERE ID < 40; Pernal PeAal PeABal PeABCal
Marenghi MaAnghi MaABnghi MaABCnghi
Figure 245, INSERT function examples
SELECT D1 ANSWER
,INTEGER(D1) ====================================
,INT('+123') D1 2 3 4 5
,INT('-123') ----- ----- ------ ------ ------
,INT(' 123 ') -2.4 -2 123 -123 123
FROM SCALAR; 0.0 0 123 -123 123
1.8 1 123 -123 123
Figure 246, INTEGER function examples
WITH TEMP1(DT1) AS ANSWER
(VALUES ('0001-01-01-00.00.00') =========================
,('1752-09-10-00.00.00') DT DY DJ
,('1993-01-03-00.00.00') ---------- ------ -------
,('1993-01-03-23.59.59')) 01/01/0001 1 1721426
SELECT DATE(DT1) AS DT 09/10/1752 639793 2361218
,DAYS(DT1) AS DY 01/03/1993 727566 2448991
,JULIAN_DAY(DT1) AS DJ 01/03/1993 727566 2448991
FROM TEMP1;
Figure 247, JULIAN_DAY function example
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
---------- ------- -------
05/17/1926 2424653 2424653
03/28/1936 2428256 2428256
07/09/1946 2432011 2432011
04/12/1955 2435210 2435210
Figure 248, JULIAN_DAY function examples
ANSWER
=============================
DT DJ1 DJ2
WITH TEMP1(DT1) AS ---------- ---------- -------
(VALUES ('1997-01-01') 01/01/1997 12/17/1996 1997001
,('1997-01-02') 01/02/1997 12/18/1996 1997002
,('1997-12-31')) 12/31/1997 12/16/1997 1997365
SELECT DATE(DT1) AS DT
,DATE(DT1) - 15 DAYS AS DJ1
,YEAR(DT1) * 1000 + DAYOFYEAR(DT1) AS DJ2
FROM TEMP1;
Figure 249, Julian Date outputs
SELECT NAME ANSWER
,LCASE(NAME) AS LNAME =========================
,UCASE(NAME) AS UNAME NAME LNAME UNAME
FROM STAFF ------- ------- -------
WHERE ID < 30; Sanders sanders SANDERS
Pernal pernal PERNAL
Figure 250, LCASE function example
WITH TEMP1 (N1,C1) AS ANSWER
(VALUES (SMALLINT(0),CHR(0)) =================
UNION ALL N1 C1 U1 U2 L1 L2
SELECT N1 + 1 -- -- -- -- -- --
,CHR(N1 + 1)
FROM TEMP1
WHERE N1 < 255
)
SELECT N1
,C1
,UCASE(C1) AS U1
,UCASE(LCASE(C1)) AS U2
,LCASE(C1) AS L1
,LCASE(UCASE(C1)) AS L2
FROM TEMP1
WHERE UCASE(C1) <> UCASE(LCASE(C1))
OR LCASE(C1) <> LCASE(UCASE(C1));
Figure 251, LCASE and UCASE usage on special characters
WITH TEMP1(C1) AS ANSWER
(VALUES (' ABC') ================
,(' ABC ') C1 C2 L2
,('ABC ')) ----- ----- --
SELECT C1 ABC AB 4
,LEFT(C1,4) AS C2 ABC ABC 4
,LENGTH(LEFT(C1,4)) AS L2 ABC ABC 4
FROM TEMP1;
Figure 252, LEFT function examples
SELECT LENGTH(D1) ANSWER
,LENGTH(F1) =======================
,LENGTH(S1) 1 2 3 4 5
,LENGTH(C1) --- --- --- --- ---
,LENGTH(RTRIM(C1)) 2 8 2 6 6
FROM SCALAR; 2 8 2 6 4
2 8 2 6 2
Figure 253, LENGTH function examples
WITH TEMP1(N1) AS ANSWER
(VALUES (1),(123),(1234) ===============================
,(12345),(123456)) N1 L1
SELECT N1 ------ -----------------------
,LOG(N1) AS L1 1 +0.00000000000000E+000
FROM TEMP1; 123 +4.81218435537241E+000
1234 +7.11801620446533E+000
12345 +9.42100640177928E+000
123456 +1.17236400962654E+001
Figure 254, LOG function example
Figure 255, LOCATE function syntax
SELECT C1 ANSWER
,LOCATE('D', C1) ==========================
,LOCATE('D', C1,2) C1 2 3 4 5
,LOCATE('EF',C1) ------ --- --- --- ---
,LOCATE('A', C1,2) ABCDEF 4 4 5 0
FROM SCALAR; ABCD 4 4 0 0
AB 0 0 0 0
Figure 256, LOCATE function examples
WITH TEMP1(N1) AS ANSWER
(VALUES (1),(123),(1234) ===============================
,(12345),(123456)) N1 L1
SELECT N1 ------ -----------------------
,LOG10(N1) AS L1 1 +0.00000000000000E+000
FROM TEMP1; 123 +2.08990511143939E+000
1234 +3.09131515969722E+000
12345 +4.09149109426795E+000
123456 +5.09151220162777E+000
Figure 257, LOG10 function example
WITH TEMP1(C1) AS ANSWER
(VALUES (' ABC') ================
,(' ABC ') C1 C2 L2
,('ABC ')) ----- ----- --
SELECT C1 ABC ABC 3
,LTRIM(C1) AS C2 ABC ABC 4
,LENGTH(LTRIM(C1)) AS L2 ABC ABC 5
FROM TEMP1;
Figure 258, LTRIM function example
SELECT TS1 ANSWER
,MICROSECOND(TS1) ======================================
FROM SCALAR TS1 2
ORDER BY TS1; -------------------------- -----------
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 259, 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 260, MIDNIGHT_SECONDS function example
ANSWER
==============
MS TM
----- --------
WITH TEMP1 (MS) AS 0 00:00:00
(SELECT MIDNIGHT_SECONDS(TS1) 54915 15:15:15
FROM SCALAR 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 TM
FROM TEMP1
ORDER BY 1;
Figure 261, Convert MIDNIGHT_SECONDS output back to a time value
SELECT TS1 ANSWER
,MINUTE(TS1) ======================================
FROM SCALAR TS1 2
ORDER BY TS1; -------------------------- -----------
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 262, MINUTE function example
WITH TEMP1(N1,N2) AS ANSWER
(VALUES (-31,+11) =======================
UNION ALL N1 N2 DIV MD1 MD2
SELECT N1 + 13 --- --- --- --- ---
,N2 - 4 -31 11 -2 -9 -9
FROM TEMP1 -18 7 -2 -4 -4
WHERE N1 < 60 -5 3 -1 -2 -2
) 8 -1 -8 0 0
SELECT N1 21 -5 -4 1 1
,N2 34 -9 -3 7 7
,N1/N2 AS DIV 47 -13 -3 8 8
,N1-((N1/N2)*N2) AS MD1 60 -17 -3 9 9
,MOD(N1,N2) AS MD2
FROM TEMP1
ORDER BY 1;
Figure 263, MOD function example
SELECT DT1 ANSWER
,MONTH(DT1) =======================
,MONTHNAME(DT1) DT1 2 3
FROM SCALAR ---------- -- -------
ORDER BY DT1; 01/01/0001 1 January
04/22/1996 4 April
08/15/1996 8 August
Figure 264, MONTH and MONTHNAME functions example
WITH TEMP1 (N1,N2) AS
(VALUES (DECIMAL(1234,10) ANSWER
,DECIMAL(1234,10))) ========
SELECT N1 >> 1234.
,N2 >> 1234.
,N1 * N2 AS P1 >> 1522756.
,"*"(N1,N2) AS P2 >> 1522756.
,MULTIPLY_ALT(N1,N2) AS P3 >> 1522756.
FROM TEMP1;
Figure 265, Multiplying numbers - examples
<--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 266, Decimal multiplication - same output lengths
Figure 267, NODENUMBER function syntax
SELECT NODENUMBER(ID) AS NN ANSWER
FROM STAFF ======
WHERE ID = 10; NN
--
0
Figure 268, NODENUMBER function example
SELECT S1 ANSWER
,NULLIF(S1,0) =====================
,C1 S1 2 C1 4
,NULLIF(C1,'AB') --- --- ------ ------
FROM SCALAR -2 -2 ABCDEF ABCDEF
WHERE NULLIF(0,0) IS NULL; 0 - ABCD ABCD
1 1 AB -
Figure 269, NULLIF function examples
SELECT PARTITION(ID) AS PP ANSWER
FROM STAFF ======
WHERE ID = 10; PP
--
0
SELECT C1 ANSWER
,POSSTR(C1,' ') AS P1 ==================
,POSSTR(C1,'CD') AS P2 C1 P1 P2 P3
,POSSTR(C1,'cd') AS P3 ------ -- -- --
FROM SCALAR AB 3 0 0
ORDER BY 1; ABCD 5 3 0
ABCDEF 0 3 0
Figure 270, POSSTR function examples
SELECT C1 ANSWER
,POSSTR(C1,' ') AS P1 ===========================
,LOCATE(' ',C1) AS L1 C1 P1 L1 P2 L2 P3 L3 L4
,POSSTR(C1,'CD') AS P2 ------ -- -- -- -- -- -- --
,LOCATE('CD',C1) AS L2 AB 3 3 0 0 0 0 0
,POSSTR(C1,'cd') AS P3 ABCD 5 5 3 3 0 0 4
,LOCATE('cd',C1) AS L3 ABCDEF 0 0 3 3 0 0 4
,LOCATE('D',C1,2) AS L4
FROM SCALAR
ORDER BY 1;
Figure 271, POSSTR vs. LOCATE functions
WITH TEMP1(N1) AS ANSWER
(VALUES (1),(10),(100)) ===============================
SELECT N1 N1 P1 P2 P3
,POWER(N1,1) AS P1 ------- ------- ------- -------
,POWER(N1,2) AS P2 1 1 1 1
,POWER(N1,3) AS P3 10 10 100 1000
FROM TEMP1; 100 100 10000 1000000
Figure 272, POWER function examples
Figure 273, RAISE_ERROR function syntax
SELECT S1 ANSWER
,CASE ==============
WHEN S1 < 1 THEN S1 S1 S2
ELSE RAISE_ERROR('80001',C1) ------ ------
END AS S2 -2 -2
FROM SCALAR; 0 0
SQLSTATE=80001
Figure 274, 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
) =============
SELECT COUNT(*) AS #ROWS ==> 100000
,COUNT(DISTINCT RAN) AS #VALUES ==> 31242
,DEC(AVG(RAN),7,6) AS AVG_RAN ==> 0.499838
,DEC(STDDEV(RAN),7,6) AS STD_DEV 0.288706
,DEC(MIN(RAN),7,6) AS MIN_RAN 0.000000
,DEC(MAX(RAN),7,6) AS MAX_RAN 1.000000
,DEC(MAX(RAN),7,6) -
DEC(MIN(RAN),7,6) AS RANGE 1.000000
,DEC(VAR(RAN),7,6) AS VARIANCE 0.083351
FROM TEMP;
Figure 275, Sample output from RAND function
SELECT DEPTNO AS DNO ANSWER
,RAND(0) AS RAN ===========================
FROM DEPARTMENT DNO RAN
WHERE DEPTNO < 'E' --- ----------------------
ORDER BY 1; 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 276, Make reproducible random numbers (use seed)
SELECT DEPTNO AS DNO ANSWER
,RAND() AS RAN ===========================
FROM DEPARTMENT DNO RAN
WHERE DEPTNO < 'D' --- ----------------------
ORDER BY 1; A00 +2.55287331766717E-001
B01 +9.85290078432569E-001
C01 +3.18918424024171E-001
Figure 277, Make non-reproducible random numbers (no seed)
WITH TEMP1 (COL1, COL2, COL3) AS ANSWER
(VALUES (0 ===================
,SMALLINT(RAND(2)*35)*10 COL1 COL2 COL3
,DECIMAL(RAND()*10000,7,2)) ---- ---- -------
UNION ALL 0 0 9342.32
SELECT COL1 + 1 1 250 8916.28
,SMALLINT(RAND()*35)*10 2 310 5430.76
,DECIMAL(RAND()*10000,7,2) 3 150 5996.88
FROM TEMP1 4 110 8066.34
WHERE COL1 + 1 < 10 5 50 5589.77
) 6 130 8602.86
SELECT * 7 340 184.94
FROM TEMP1; 8 310 5441.14
9 70 9267.55
Figure 278, Use RAND to make sample data
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 279, Use RAND to make many distinct random values
SELECT ID ANSWER
,NAME ============
FROM STAFF ID NAME
WHERE RAND() < 0.1 --- --------
ORDER BY ID; 140 Fraye
190 Sneider
290 Quill
Figure 280, Randomly select 10% of matching rows
SELECT ID ANSWER
,NAME ============
FROM (SELECT S.* ID NAME
,ROW_NUMBER() OVER(ORDER BY RAND()) AS R --- --------
FROM STAFF S 10 Sanders
)AS XXX 30 Marenghi
WHERE R <= 5 190 Sneider
ORDER BY ID; 270 Lea
280 Wilson
Figure 281, Select five random rows
UPDATE STAFF
SET SALARY = RAND()*10000
WHERE ID < 50;
Figure 282, Use RAND to assign random salaries
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 283, REAL and other numeric function examples
Figure 284, REPEAT function syntax
SELECT ID ANSWER
,CHAR(REPEAT(NAME,3),40) ===========================
FROM STAFF ID 2
WHERE ID < 40 -- ------------------------
ORDER BY ID; 10 SandersSandersSanders
20 PernalPernalPernal
30 MarenghiMarenghiMarenghi
Figure 285, REPEAT function example
Figure 286, REPLACE function syntax
SELECT C1 ANSWER
,REPLACE(C1,'AB','XY') AS R1 ======================
,REPLACE(C1,'BA','XY') AS R2 C1 R1 R2
FROM SCALAR; ------ ------ ------
ABCDEF XYCDEF ABCDEF
ABCD XYCD ABCD
AB XY AB
Figure 287, REPLACE function examples
SELECT C1 ANSWER
,REPLACE(REPLACE( ==============
REPLACE(REPLACE(C1, C1 R1
'AB','XY'),'ab','XY'), ------ ------
'Ab','XY'),'aB','XY') ABCDEF XYCDEF
FROM SCALAR; ABCD XYCD
AB XY
Figure 288, Nested REPLACE functions
WITH TEMP1(C1) AS ANSWER
(VALUES (' ABC') ================
,(' ABC ') C1 C2 L2
,('ABC ')) ----- ----- --
SELECT C1 ABC ABC 4
,RIGHT(C1,4) AS C2 ABC ABC 4
,LENGTH(RIGHT(C1,4)) AS L2 ABC BC 4
FROM TEMP1;
Figure 289, RIGHT function examples
ANSWER
===============================================
D1 P2 P1 P0 N1 N2
------- ------- ------- ------- ------- -------
WITH TEMP1(D1) AS 123.400 123.400 123.400 123.000 120.000 100.000
(VALUES (123.400) 23.450 23.450 23.400 23.000 20.000 0.000
,( 23.450) 3.456 3.460 3.500 3.000 0.000 0.000
,( 3.456) 0.056 0.060 0.100 0.000 0.000 0.000
,( .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 290, ROUND function examples
SELECT C1 ANSWER
,RTRIM(C1) ========================
,LENGTH(C1) C1 2 3 4
,LENGTH(RTRIM(C1)) ------ ------ --- ---
FROM SCALAR; ABCDEF ABCDEF 6 6
ABCD ABCD 6 4
AB AB 6 2
Figure 291, RTRIM function example
SELECT D1 ANSWER (float output shortened)
,SIGN(D1) =========================================
,F1 D1 2 F1 4
,SIGN(F1) ----- ---------- ---------- ----------
FROM SCALAR; -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 292, SIGN function examples
WITH TEMP1(N1) AS ANSWER
(VALUES (0) =======================
UNION ALL N1 RAN COS TAN
SELECT N1 + 10 -- ----- ----- -----
FROM TEMP1 0 0.000 0.000 0.000
WHERE N1 < 90) 10 0.174 0.173 0.176
SELECT N1 20 0.349 0.342 0.363
,DEC(RADIANS(N1),4,3) AS RAN 30 0.523 0.500 0.577
,DEC(SIN(RADIANS(N1)),4,3) AS COS 40 0.698 0.642 0.839
,DEC(TAN(RADIANS(N1)),4,3) AS TAN 50 0.872 0.766 1.191
FROM TEMP1; 60 1.047 0.866 1.732
70 1.221 0.939 2.747
80 1.396 0.984 5.671
Figure 293, SIN function example
SELECT D1 ANSWER
,SMALLINT(D1) ==================================
,SMALLINT('+123') D1 2 3 4 5
,SMALLINT('-123') ----- ------ ------ ------ ------
,SMALLINT(' 123 ') -2.4 -2 123 -123 123
FROM SCALAR; 0.0 0 123 -123 123
1.8 1 123 -123 123
Figure 294, SMALLINT function examples
SELECT A.NAME AS N1 ANSWER
,SOUNDEX(A.NAME) AS S1 ==============================
,B.NAME AS N2 N1 S1 N2 S2 DF
,SOUNDEX(B.NAME) AS S2 ------- ---- --------- ---- --
,DIFFERENCE Sanders S536 Sneider S536 4
(A.NAME,B.NAME) AS DF Sanders S536 Smith S530 3
FROM STAFF A Sanders S536 Lundquist L532 2
,STAFF B Sanders S536 Daniels D542 1
WHERE A.ID = 10 Sanders S536 Scoutten S350 1
AND B.ID > 150 Sanders S536 Molinare M456 1
AND B.ID < 250 Sanders S536 Lu L000 0
ORDER BY DF DESC; Sanders S536 Abrahams A165 0
Sanders S536 Kermisch K652 0
Figure 295, SOUNDEX function example
WITH TEMP1(N1) AS ANSWER
(VALUES (1),(2),(3)) ==================
SELECT N1 N1 S1 S2 S3
,SPACE(N1) AS S1 -- ---- -- ----
,LENGTH(SPACE(N1)) AS S2 1 1 X
,SPACE(N1) || 'X' AS S3 2 2 X
FROM TEMP1; 3 3 X
Figure 296, SPACE function examples
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 297, GET SNAPSHOT command
SELECT *
FROM TABLE(SQLCACHE_SNAPSHOT()) SS
WHERE SS.NUM_EXECUTIONS <> 0;
Figure 298, SQLCACHE_SNAPSHOT function example
SELECT ORDINAL AS COLNO
,CHAR(PARMNAME,18) AS COLNAME
,TYPENAME AS COLTYPE
,LENGTH
,SCALE
FROM SYSCAT.FUNCPARMS
WHERE FUNCSCHEMA = 'SYSFUN'
AND FUNCNAME = 'SQLCACHE_SNAPSHOT'
ORDER BY COLNO;
Figure 299, List columns returned by SQLCACHE_SNAPSHOT
WITH TEMP1(N1) AS ANSWER
(VALUES (0.5),(0.0) ============
,(1.0),(2.0)) N1 S1
SELECT DEC(N1,4,3) AS N1 ----- -----
,DEC(SQRT(N1),4,3) AS S1 0.500 0.707
FROM TEMP1; 0.000 0.000
1.000 1.000
2.000 1.414
Figure 300, SQRT function example
Figure 301, 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 302, 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 303, SUBSTR function - avoid error using CASE (see previous)
SELECT NAME ANSWER
,LENGTH(NAME) AS LEN ===========================
,SUBSTR(NAME,5) AS S1 NAME LEN S1 L1 S2 L2
,LENGTH(SUBSTR(NAME,5)) AS L1 -------- --- ---- -- --- --
,SUBSTR(NAME,5,3) AS S2 Sanders 7 ers 3 ers 3
,LENGTH(SUBSTR(NAME,5,3)) AS L2 Pernal 6 al 2 al 3
FROM STAFF Marenghi 8 nghi 4 ngh 3
WHERE ID < 60; O'Brien 7 ien 3 ien 3
Hanes 5 s 1 s 3
Figure 304, SUBSTR function - fixed length output if third parm. used
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 305, Full-select with external table reference
CREATE ALIAS EMP1 FOR EMPLOYEE; ANSWER
CREATE ALIAS EMP2 FOR EMP1; =======================
TABSCHEMA TABNAME CARD
SELECT TABSCHEMA --------- -------- ----
,TABNAME GRAEME EMPLOYEE -1
,CARD
FROM SYSCAT.TABLES
WHERE TABNAME = TABLE_NAME('EMP2','GRAEME');
Figure 306, TABLE_NAME function example
CREATE VIEW FRED1 (C1, C2, C3) ANSWER
AS VALUES (11, 'AAA', 'BBB'); ===========================
TAB_SCH TAB_NME
CREATE ALIAS FRED2 FOR FRED1; -------- ------------------
CREATE ALIAS FRED3 FOR FRED2; GRAEME FRED1
GRAEME XXXXX
DROP VIEW FRED1;
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 307, 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 308, TIMESTAMP function examples
SELECT TM1 ANSWER
,TIMESTAMP_ISO(TM1) ===================================
FROM SCALAR; 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 309, 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'))
SELECT DF1
,TIMESTAMPDIFF(16,DF1) AS DIFF
,DAYS(TS1) - DAYS(TS2) AS DAYS
FROM (SELECT TS1
,TS2
,CHAR(TS1 - TS2) AS DF1
FROM (SELECT TIMESTAMP(TS1) AS TS1
,TIMESTAMP(TS2) AS TS2
FROM TEMP1
)AS TEMP2 ANSWER
)AS TEMP3; ================================
DF1 DIFF DAYS
---------------------- ---- ----
00010000000001.000000 365 366
00001130235959.000000 360 366
Figure 310, TIMESTAMPDIFF function example
WITH TEMP1 (TS1,TS2) AS
(VALUES ('1995-03-01-00.12.34.000','1995-03-01-00.00.00.000')
,('1995-03-01-00.12.00.034','1995-03-01-00.00.00.000'))
SELECT MS1
,MS2
,MS1 - MS2 AS DIFF
FROM (SELECT BIGINT(DAYS(TS1) * 86400000000
+ MIDNIGHT_SECONDS(TS1) * 1000000
+ MICROSECOND(TS1)) AS MS1
,BIGINT(DAYS(TS2) * 86400000000
+ MIDNIGHT_SECONDS(TS2) * 1000000
+ MICROSECOND(TS2)) AS MS2
FROM (SELECT TIMESTAMP(TS1) AS TS1
,TIMESTAMP(TS2) AS TS2
FROM TEMP1
)AS TEMP2
)AS TEMP3;
ANSWER
=============================================
MS1 MS2 DIFF
----------------- ----------------- ---------
62929699920034000 62929699200000000 720034000
62929699954000000 62929699200000000 754000000
Figure 311, Difference in microseconds between two timestamps
Figure 312, TRANSLATE function syntax
ANS. NOTES
==== =================
SELECT 'abcd' ==> abcd No change
,TRANSLATE('abcd') ==> ABCD Make upper case
,TRANSLATE('abcd','','a') ==> bcd 'a'=>' '
,TRANSLATE('abcd','A','A') abcd 'A'=>'A'
,TRANSLATE('abcd','A','a') Abcd 'a'=>'A'
,TRANSLATE('abcd','A','ab') A cd 'a'=>'A','b'=>' '
,TRANSLATE('abcd','A','ab',' ') A cd 'a'=>'A','b'=>' '
,TRANSLATE('abcd','A','ab','z') Azcd 'a'=>'A','b'=>'z'
FROM STAFF
WHERE ID = 10;
Figure 313, TRANSLATE function examples
ANSWER
======
SELECT C1 ==> ABCD
,REPLACE(C1,'AB','XY') ==> XYCD
,REPLACE(C1,'BA','XY') ==> ABCD
,TRANSLATE(C1,'XY','AB') XYCD
,TRANSLATE(C1,'XY','BA') YXCD
FROM SCALAR
WHERE C1 = 'ABCD';
Figure 314, REPLACE vs. TRANSLATE
ANSWER
===============================================
D1 POS2 POS1 ZERO NEG1 NEG2
------- ------- ------- ------- ------- -------
WITH TEMP1(D1) AS 123.400 123.400 123.400 123.000 120.000 100.000
(VALUES (123.400) 23.450 23.440 23.400 23.000 20.000 0.000
,( 23.450) 3.456 3.450 3.400 3.000 0.000 0.000
,( 3.456) 0.056 0.050 0.000 0.000 0.000 0.000
,( .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 315, TRUNCATE function examples
SELECT NAME ANSWER
,LCASE(NAME) AS LNAME =========================
,UCASE(NAME) AS UNAME NAME LNAME UNAME
FROM STAFF ------- ------- -------
WHERE ID < 30; Sanders sanders SANDERS
Pernal pernal PERNAL
Figure 316, UCASE function example
SELECT C1 ANSWER
,LENGTH(C1) AS L1 ========================
,VARCHAR(C1) AS V2 C1 L1 V2 L2 V3
,LENGTH(VARCHAR(C1)) AS L2 ------ -- ------ -- ----
,VARCHAR(C1,4) AS V3 ABCDEF 6 ABCDEF 6 ABCD
FROM SCALAR; ABCD 6 ABCD 6 ABCD
AB 6 AB 6 AB
Figure 317, VARCHAR function examples
SELECT WEEK(DATE('2000-01-01')) AS W1 ANSWER
,WEEK(DATE('2000-01-02')) AS W2 ==================
,WEEK(DATE('2001-01-02')) AS W3 W1 W2 W3 W4 W5
,WEEK(DATE('2000-12-31')) AS W4 -- -- -- -- --
,WEEK(DATE('2040-12-31')) AS W5 1 2 1 54 53
FROM SYSIBM.SYSDUMMY1;
Figure 318, WEEK function examples
WITH ANSWER
TEMP1 (N) AS ==========================
(VALUES (0) DTE DY WK DY WI DI
UNION ALL ---------- --- -- -- -- --
SELECT N+1 1998-12-27 Sun 53 1 52 7
FROM TEMP1 1998-12-28 Mon 53 2 53 1
WHERE N < 10), 1998-12-29 Tue 53 3 53 2
TEMP2 (DT2) AS 1998-12-30 Wed 53 4 53 3
(SELECT DATE('1998-12-27') + Y.N YEARS 1998-12-31 Thu 53 5 53 4
+ D.N DAYS 1999-01-01 Fri 1 6 53 5
FROM TEMP1 Y 1999-01-02 Sat 1 7 53 6
,TEMP1 D 1999-01-03 Sun 2 1 53 7
WHERE Y.N IN (0,2)) 1999-01-04 Mon 2 2 1 1
SELECT CHAR(DT2,ISO) DTE 1999-01-05 Tue 2 3 1 2
,SUBSTR(DAYNAME(DT2),1,3) DY 1999-01-06 Wed 2 4 1 3
,WEEK(DT2) WK 2000-12-27 Wed 53 4 52 3
,DAYOFWEEK(DT2) DY 2000-12-28 Thu 53 5 52 4
,WEEK_ISO(DT2) WI 2000-12-29 Fri 53 6 52 5
,DAYOFWEEK_ISO(DT2) DI 2000-12-30 Sat 53 7 52 6
FROM TEMP2 2000-12-31 Sun 54 1 52 7
ORDER BY 1; 2001-01-01 Mon 1 2 1 1
2001-01-02 Tue 1 3 1 2
2001-01-03 Wed 1 4 1 3
2001-01-04 Thu 1 5 1 4
2001-01-05 Fri 1 6 1 5
2001-01-06 Sat 1 7 1 6
Figure 319, WEEK_ISO function example
SELECT DT1 ANSWER
,YEAR(DT1) AS YR ======================
,WEEK(DT1) AS WK DT1 YR WK
FROM SCALAR; ---------- ---- ----
04/22/1996 1996 17
08/15/1996 1996 33
01/01/0001 1 1
Figure 320, YEAR and WEEK functions example
Figure 321, ORDER BY syntax
CREATE VIEW SEQ_DATA(COL1,COL2) AS VALUES
('ab','xy'),('AB','xy'),('ac','XY'),('AB','XY'),('Ab','12');
Figure 322, ORDER BY sample data definition
SELECT COL1 ANSWER
,COL2 =========
FROM SEQ_DATA COL1 COL2
ORDER BY COL1 ASC ---- ----
,COL2; ab xy
ac XY
Ab 12
AB xy
AB XY
Figure 323, Simple ORDER BY
SELECT COL1 ANSWER
,COL2 =========
FROM SEQ_DATA COL1 COL2
ORDER BY TRANSLATE(COL1) ASC ---- ----
,TRANSLATE(COL2) ASC Ab 12
ab xy
AB XY
AB xy
ac XY
Figure 324, Case insensitive ORDER BY
SELECT COL2 ANSWER
FROM SEQ_DATA ======
ORDER BY COL1 COL2
,COL2; ----
xy
XY
12
xy
XY
Figure 325, ORDER BY on not-displayed column
SELECT COL1 ANSWER
,COL2 =========
FROM SEQ_DATA COL1 COL2
ORDER BY SUBSTR(COL1,2) DESC ---- ----
,COL2 ac XY
,1; AB xy
AB XY
Ab 12
ab xy
Figure 326, ORDER BY second byte of first column
SELECT COL1 ANSWER
,HEX(COL1) AS HEX1 ===================
,COL2 COL1 HEX1 COL2 HEX2
,HEX(COL2) AS HEX2 ---- ---- ---- ----
FROM SEQ_DATA AB 4142 XY 5859
ORDER BY HEX(COL1) AB 4142 xy 7879
,HEX(COL2) Ab 4162 12 3132
ab 6162 xy 7879
ac 6163 XY 5859
Figure 327, ORDER BY in bit-data sequence
Figure 328, GROUP BY syntax
CREATE VIEW EMPLOYEE_VIEW AS ANSWER
SELECT SUBSTR(WORKDEPT,1,1) AS D1 ==================
,WORKDEPT AS DEPT D1 DEPT SEX SALARY
,SEX AS SEX -- ---- --- ------
,INTEGER(SALARY) AS SALARY A A00 F 52750
FROM EMPLOYEE A A00 M 29250
WHERE WORKDEPT < 'D20'; A A00 M 46500
COMMIT; B B01 M 41250
C C01 F 23800
C C01 F 28420
C C01 F 38250
D D11 F 21340
SELECT * D D11 F 22250
FROM EMPLOYEE_VIEW D D11 F 29840
ORDER BY 1,2,3,4; D D11 M 18270
D D11 M 20450
D D11 M 24680
D D11 M 25280
D D11 M 27740
D D11 M 32250
Figure 329, GROUP BY Sample Data
SELECT D1, DEPT, SEX ANSWER
,SUM(SALARY) AS SALARY ========================
,SMALLINT(COUNT(*)) AS #ROWS D1 DEPT SEX SALARY #ROWS
FROM EMPLOYEE_VIEW -- ---- --- ------ -----
WHERE DEPT <> 'ABC' A A00 F 52750 1
GROUP BY D1, DEPT, SEX A A00 M 75750 2
HAVING DEPT > 'A0' B B01 M 41250 1
AND (SUM(SALARY) > 100 C C01 F 90470 3
OR MIN(SALARY) > 10 D D11 F 73430 3
OR COUNT(*) <> 22) D D11 M 148670 6
ORDER BY D1, DEPT, SEX;
Figure 330, Simple GROUP BY
SELECT SEX ANSWER
,SUM(SALARY) AS SALARY ================
,SMALLINT(COUNT(*)) AS #ROWS SEX SALARY #ROWS
FROM EMPLOYEE_VIEW --- ------ -----
WHERE SEX IN ('F','M') F 52750 1
GROUP BY DEPT F 90470 3
,SEX F 73430 3
ORDER BY SEX; M 75750 2
M 41250 1
M 148670 6
Figure 331, GROUP BY on non-displayed field
SELECT SUM(SALARY) AS SALARY ANSWER
,SMALLINT(COUNT(*)) AS #ROWS ============
FROM EMPLOYEE_VIEW SALARY #ROWS
WHERE D1 <> 'X' ------ -----
GROUP BY SUBSTR(DEPT,3,1) 128500 3
HAVING COUNT(*) <> 99; 353820 13
Figure 332, GROUP BY on derived field, not shown
SELECT SUBSTR(DEPT,3,1) AS WPART ANSWER
,SUM(SALARY) AS SALARY ==================
,SMALLINT(COUNT(*)) AS #ROWS WPART SALARY #ROWS
FROM EMPLOYEE_VIEW ----- ------ -----
GROUP BY SUBSTR(DEPT,3,1) 1 353820 13
ORDER BY WPART DESC; 0 128500 3
Figure 333, 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 BY A
UNION ALL
GROUP BY B
UNION ALL
GROUP BY C
GROUP BY GROUPING SETS (A,(B,C)) is equivalent to GROUP BY A
UNION ALL
GROUP BY B
,BY C
Figure 334, GROUPING SETS in parenthesis vs. not
GROUP BY GROUPING SETS (A) is equivalent to GROUP BY A
,GROUPING SETS (B) ,B
,GROUPING SETS (C) ,C
GROUP BY GROUPING SETS (A) is equivalent to GROUP BY A
,GROUPING SETS ((B,C)) ,B
,C
GROUP BY GROUPING SETS (A) is equivalent to GROUP BY A
,GROUPING SETS (B,C) ,B
UNION ALL
GROUP BY A
,C
Figure 335, Multiple GROUPING SETS
GROUP BY A is equivalent to GROUP BY A
,GROUPING SETS ((B,C)) ,B
,C
Figure 336, Simple GROUP BY expression and GROUPING SETS combined
GROUP BY A is equivalent to GROUP BY A
,B ,B
,GROUPING SETS ((B,C)) ,C
GROUP BY A is equivalent to GROUP BY A
,B ,B
,GROUPING SETS (B,C) ,C
UNION ALL
GROUP BY A
,B
GROUP BY A is equivalent to GROUP BY A
,B ,B
,C ,C
,GROUPING SETS (B,C) UNION ALL
GROUP BY A
,B
,C
Figure 337, Mixing simple GROUP BY expressions and GROUPING SETS
GROUP BY GROUPING SETS ((A,B,C) is equivalent to GROUP BY A
,(A,B) ,B
,(C)) ,C
UNION ALL
GROUP BY A
,B
UNION ALL
GROUP BY C
GROUP BY GROUPING SETS ((A) is equivalent to GROUP BY A
,(B,C) UNION ALL
,(A) GROUP BY B
,A ,C
,((C))) UNION ALL
GROUP BY A
UNION ALL
GROUP BY A
UNION ALL
GROUP BY C
Figure 338, GROUPING SETS with multiple components
GROUP BY GROUPING SETS ((A,B,C) is equivalent to GROUP BY A
,(A,B) ,B
,(A) ,C
,()) UNION ALL
GROUP BY A
,B
is equivalent to UNION ALL
GROUP BY A
UNION ALL
ROLLUP(A,B,C) grand-totl
Figure 339, GROUPING SET with multiple components, using grand-total
GROUP BY GROUPING SETS ((A,B,C) is equivalent to GROUP BY A
,(A,B) ,B
,(A,C) ,C
,(B,C) UNION ALL
,(A) GROUP BY A
,(B) ,B
,(C) 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 340, 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 341, 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 342, 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 343, 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 344, Repeated field impacts query result
GROUP BY D1 is equivalent to GROUP BY D1
,DEPT ,DEPT
,GROUPING SETS ((DEPT,SEX)) SEX
GROUP BY D1 is equivalent to GROUP BY D1
,DEPT ,DEPT
,GROUPING SETS (DEPT,SEX) SEX
UNION ALL
GROUP BY D1
,DEPT
,DEPT
Figure 345, 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 346, ROLLUP vs. GROUPING SETS
GROUP BY ROLLUP(A,(B,C)) ===> GROUP BY GROUPING SETS((A,B,C)
,(A)
,())
Figure 347, ROLLUP vs. GROUPING SETS
GROUP BY ROLLUP(A) ===> GROUP BY GROUPING SETS((A,B,C)
,ROLLUP(B,C) ,(A,B)
,(A)
,(B,C)
,(B)
,())
Figure 348, ROLLUP vs. GROUPING SETS
SELECT DEPT ANSWER
,SUM(SALARY) AS SALARY ====================
,SMALLINT(COUNT(*)) AS #ROWS DEPT SALARY #ROWS FD
,GROUPING(DEPT) AS FD ---- ------ ----- --
FROM EMPLOYEE_VIEW A00 128500 3 0
GROUP BY DEPT B01 41250 1 0
ORDER BY DEPT; C01 90470 3 0
D11 222100 9 0
Figure 349, Simple GROUP BY
SELECT DEPT ANSWER
,SUM(SALARY) AS SALARY ====================
,SMALLINT(COUNT(*)) AS #ROWS DEPT SALARY #ROWS FD
,GROUPING(DEPT) AS FD ---- ------ ----- --
FROM EMPLOYEE_VIEW A00 128500 3 0
GROUP BY ROLLUP(DEPT) B01 41250 1 0
ORDER BY DEPT; C01 90470 3 0
D11 222100 9 0
- 482320 16 1
Figure 350, GROUP BY with ROLLUP
SELECT DEPT ANSWER
,SUM(SALARY) AS SALARY ====================
,SMALLINT(COUNT(*)) AS #ROWS DEPT SALARY #ROWS FD
,GROUPING(DEPT) AS FD ---- ------ ----- --
FROM EMPLOYEE_VIEW A00 128500 3 0
GROUP BY DEPT B01 41250 1 0
UNION ALL C01 90470 3 0
SELECT CAST(NULL AS CHAR(3)) AS DEPT D11 222100 9 0
,SUM(SALARY) AS SALARY - 482320 16 1
,SMALLINT(COUNT(*)) AS #ROWS
,CAST(1 AS INTEGER) AS FD
FROM EMPLOYEE_VIEW
ORDER BY DEPT;
Figure 351, ROLLUP done the old-fashioned way
SELECT DEPT ANSWER
,SUM(SALARY) AS SALARY ====================
,SMALLINT(COUNT(*)) AS #ROWS DEPT SALARY #ROWS FD
,GROUPING(DEPT) AS FD ---- ------ ----- --
FROM EMPLOYEE_VIEW A00 128500 3 0
GROUP BY DEPT A00 128500 3 0
,ROLLUP(DEPT) B01 41250 1 0
ORDER BY DEPT; B01 41250 1 0
C01 90470 3 0
C01 90470 3 0
D11 222100 9 0
D11 222100 9 0
Figure 352, 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 353, Repeating a field, explanation
SELECT DEPT ANSWER
,SEX ===========================
,SUM(SALARY) AS SALARY DEPT SEX SALARY #ROWS FD FS
,SMALLINT(COUNT(*)) AS #ROWS ---- --- ------ ----- -- --
,GROUPING(DEPT) AS FD A00 F 52750 1 0 0
,GROUPING(SEX) AS FS A00 M 75750 2 0 0
FROM EMPLOYEE_VIEW A00 - 128500 3 0 1
GROUP BY DEPT B01 M 41250 1 0 0
,ROLLUP(SEX) B01 - 41250 1 0 1
ORDER BY DEPT C01 F 90470 3 0 0
,SEX; C01 - 90470 3 0 1
D11 F 73430 3 0 0
D11 M 148670 6 0 0
D11 - 222100 9 0 1
Figure 354, GROUP BY on 1st field, ROLLUP on 2nd
SELECT DEPT ANSWER
,SEX ===========================
,SUM(SALARY) AS SALARY DEPT SEX SALARY #ROWS FD FS
,SMALLINT(COUNT(*)) AS #ROWS ---- --- ------ ----- -- --
,GROUPING(DEPT) AS FD A00 F 52750 1 0 0
,GROUPING(SEX) AS FS A00 M 75750 2 0 0
FROM EMPLOYEE_VIEW A00 - 128500 3 0 1
GROUP BY ROLLUP(DEPT B01 M 41250 1 0 0
,SEX) B01 - 41250 1 0 1
ORDER BY DEPT C01 F 90470 3 0 0
,SEX; 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 355, ROLLUP on DEPT, then SEX
SELECT SEX ANSWER
,DEPT ===========================
,SUM(SALARY) AS SALARY SEX DEPT SALARY #ROWS FD FS
,SMALLINT(COUNT(*)) AS #ROWS --- ---- ------ ----- -- --
,GROUPING(DEPT) AS FD F A00 52750 1 0 0
,GROUPING(SEX) AS FS F C01 90470 3 0 0
FROM EMPLOYEE_VIEW F D11 73430 3 0 0
GROUP BY ROLLUP(SEX F - 216650 7 1 0
,DEPT) M A00 75750 2 0 0
ORDER BY SEX M B01 41250 1 0 0
,DEPT; M D11 148670 6 0 0
M - 265670 9 1 0
- - 482320 16 1 1
Figure 356, ROLLUP on SEX, then DEPT
SELECT SEX ANSWER
,DEPT ===========================
,SUM(SALARY) AS SALARY SEX DEPT SALARY #ROWS FD FS
,SMALLINT(COUNT(*)) AS #ROWS --- ---- ------ ----- -- --
,GROUPING(DEPT) AS FD F A00 52750 1 0 0
,GROUPING(SEX) AS FS F C01 90470 3 0 0
FROM EMPLOYEE_VIEW F D11 73430 3 0 0
GROUP BY GROUPING SETS ((SEX, DEPT) F - 216650 7 1 0
,(SEX) M A00 75750 2 0 0
,()) M B01 41250 1 0 0
ORDER BY SEX M D11 148670 6 0 0
,DEPT; M - 265670 9 1 0
- - 482320 16 1 1
Figure 357, ROLLUP on SEX, then DEPT
SELECT SEX ANSWER
,DEPT ===========================
,SUM(SALARY) AS SALARY SEX DEPT SALARY #ROWS FD FS
,SMALLINT(COUNT(*)) AS #ROWS --- ---- ------ ----- -- --
,GROUPING(DEPT) AS FD F A00 52750 1 0 0
,GROUPING(SEX) AS FS F C01 90470 3 0 0
FROM EMPLOYEE_VIEW F D11 73430 3 0 0
GROUP BY ROLLUP(SEX) F - 216650 7 1 0
,ROLLUP(DEPT) M A00 75750 2 0 0
ORDER BY SEX M B01 41250 1 0 0
,DEPT; 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
Figure 358, Two independent ROLLUPS
SELECT DEPT ANSWER
,SEX ===========================
,SUM(SALARY) AS SALARY DEPT SEX SALARY #ROWS FD FS
,SMALLINT(COUNT(*)) AS #ROWS ---- --- ------ ----- -- --
,GROUPING(DEPT) AS FD A00 F 52750 1 0 0
,GROUPING(SEX) AS FS A00 M 75750 2 0 0
FROM EMPLOYEE_VIEW B01 M 41250 1 0 0
GROUP BY ROLLUP((DEPT,SEX)) C01 F 90470 3 0 0
ORDER BY DEPT D11 F 73430 3 0 0
,SEX; D11 M 148670 6 0 0
- - 482320 16 1 1
Figure 359, Combined-field ROLLUP
SELECT SUM(SALARY) AS SALARY ANSWER
,SMALLINT(COUNT(*)) AS #ROWS ============
FROM EMPLOYEE_VIEW SALARY #ROWS
GROUP BY ROLLUP(SEX ------ -----
,DEPT) 482320 16
HAVING GROUPING(DEPT) = 1
AND GROUPING(SEX) = 1
ORDER BY SALARY;
Figure 360, Use HAVING to get only grand-total row
SELECT SUM(SALARY) AS SALARY ANSWER
,SMALLINT(COUNT(*)) AS #ROWS ============
FROM EMPLOYEE_VIEW SALARY #ROWS
GROUP BY GROUPING SETS(()); ------ -----
482320 16
Figure 361, Use GROUPING SETS to get grand-total row
SELECT SUM(SALARY) AS SALARY ANSWER
,SMALLINT(COUNT(*)) AS #ROWS ============
FROM EMPLOYEE_VIEW SALARY #ROWS
GROUP BY (); ------ -----
482320 16
Figure 362, Use GROUP BY to get grand-total row
SELECT SUM(SALARY) AS SALARY ANSWER
,SMALLINT(COUNT(*)) AS #ROWS ============
FROM EMPLOYEE_VIEW; SALARY #ROWS
------ -----
482320 16
Figure 363, Get grand-total row directly
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 364, CUBE vs. GROUPING SETS
GROUP BY CUBE(A,(B,C)) ===> GROUP BY GROUPING SETS((A,B,C)
,(B,C)
,(A)
,())
Figure 365, CUBE vs. GROUPING SETS
GROUP BY CUBE(A,B) ==> GROUPING SETS((A,B,C),(A,B),(A,B,C),(A,B)
,CUBE(B,C) ,(A,B,C),(A,B),(A,C),(A)
,(B,C),(B),(B,C),(B)
,(B,C),(B),(C),())
Figure 366, CUBE vs. GROUPING SETS
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 A A00 - 128500 3 0 0 1
,GROUPING(SEX) AS FS A - F 52750 1 0 1 0
FROM EMPLOYEE_VIEW A - M 75750 2 0 1 0
GROUP BY CUBE(D1, DEPT, SEX) A - - 128500 3 0 1 1
ORDER BY D1 B B01 M 41250 1 0 0 0
,DEPT B B01 - 41250 1 0 0 1
,SEX; 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
- A00 F 52750 1 1 0 0
- A00 M 75750 2 1 0 0
- A00 - 128500 3 1 0 1
- B01 M 41250 1 1 0 0
- B01 - 41250 1 1 0 1
- C01 F 90470 3 1 0 0
- C01 - 90470 3 1 0 1
- D11 F 73430 3 1 0 0
- D11 M 148670 6 1 0 0
- D11 - 222100 9 1 0 1
- - F 216650 7 1 1 0
- - M 265670 9 1 1 0
- - - 482320 16 1 1 1
Figure 367, 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 368, CUBE expressed using multiple GROUPING SETS
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 (ROLLUP(D1, DEPT, SEX)
,(DEPT, SEX)
,(SEX, DEPT)
,(D1, SEX))
ORDER BY D1
,DEPT
,SEX;
Figure 369, CUBE expressed using ROLLUP and GROUPING SETS
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 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 CUBE((D1, DEPT, SEX)) D D11 M 148670 6 0 0 0
ORDER BY D1 - - - 482320 16 1 1 1
,DEPT
,SEX;
Figure 370, CUBE on compound fields
GROUP BY CUBE((A,B,C) => GROUP BY GROUING SETS ((A,B,C) => GROUP BY A
,()) ,B
,C
UNION ALL
GROUP BY()
Figure 371, CUBE on compound field, explanation
SELECT D1 AS D1 ANSWER
,DEPT AS DPT ==================
,SEX AS SX D1 DPT SX SAL R
,INT(SUM(SALARY)) AS SAL -- --- -- ------ -
,SMALLINT(COUNT(*)) AS R A A00 F 52750 1
FROM EMPLOYEE_VIEW A A00 M 75750 2
GROUP BY D1 B B01 M 41250 1
,DEPT C C01 F 90470 3
,SEX D D11 F 73430 3
ORDER BY 1,2,3; D D11 M 148670 6
Figure 372, Basic GROUP BY example
DESIRED SUB-TOTALS EQUIVILENT TO
================== =====================================
D1, DEPT, and SEX. GROUP BY GROUPING SETS ((D1,DEPT,SEX)
D1 and DEPT. ,(D1,DEPT)
D1 and SEX. ,(D1,SEX)
D1. ,(D1)
SEX. ,(SEX)
Grand total. ,())
GROUP BY ROLLUP(D1,DEPT)
,ROLLUP(SEX)
Figure 373, Sub-totals that we want to get
SELECT *
FROM (SELECT D1 AS D1
,DEPT AS DPT
,SEX AS SX
,INT(SUM(SALARY)) AS 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 374, Get lots of sub-totals, using CUBE
(G1,GD,GS) = (0,0,0) <== D1, DEPT, SEX
(G1,GD,GS) = (0,0,1) <== D1, DEPT
(G1,GD,GS) = (0,1,0) <== D1, SEX
(G1,GD,GS) = (0,1,1) <== D1,
(G1,GD,GS) = (1,1,0) <== SEX,
(G1,GD,GS) = (1,1,1) <== grand total
Figure 375, Predicates used - explanation
SELECT D1 ANSWER
,DEPT =====================
,SEX D1 DEPT SEX SAL #R
,INT(SUM(SALARY)) AS SAL -- ---- --- ------ --
,SMALLINT(COUNT(*)) AS #R A A00 F 52750 1
FROM EMPLOYEE_VIEW A A00 M 75750 2
GROUP BY ROLLUP(D1,DEPT) A A00 - 128500 3
,ROLLUP(SEX) A - F 52750 1
ORDER BY 1,2,3; A - M 75750 2
A - - 128500 3
B B01 M 41250 1
B B01 - 41250 1
B - M 41250 1
B - - 41250 1
C C01 F 90470 3
C C01 - 90470 3
C - F 90470 3
C - - 90470 3
D D11 F 73430 3
D D11 M 148670 6
D D11 - 222100 9
D - F 73430 3
D - M 148670 6
D - - 222100 9
- - F 216650 7
- - M 265670 9
- - - 482320 16
Figure 376, Get lots of sub-totals, using ROLLUP
SELECT DEPT, JOB
,COUNT(*)
FROM STAFF
GROUP BY DEPT, JOB
ORDER BY DEPT, JOB;
Figure 377, 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 378, GROUP BY on one side of join - using common table expression
SELECT A.ID ANSWER
,A.NAME =================
,A.DEPT ID NAME DEPT
FROM STAFF A --- -------- ----
,(SELECT DEPT AS DEPT 160 Molinare 10
,AVG(SALARY) AS AVGSAL 210 Lu 10
FROM STAFF 240 Daniels 10
GROUP BY DEPT 260 Jones 10
HAVING AVG(SALARY) > 18000
)AS B
WHERE A.DEPT = B.DEPT
ORDER BY A.ID;
Figure 379, GROUP BY on one side of join - using full-select
SELECT COUNT(*) AS C1 ANSWER
FROM STAFF ======
WHERE ID < 1; 0
SELECT COUNT(*) AS C1 ANSWER
FROM STAFF ======
WHERE ID < 1 no row
GROUP BY ID;
Figure 380, COUNT and No Rows
CREATE VIEW STAFF_V1 AS STAFF_V1 STAFF_V2
SELECT ID, NAME +-----------+ +---------+
FROM STAFF |ID|NAME | |ID|JOB |
WHERE ID BEWTEEEN 10 AND 30; |--|--------| |--|------|
|10|Sanders | |20|Sales |
CREATE VIEW STAFF_V2 AS |20|Pernal | |30|Mgr |
SELECT ID, JOB |30|Marenghi| |40|Sales |
FROM STAFF +-----------+ |50|Mgr |
WHERE ID BETWEEN 20 AND 50; +---------+
Figure 381, Sample Views used in Join Examples
Figure 382, Join Syntax #1
SELECT V1.ID JOIN ANSWER
,V1.NAME =================
,V2.JOB ID NAME JOB
FROM STAFF_V1 V1 -- -------- -----
,STAFF_V2 V2 20 Pernal Sales
WHERE V1.ID = V2.ID 30 Marenghi Mgr
ORDER BY V1.ID;
Figure 383, Sample two-table join
SELECT V1.ID JOIN ANSWER
,V2.JOB ===============
,V3.NAME ID JOB NAME
FROM STAFF_V1 V1 -- --- --------
,STAFF_V2 V2 30 Mgr Marenghi
,STAFF_V1 V3
WHERE V1.ID = V2.ID
AND V2.ID = V3.ID
AND V3.NAME LIKE 'M%'
ORDER BY V1.NAME;
Figure 384, Sample three-table join
Figure 385, Join Syntax #2
SELECT V1.ID JOIN ANSWER
,V1.NAME =================
,V2.JOB ID NAME JOB
FROM STAFF_V1 V1 -- -------- -----
INNER JOIN 20 Pernal Sales
STAFF_V2 V2 30 Marenghi Mgr
ON V1.ID = V2.ID
ORDER BY V1.ID;
Figure 386, Sample two-table inner join
SELECT V1.ID JOIN ANSWER
,V2.JOB ===============
,V3.NAME ID JOB NAME
FROM STAFF_V1 V1 -- --- --------
JOIN 30 Mgr Marenghi
STAFF_V2 V2
ON V1.ID = V2.ID
JOIN
STAFF_V1 V3
ON V2.ID = V3.ID
WHERE V3.NAME LIKE 'M%'
ORDER BY V1.NAME;
Figure 387, Sample three-table inner join
STAFF_V1 STAFF_V2 INNER-JOIN ANSWER
+-----------+ +---------+ ====================
|ID|NAME | |ID|JOB | ID NAME ID JOB
|--|--------| |--|------| =========> -- -------- -- -----
|10|Sanders | |20|Sales | 20 Pernal 20 Sales
|20|Pernal | |30|Mgr | 30 Marenghi 30 Mgr
|30|Marenghi| |40|Sales |
+-----------+ |50|Mgr |
+---------+
Figure 388, Example of Inner Join
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
,STAFF_V2 V2 ID NAME ID JOB
WHERE V1.ID = V2.ID -- -------- -- -----
ORDER BY V1.ID; 20 Pernal 20 Sales
30 Marenghi 30 Mgr
Figure 389, 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;
Figure 390, Inner Join SQL (2 of 2)
STAFF_V1 STAFF_V2 CARTESIAN-PRODUCT
+-----------+ +---------+ ====================
|ID|NAME | |ID|JOB | ID NAME ID JOB
|--|--------| |--|------| =========> -- -------- -- -----
|10|Sanders | |20|Sales | 10 Sanders 20 Sales
|20|Pernal | |30|Mgr | 10 Sanders 30 Mgr
|30|Marenghi| |40|Sales | 10 Sanders 40 Sales
+-----------+ |50|Mgr | 10 Sanders 50 Mgr
+---------+ 20 Pernal 20 Sales
20 Pernal 30 Mgr
20 Pernal 40 Sales
20 Pernal 50 Mgr
30 Marenghi 20 Sales
30 Marenghi 30 Mgr
30 Marenghi 40 Sales
30 Marenghi 50 Mgr
Figure 391, Example of Cartesian Product
SELECT *
FROM STAFF_V1 V1
,STAFF_V2 V2
ORDER BY V1.ID
,V2.ID;
Figure 392, 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;
Figure 393, Cartesian Product SQL (2 of 2)
SELECT V2A.ID ANSWER
,V2A.JOB ===========
,V2B.ID ID JOB ID
FROM STAFF_V2 V2A -- ----- --
,STAFF_V2 V2B 20 Sales 20
WHERE V2A.JOB = V2B.JOB 20 Sales 40
AND V2A.ID < 40 30 Mgr 30
ORDER BY V2A.ID 30 Mgr 50
,V2B.ID;
Figure 394, Partial Cartesian Product SQL
SELECT V2.JOB ANSWER
,COUNT(*) AS #ROWS ===========
FROM STAFF_V1 V1 JOB #ROWS
,STAFF_V2 V2 ----- -----
GROUP BY V2.JOB Mgr 6
ORDER BY #ROWS Sales 6
,V2.JOB;
Figure 395, Partial Cartesian Product SQL, with GROUP BY
STAFF_V1 STAFF_V2 LEFT-OUTER-JOIN ANSWER
+-----------+ +---------+ ======================
|ID|NAME | |ID|JOB | ID NAME ID JOB
|--|--------| |--|------| =========> -- -------- -- -----
|10|Sanders | |20|Sales | 10 Sanders - -
|20|Pernal | |30|Mgr | 20 Pernal 20 Sales
|30|Marenghi| |40|Sales | 30 Marenghi 30 Mgr
+-----------+ |50|Mgr |
+---------+
Figure 396, Example of Left Outer Join
SELECT *
FROM STAFF_V1 V1
LEFT OUTER JOIN
STAFF_V2 V2
ON V1.ID = V2.ID
ORDER BY V1.ID;
Figure 397, Left Outer Join SQL (1 of 2)
SELECT V1.* <== This join gets all
,V2.* rows in STAFF_V1
FROM STAFF_V1 V1 that match rows
,STAFF_V2 V2 in STAFF_V2.
WHERE V1.ID = V2.ID
UNION
SELECT V1.* <== This query gets
,CAST(NULL AS SMALLINT) AS ID all the rows in
,CAST(NULL AS CHAR(5)) AS JOB STAFF_V1 with no
FROM STAFF_V1 V1 matching rows
WHERE V1.ID NOT IN in STAFF_V2.
(SELECT ID FROM STAFF_V2)
ORDER BY 1,3;
Figure 398, Left Outer Join SQL (2 of 2)
STAFF_V1 STAFF_V2 RIGHT-OUTER-JOIN ANSWER
+-----------+ +---------+ =======================
|ID|NAME | |ID|JOB | ID NAME ID JOB
|--|--------| |--|------| =========> -- -------- -- -----
|10|Sanders | |20|Sales | 20 Pernal 20 Sales
|20|Pernal | |30|Mgr | 30 Marenghi 30 Mgr
|30|Marenghi| |40|Sales | - - 40 Sales
+-----------+ |50|Mgr | - - 50 Mgr
+---------+
Figure 399, Example of Right Outer Join
SELECT *
FROM STAFF_V1 V1
RIGHT OUTER JOIN
STAFF_V2 V2
ON V1.ID = V2.ID
ORDER BY V2.ID;
Figure 400, Right Outer Join SQL (1 of 2)
SELECT V1.* ANSWER
,V2.* ====================
FROM STAFF_V1 V1 ID NAME ID JOB
,STAFF_V2 V2 -- -------- -- -----
WHERE V1.ID = V2.ID 20 Pernal 20 Sales
UNION 30 Marenghi 30 Mgr
SELECT CAST(NULL AS SMALLINT) AS ID - - 40 Sales
,CAST(NULL AS VARCHAR(9)) AS NAME - - 50 Mgr
,V2.*
FROM STAFF_V2 V2
WHERE V2.ID NOT IN
(SELECT ID FROM STAFF_V1)
ORDER BY 1,3;
Figure 401, Right Outer Join SQL (2 of 2)
STAFF_V1 STAFF_V2 FULL-OUTER-JOIN ANSWER
+-----------+ +---------+ ======================
|ID|NAME | |ID|JOB | ID NAME ID JOB
|--|--------| |--|------| =========> -- -------- -- -----
|10|Sanders | |20|Sales | 10 Sanders - -
|20|Pernal | |30|Mgr | 20 Pernal 20 Sales
|30|Marenghi| |40|Sales | 30 Marenghi 30 Mgr
+-----------+ |50|Mgr | - - 40 Sales
+---------+ - - 50 Mgr
Figure 402, 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;
Figure 403, Full Outer Join SQL
SELECT V1.*
,V2.*
FROM STAFF_V1 V1
,STAFF_V2 V2
WHERE V1.ID = V2.ID
UNION
SELECT 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)
UNION
SELECT 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;
Figure 404, Full Outer Join SQL
SELECT COALESCE(V1.ID,V2.ID) AS ID ANSWER
,COALESCE(V1.NAME,'?') AS NAME =================
,V2.JOB ID NAME JOB
FROM STAFF_V1 V1 -- -------- -----
FULL OUTER JOIN 10 Sanders -
STAFF_V2 V2 20 Pernal Sales
ON V1.ID = V2.ID 30 Marenghi Mgr
ORDER BY ID; 40 ? Sales
50 ? Mgr
Figure 405, Use of COALESCE function in outer join
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
FULL OUTER JOIN ID NAME ID JOB
STAFF_V2 V2 -- -------- -- -----
ON V1.ID = V2.ID 10 Sanders - -
ORDER BY V1.ID 20 Pernal 20 Sales
,V2.ID; 30 Marenghi 30 Mgr
- - 40 Sales
- - 50 Mgr
Figure 406, Full Outer Join, match on keys
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
FULL OUTER JOIN ID NAME ID JOB
STAFF_V2 V2 -- -------- -- -----
ON V1.ID = V2.ID 10 Sanders - -
AND V1.ID > 20 20 Pernal - -
ORDER BY V1.ID 30 Marenghi 30 Mgr
,V2.ID; - - 20 Sales
- - 40 Sales
- - 50 Mgr
Figure 407, Full Outer Join, match on keys > 20
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
FULL OUTER JOIN ID NAME ID JOB
STAFF_V2 V2 -- -------- -- -----
ON V1.ID = V2.ID 10 Sanders - -
AND +1 = -1 20 Pernal - -
ORDER BY V1.ID 30 Marenghi - -
,V2.ID; - - 20 Sales
- - 30 Mgr
- - 40 Sales
- - 50 Mgr
Figure 408, Full Outer Join, match on keys (no rows match)
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
FULL OUTER JOIN ID NAME ID JOB
STAFF_V2 V2 -- -------- -- -----
ON +1 = -1 10 Sanders - -
ORDER BY V1.ID 20 Pernal - -
,V2.ID; 30 Marenghi - -
- - 20 Sales
- - 30 Mgr
- - 40 Sales
- - 50 Mgr
Figure 409, Full Outer Join, don't match on keys (no rows match)
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
FULL OUTER JOIN ID NAME ID JOB
STAFF_V2 V2 -- -------- -- -----
ON +1 <> -1 10 Sanders 20 Sales
ORDER BY V1.ID 10 Sanders 30 Mgr
,V2.ID; 10 Sanders 40 Sales
10 Sanders 50 Mgr
20 Pernal 20 Sales
20 Pernal 30 Mgr
20 Pernal 40 Sales
20 Pernal 50 Mgr
30 Marenghi 20 Sales
30 Marenghi 30 Mgr
30 Marenghi 40 Sales
30 Marenghi 50 Mgr
Figure 410, Full Outer Join, don't match on keys (all rows match)
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
FULL JOIN ID NAME ID JOB
STAFF_V2 V2 -- -------- -- -----
ON V1.ID = V2.ID 20 Pernal 20 Sales
WHERE V1.ID = V2.ID 30 Marenghi 30 Mgr
ORDER BY 1,3;
Figure 411, Full Outer Join, turned into an inner join by WHERE
STAFF_V1 STAFF_V2
+-----------+ +---------+ ANSWER
|ID|NAME | |ID|JOB | OUTER-JOIN CRITERIA ============
|--|--------| |--|------| ==================> ???, DEPENDS
|10|Sanders | |20|Sales | V1.ID = V2.ID
|20|Pernal | |30|Mgr | V1.ID < 30
|30|Marenghi| |40|Sales |
+-----------+ |50|Mgr |
+---------+
Figure 412, Outer join V1.ID < 30, sample data
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;
Figure 413, Outer join V1.ID < 30, check applied in WHERE (after join)
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
FULL JOIN ID NAME ID JOB
STAFF_V2 V2 -- -------- -- -----
ON V1.ID = V2.ID 10 Sanders - -
AND V1.ID < 30 20 Pernal 20 Sales
ORDER BY 1,3; 30 Marenghi - -
- - 30 Mgr
- - 40 Sales
- - 50 Mgr
Figure 414, Outer join V1.ID < 30, check applied in ON (during join)
SELECT * ANSWER
FROM (SELECT * ====================
FROM STAFF_V1 ID NAME ID JOB
WHERE ID < 30) AS V1 -- -------- -- -----
FULL OUTER JOIN 10 Sanders - -
STAFF_V2 V2 20 Pernal 20 Sales
ON V1.ID = V2.ID - - 30 Mgr
ORDER BY 1,3; - - 40 Sales
- - 50 Mgr
Figure 415, Outer join V1.ID < 30, check applied in WHERE (before join)
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
FULL OUTER JOIN ID NAME ID JOB
STAFF_V2 V2 -- -------- -- -----
ON V1.ID = V2.ID 10 Sanders - -
WHERE V1.ID < 30 20 Pernal 20 Sales
OR V1.ID IS NULL - - 40 Sales
ORDER BY 1,3; - - 50 Mgr
Figure 416, Outer join V1.ID < 30, (gives wrong answer - see text)
SELECT * ANSWER
FROM STAFF_V1 V1 ====================
FULL OUTER JOIN ID NAME ID JOB
STAFF_V2 V2 -- -------- -- -----
ON V1.ID = V2.ID 10 Sanders - -
WHERE V1.ID < 30 20 Pernal 20 Sales
OR V1.ID = V2.ID 30 Marenghi 30 Sales
OR V1.ID IS NULL - - 40 Sales
ORDER BY 1,3; - - 50 Mgr
Figure 417, Outer join V1.ID < 30, (gives wrong answer - see text)
STAFF_V1 STAFF_V2 ANSWER
+-----------+ +---------+ NON-MATCHING ===================
|ID|NAME | |ID|JOB | OUTER-JOIN ID NAME ID JOB
|--|--------| |--|------| ===========> -- ------- -- -----
|10|Sanders | |20|Sales | 10 Sanders - -
|20|Pernal | |30|Mgr | - - 40 Sales
|30|Marenghi| |40|Sales | - - 50 Mgr
+-----------+ |50|Mgr |
+---------+
Figure 418, Example of outer join, only getting the non-matching rows
SELECT V1.* <== Get all the rows
,CAST(NULL AS SMALLINT) AS ID in STAFF_V1 that
,CAST(NULL AS CHAR(5)) AS JOB have no matching
FROM STAFF_V1 V1 row in STAFF_V2.
WHERE V1.ID NOT IN
(SELECT ID FROM STAFF_V2)
UNION
SELECT CAST(NULL AS SMALLINT) AS ID <== Get all the rows
,CAST(NULL AS VARCHAR(9)) AS NAME in STAFF_V2 that
,V2.* have no matching
FROM STAFF_V2 V2 row in STAFF_V1.
WHERE V2.ID NOT IN
(SELECT ID FROM STAFF_V1)
ORDER BY 1,3;
Figure 419, Outer Join SQL, getting only non-matching rows
SELECT *
FROM (SELECT V1.* ,'V1' AS FLAG FROM STAFF_V1 V1) AS V1
FULL OUTER JOIN
(SELECT V2.* ,'V2' AS FLAG FROM STAFF_V2 V2) AS V2
ON V1.ID = V2.ID
WHERE V1.FLAG IS NULL ANSWER
OR V2.FLAG IS NULL =============================
ORDER BY V1.ID ID NAME FLAG ID JOB FLAG
,V2.ID; -- ------- ---- -- ----- ----
10 Sanders V1 - - -
- - - 40 Sales V2
- - - 50 Mgr V2
Figure 420, 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
FULL OUTER JOIN ANSWER
V2 V2 =============================
ON V1.ID = V2.ID ID NAME FLAG ID JOB FLAG
WHERE V1.FLAG IS NULL -- ------- ---- -- ----- ----
OR V2.FLAG IS NULL 10 Sanders V1 - - -
ORDER BY V1.ID - - - 40 Sales V2
,V2.ID; - - - 50 Mgr V2
Figure 421, Outer Join SQL, getting only non-matching rows
SELECT * STAFF_V1 STAFF_V2
FROM STAFF_V1 V1 +-----------+ +---------+
FULL OUTER JOIN |ID|NAME | |ID|JOB |
STAFF_V2 V2 |--|--------| |--|------|
ON V1.ID = V2.ID |10|Sanders | |20|Sales |
WHERE V1.ID IS NULL |20|Pernal | |30|Mgr |
OR V2.ID IS NULL |30|Marenghi| |40|Sales |
ORDER BY V1.ID +-----------+ |50|Mgr |
,V2.ID; +---------+
Figure 422, Outer Join SQL, getting only non-matching rows
SELECT V1.ID ANSWER
,V1.NAME =================
,V2.JOB ID NAME JOB
FROM STAFF_V1 V1 -- -------- -----
LEFT OUTER JOIN 10 Sanders -
STAFF_V2 V2 20 Pernal Sales
ON V1.ID = V2.ID 30 Marenghi Mgr
ORDER BY V1.ID;
Figure 423, Outer Join done in FROM phrase of SQL
SELECT V1.ID ANSWER
,V1.NAME =================
,(SELECT V2.JOB ID NAME JOB
FROM STAFF_V2 V2 -- -------- -----
WHERE V1.ID = V2.ID) 10 Sanders -
FROM STAFF_V1 V1 20 Pernal Sales
ORDER BY V1.ID; 30 Marenghi Mgr
Figure 424, Outer Join done in SELECT phrase of SQL
SELECT V1.ID ANSWER
,V1.NAME ====================
,(SELECT V2.JOB ID NAME JOB J2
FROM STAFF_V2 V2 -- -------- ----- --
WHERE V1.ID = V2.ID) 10 Sanders - -
,(SELECT LENGTH(V2.JOB) AS J2 20 Pernal Sales 5
FROM STAFF_V2 V2 30 Marenghi Mgr 5
WHERE V1.ID = V2.ID)
FROM STAFF_V1 V1
ORDER BY V1.ID;
Figure 425, Outer Join done in SELECT, 2 columns
SELECT V1.ID ANSWER
,V1.NAME ====================
,V2.JOB ID NAME JOB J2
,LENGTH(V2.JOB) AS J2 -- -------- ----- --
FROM STAFF_V1 V1 10 Sanders - -
LEFT OUTER JOIN 20 Pernal Sales 5
STAFF_V2 V2 30 Marenghi Mgr 5
ON V1.ID = V2.ID
ORDER BY V1.ID;
Figure 426, Outer Join done in FROM, 2 columns
SELECT V1.ID ANSWER
,V1.NAME ==================
,(SELECT SUM(X1.ID) ID NAME SUM_ID
FROM STAFF_V1 X1 -- -------- ------
WHERE X1.ID <= V1.ID 10 Sanders 10
)AS SUM_ID 20 Pernal 30
FROM STAFF_V1 V1 30 Marenghi 60
ORDER BY V1.ID;
Figure 427, Running total, using JOIN in SELECT
SELECT V1.ID ANSWER
,V1.NAME ==================
,SUM(ID) OVER(ORDER BY ID) AS SUM_ID ID NAME SUM_ID
FROM STAFF_V1 V1 -- -------- ------
ORDER BY V1.ID; 10 Sanders 10
20 Pernal 30
30 Marenghi 60
Figure 428, Running total, using OLAP function
STAFF_V1 STAFF_V2 ANSWER
+-----------+ +---------+ =================
|ID|NAME | |ID|JOB | OUTER-JOIN CRITERIA ID NAME JOB
|--|--------| |--|------| ==================> -- -------- -----
|10|Sanders | |20|Sales | V1.ID = V2.ID 10 Sanders -
|20|Pernal | |30|Mgr | V2.JOB LIKE 'S%' 20 Pernal Sales
|30|Marenghi| |40|Sales | 30 Marenghi -
+-----------+ |50|Mgr |
+---------+
Figure 429, Outer join, with WHERE filter
SELECT V1.ID ANSWER (WRONG)
,V1.NAME =================
,V2.JOB ID NAME JOB
FROM STAFF_V1 V1 -- -------- -----
LEFT OUTER JOIN 20 Pernal Sales
STAFF_V2 V2
ON V1.ID = V2.ID
WHERE V2.JOB LIKE 'S%'
ORDER BY V1.ID;
Figure 430, Outer Join, WHERE done after - wrong
SELECT V1.ID ANSWER
,V1.NAME =================
,V2.JOB ID NAME JOB
FROM STAFF_V1 V1 -- -------- -----
LEFT OUTER JOIN 10 Sanders -
(SELECT * 20 Pernal Sales
FROM STAFF_V2 30 Marenghi -
WHERE JOB LIKE 'S%'
)AS V2
ON V1.ID = V2.ID
ORDER BY V1.ID;
Figure 431, 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;
Figure 432, Outer Join, WHERE done independently - correct
CREATE TABLE TABLE1 TABLE1 TABLE2
(T1A CHAR(1) NOT NULL +-------+ +-----------+
,T1B CHAR(2) NOT NULL |T1A|T1B| |T2A|T2B|T2C|
,PRIMARY KEY(T1A)); |---|---| |---|---|---|
COMMIT; |A |AA | |A |A |A |
|B |BB | |B |A | - |
CREATE TABLE TABLE2 |C |CC | +-----------+
(T2A CHAR(1) NOT NULL +-------+ "-" = null
,T2B CHAR(1) NOT NULL
,T2C CHAR(1));
INSERT INTO TABLE1 VALUES ('A','AA'),('B','BB'),('C','CC');
INSERT INTO TABLE2 VALUES ('A','A','A'),('B','A',NULL);
Figure 433, Sample tables used in sub-query examples
Figure 434, Sub-query syntax diagram
SELECT * ANSWER
FROM TABLE1 =======
WHERE T1A = T1A T1B
(SELECT T2A --- --
FROM TABLE2 A AA
WHERE T2A = 'A');
SUB-Q TABLE1 TABLE2
RESLT +-------+ +-----------+
+---+ |T1A|T1B| |T2A|T2B|T2C|
|T2A| |---|---| |---|---|---|
|---| |A |AA | |A |A |A |
|A | |B |BB | |B |A | - |
+---+ |C |CC | +-----------+
+-------+ "-" = null
Figure 435, No keyword sub-query, works
SELECT * ANSWER
FROM TABLE1 =======
WHERE T1A =
(SELECT T2A
FROM TABLE2);
SUB-Q TABLE1 TABLE2
RESLT +-------+ +-----------+
+---+ |T1A|T1B| |T2A|T2B|T2C|
|T2A| |---|---| |---|---|---|
|---| |A |AA | |A |A |A |
|A | |B |BB | |B |A | - |
|B | |C |CC | +-----------+
+---+ +-------+ "-" = null
Figure 436, No keyword sub-query, fails
SELECT * ANSWER SUB-Q TABLE1 TABLE2
FROM TABLE1 ======= RESLT +-------+ +-----------+
WHERE T1A > ANY T1A T1B +---+ |T1A|T1B| |T2A|T2B|T2C|
(SELECT T2A --- -- |T2A| |---|---| |---|---|---|
FROM TABLE2); B BB |---| |A |AA | |A |A |A |
C CC |A | |B |BB | |B |A | - |
|B | |C |CC | +-----------+
+---+ +-------+ "-" = null
Figure 437, ANY sub-query
SUB-QUERY CHECK EQUIVALENT COLUMN FUNCTION
================ ============================
> ANY(sub-qurey) > MINIMUM(sub-query results)
< ANY(sub-query) < MAXIMUM(sub-query results)
> ALL(sub-query) > MAXIMUM(sub-query results)
< ALL(sub-query) < MINIMUM(sub-query results)
Figure 438, ANY and ALL vs. column functions
SELECT * ANSWER SUB-Q
FROM TABLE1 ======= RESLT
WHERE T1A = ALL T1A T1B +---+
(SELECT T2B --- -- |T2B|
FROM TABLE2 A AA |---|
WHERE T2B >= 'A'); |A |
|A |
+---+
Figure 439, ALL sub-query, with non-empty sub-query result
SELECT * ANSWER SUB-Q
FROM TABLE1 ======= RESLT
WHERE T1A = ALL T1A T1B +---+
(SELECT T2B --- -- |T2B|
FROM TABLE2 A AA |---|
WHERE T2B >= 'X'); B BB +---+
C CC
Figure 440, ALL sub-query, with empty sub-query result
SELECT * ANSWER
FROM TABLE1 ======
WHERE T1A = ALL 0 rows
(SELECT T2B
FROM TABLE2 SQ-#1 SQ-#2 TABLE1 TABLE2
WHERE T2B >= 'X') RESLT RESLT +-------+ +-----------+
AND 0 <> +---+ +---+ |T1A|T1B| |T2A|T2B|T2C|
(SELECT COUNT(*) |T2B| |(*)| |---|---| |---|---|---|
FROM TABLE2 |---| |---| |A |AA | |A |A |A |
WHERE T2B >= 'X'); +---+ |0 | |B |BB | |B |A | - |
+---+ |C |CC | +-----------+
+-------+ "-" = null
Figure 441, ALL sub-query, with extra check for empty set
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE EXISTS T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT * --- -- |---|---| |---|---|---|
FROM TABLE2); A AA |A |AA | |A |A |A |
B BB |B |BB | |B |A | - |
C CC |C |CC | +-----------+
+-------+ "-" = null
Figure 442, EXISTS sub-query, always returns a match
SELECT * ANSWER
FROM TABLE1 ======
WHERE EXISTS 0 rows
(SELECT *
FROM TABLE2
WHERE T2B >= 'X');
Figure 443, EXISTS sub-query, always returns a non-match
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE EXISTS T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT COUNT(*) --- -- |---|---| |---|---|---|
FROM TABLE2 A AA |A |AA | |A |A |A |
WHERE T2B = 'X'); B BB |B |BB | |B |A | - |
C CC |C |CC | +-----------+
+-------+ "-" = null
Figure 444, EXISTS sub-query, always returns a match
SELECT * ANSWERS TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE NOT EXISTS T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT * --- --- |---|---| |---|---|---|
FROM TABLE2 A AA |A |AA | |A |A |A |
WHERE T2C >= 'A' |B |BB | |B |A | - |
AND T2C <> T1A); |C |CC | +-----------+
+-------+ "-" = null
SELECT *
FROM TABLE1
WHERE T1A = ALL
(SELECT T2C
FROM TABLE2
WHERE T2C >= 'A');
Figure 445, NOT EXISTS vs. ALL, ignore nulls, find match
SELECT * ANSWERS TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE NOT EXISTS T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT * --- --- |---|---| |---|---|---|
FROM TABLE2 A AA |A |AA | |A |A |A |
WHERE T2C >= 'X' B BB |B |BB | |B |A | - |
AND T2C <> T1A); C CC |C |CC | +-----------+
+-------+ "-" = null
SELECT *
FROM TABLE1
WHERE T1A = ALL
(SELECT T2C
FROM TABLE2
WHERE T2C >= 'X');
Figure 446, NOT EXISTS vs. ALL, ignore nulls, no match
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE NOT EXISTS T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT * --- --- |---|---| |---|---|---|
FROM TABLE2 A AA |A |AA | |A |A |A |
WHERE T2C <> T1A); |B |BB | |B |A | - |
|C |CC | +-----------+
+-------+ "-" = null
SELECT * ANSWER
FROM TABLE1 =======
WHERE T1A = ALL no rows
(SELECT T2C
FROM TABLE2);
Figure 447, NOT EXISTS vs. ALL, process nulls
SELECT * SELECT * SELECT *
FROM TABLE2 FROM TABLE2 FROM TABLE2
WHERE T2C <> 'A'; WHERE T2C <> 'B'; WHERE T2C <> 'C';
ANSWER ANSWER ANSWER
=========== =========== ===========
T2A T2B T2C T2A T2B T2C T2A T2B T2C
--- --- --- --- --- --- --- --- ---
no rows A A A A A A
Figure 448, List of values in T2C <> T1A value
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE NOT EXISTS no rows |T1A|T1B| |T2A|T2B|T2C|
(SELECT * |---|---| |---|---|---|
FROM TABLE2 |A |AA | |A |A |A |
WHERE T2C <> T1A) |B |BB | |B |A | - |
OR T2C IS NULL); |C |CC | +-----------+
+-------+ "-" = null
Figure 449, NOT EXISTS - same as ALL
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE T1A IN T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT T2A --- -- |---|---| |---|---|---|
FROM TABLE2); A AA |A |AA | |A |A |A |
B BB |B |BB | |B |A | - |
|C |CC | +-----------+
+-------+ "-" = null
Figure 450, IN sub-query example, two matches
SELECT * ANSWER
FROM TABLE1 ======
WHERE T1A IN 0 rows
(SELECT T2A
FROM TABLE2
WHERE T2A >= 'X');
Figure 451, IN sub-query example, no matches
SELECT * ANSWERS TABLE2
FROM TABLE2 =========== +-----------+
WHERE T2C IN T2A T2B T2C |T2A|T2B|T2C|
(SELECT T2C --- --- --- |---|---|---|
FROM TABLE2); A A A |A |A |A |
|B |A | - |
SELECT * +-----------+
FROM TABLE2 "-" = null
WHERE T2C = ANY
(SELECT T2C
FROM TABLE2);
Figure 452, IN and = ANY sub-query examples, with nulls
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ====== +-------+ +-----------+
WHERE T1A NOT IN 0 rows |T1A|T1B| |T2A|T2B|T2C|
(SELECT T2C |---|---| |---|---|---|
FROM TABLE2); |A |AA | |A |A |A |
|B |BB | |B |A | - |
|C |CC | +-----------+
+-------+ "-" = null
Figure 453, NOT IN sub-query example, no matches
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE T1A NOT IN T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT T2C --- -- |---|---| |---|---|---|
FROM TABLE2 B BB |A |AA | |A |A |A |
WHERE T2C IS NOT NULL); C CC |B |BB | |B |A | - |
|C |CC | +-----------+
+-------+ "-" = null
Figure 454, NOT IN sub-query example, matches
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE NOT EXISTS T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT * --- -- |---|---| |---|---|---|
FROM TABLE2 B BB |A |AA | |A |A |A |
WHERE T1A = T2C); C CC |B |BB | |B |A | - |
|C |CC | +-----------+
+-------+ "-" = null
Figure 455, NOT EXISTS sub-query example, matches
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE T1A IN T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT T2A --- -- |---|---| |---|---|---|
FROM TABLE2); A AA |A |AA | |A |A |A |
B BB |B |BB | |B |A | - |
|C |CC | +-----------+
+-------+ "-" = null
Figure 456, Uncorrelated sub-query
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE T1A IN T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT T2A --- -- |---|---| |---|---|---|
FROM TABLE2 A AA |A |AA | |A |A |A |
WHERE T1A = T2A); B BB |B |BB | |B |A | - |
|C |CC | +-----------+
+-------+ "-" = null
Figure 457, Correlated sub-query
SELECT * ANSWER TABLE2
FROM TABLE2 AA =========== +-----------+
WHERE EXISTS T2A T2B T2C |T2A|T2B|T2C|
(SELECT * --- --- --- |---|---|---|
FROM TABLE2 BB A A A |A |A |A |
WHERE AA.T2A = BB.T2B); |B |A | - |
+-----------+
"-" = null
Figure 458,Correlated sub-query, with correlation names
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ====== +-------+ +-----------+
WHERE (T1A,T1B) IN 0 rows |T1A|T1B| |T2A|T2B|T2C|
(SELECT T2A, T2B |---|---| |---|---|---|
FROM TABLE2); |A |AA | |A |A |A |
|B |BB | |B |A | - |
|C |CC | +-----------+
+-------+ "-" = null
SELECT * ANSWER
FROM TABLE1 ======
WHERE EXISTS 0 rows
(SELECT *
FROM TABLE2
WHERE T1A = T2A
AND T1B = T2B);
Figure 459, Multi-field sub-queries, equal checks
SELECT * ANSWER TABLE1 TABLE2
FROM TABLE1 ======= +-------+ +-----------+
WHERE EXISTS T1A T1B |T1A|T1B| |T2A|T2B|T2C|
(SELECT * --- -- |---|---| |---|---|---|
FROM TABLE2 A AA |A |AA | |A |A |A |
WHERE T1A = T2A B BB |B |BB | |B |A | - |
AND T1B >= T2B); |C |CC | +-----------+
+-------+ "-" = null
Figure 460, Multi-field sub-query, with non-equal check
SELECT EMPNO ANSWER
,LASTNAME =========================
,SALARY EMPNO LASTNAME SALARY
FROM EMPLOYEE ------ --------- --------
WHERE SALARY > 000010 HAAS 52750.00
(SELECT MAX(SALARY) 000110 LUCCHESSI 46500.00
FROM EMPLOYEE
WHERE EMPNO NOT IN
(SELECT EMPNO
FROM EMP_ACT
WHERE PROJNO LIKE 'MA%'))
ORDER BY 1;
Figure 461, Nested Sub-Queries
SELECT COUNT(*) AS #ROWS ANSWER
,MAX(DEPTNO) AS MAXDPT =============
FROM DEPARTMENT #ROWS MAXDEPT
WHERE DEPTNAME LIKE 'Z%' ----- -------
ORDER BY 1; 0 null
Figure 462, Getting a null value from a not null field
SELECT * TABLE1 TABLE2
FROM TABLE1 T1 +-------+ +-----------+
WHERE 0 = |T1A|T1B| |T2A|T2B|T2C|
(SELECT COUNT(*) |---|---| |---|---|---|
FROM TABLE2 T2 |A |AA | |A |A |A |
WHERE T1.T1A = T2.T2C); |B |BB | |B |A | - |
|C |CC | +-----------+
SELECT * +-------+ "-" = null
FROM TABLE1 T1
WHERE NOT EXISTS
(SELECT * ANSWER
FROM TABLE2 T2 =======
WHERE T1.T1A = T2.T2C); T1A T1B
--- ---
SELECT * B BB
FROM TABLE1 C CC
WHERE T1A NOT IN
(SELECT T2C
FROM TABLE2
WHERE T2C IS NOT NULL);
Figure 463, Sub-queries, true if none match
SELECT T1.* ANSWER
FROM TABLE1 T1 =======
LEFT OUTER JOIN T1A T1B
TABLE2 T2 --- ---
ON T1.T1A = T2.T2C B BB
WHERE T2.T2C IS NULL; C CC
Figure 464, Outer join, true if none match
SELECT * TABLE1 TABLE2
FROM TABLE1 T1 +-------+ +-----------+
WHERE EXISTS |T1A|T1B| |T2A|T2B|T2C|
(SELECT * |---|---| |---|---|---|
FROM TABLE2 T2 |A |AA | |A |A | - |
WHERE T1.T1A = T2.T2C); |B |BB | |A | - | - |
|C |CC | +-----------+
SELECT * +-------+ null value
FROM TABLE1 T1
WHERE 1 <=
(SELECT COUNT(*) ANSWER
FROM TABLE2 T2 =======
WHERE T1.T1A = T2.T2C); T1A T1B
--- ---
SELECT * A AA
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 465, Sub-queries, true if any match
WITH T2 AS TABLE1 TABLE2
(SELECT DISTINCT T2C +-------+ +-----------+
FROM TABLE2 |T1A|T1B| |T2A|T2B|T2C|
) |---|---| |---|---|---|
SELECT T1.* |A |AA | |A |A |A |
FROM TABLE1 T1 |B |BB | |B |A | - |
,T2 |C |CC | +-----------+
WHERE T1.T1A = T2.T2C; +-------+ "-" = null
SELECT T1.*
FROM TABLE1 T1 ANSWER
,(SELECT DISTINCT T2C =======
FROM TABLE2 T1A T1B
)AS T2 --- ---
WHERE T1.T1A = T2.T2C; A AA
SELECT T1.*
FROM TABLE1 T1
INNER JOIN
(SELECT DISTINCT T2C
FROM TABLE2
) AS T2
ON T1.T1A = T2.T2C;
Figure 466, Joins, true if any match
SELECT * TABLE1 TABLE2
FROM TABLE1 T1 +-------+ +-----------+
WHERE 10 = |T1A|T1B| |T2A|T2B|T2C|
(SELECT COUNT(*) |---|---| |---|---|---|
FROM TABLE2 T2 |A |AA | |A |A |A |
WHERE T1.T1A = T2.T2B); |B |BB | |B |A | - |
|C |CC | +-----------+
SELECT * +-------+ "-" = null
FROM TABLE1
WHERE EXISTS
(SELECT T2B ANSWER
FROM TABLE2 ======
WHERE T1A = T2B 0 rows
GROUP BY T2B
HAVING COUNT(*) = 10);
SELECT *
FROM TABLE1
WHERE T1A IN
(SELECT T2B
FROM TABLE2
GROUP BY T2B
HAVING COUNT(*) = 10);
Figure 467, Sub-queries, true if ten match (1 of 2)
SELECT * ANSWER
FROM TABLE1 ======
WHERE (T1A,10) IN 0 rows
(SELECT T2B, COUNT(*)
FROM TABLE2
GROUP BY T2B);
Figure 468, Sub-queries, true if ten match (2 of 2)
WITH T2 AS TABLE1 TABLE2
(SELECT T2B +-------+ +-----------+
FROM TABLE2 |T1A|T1B| |T2A|T2B|T2C|
GROUP BY T2B |---|---| |---|---|---|
HAVING COUNT(*) = 10 |A |AA | |A |A |A |
) |B |BB | |B |A | - |
SELECT T1.* |C |CC | +-----------+
FROM TABLE1 T1 +-------+ "-" = null
,T2
WHERE T1.T1A = T2.T2B;
ANSWER
SELECT T1.* ======
FROM TABLE1 T1 0 rows
,(SELECT T2B
FROM TABLE2
GROUP BY T2B
HAVING COUNT(*) = 10
) AS T2
WHERE T1.T1A = 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 469, Joins, true if ten match
SELECT * TABLE1 TABLE2
FROM TABLE1 +-------+ +-----------+
WHERE T1A = ALL |T1A|T1B| |T2A|T2B|T2C|
(SELECT T2B |---|---| |---|---|---|
FROM TABLE2); |A |AA | |A |A |A |
|B |BB | |B |A | - |
SELECT * |C |CC | +-----------+
FROM TABLE1 +-------+ "-" = null
WHERE NOT EXISTS
(SELECT * ANSWER
FROM TABLE2 =======
WHERE T1A <> T2B); T1A T1B
--- ---
A AA
Figure 470, Sub-queries, true if all match, find rows
SELECT * ANSWER
FROM TABLE1 =======
WHERE T1A = ALL T1A T1B
(SELECT T2B --- ---
FROM TABLE2 A AA
WHERE T2B >= 'X'); B BB
C CC
SELECT *
FROM TABLE1
WHERE NOT EXISTS
(SELECT *
FROM TABLE2
WHERE T1A <> T2B
AND T2B >= 'X');
Figure 471, Sub-queries, true if all match, empty set
SELECT * TABLE1 TABLE2
FROM TABLE1 +-------+ +-----------+
WHERE T1A = ALL |T1A|T1B| |T2A|T2B|T2C|
(SELECT T2B |---|---| |---|---|---|
FROM TABLE2 |A |AA | |A |A |A |
WHERE T2B >= 'X') |B |BB | |B |A | - |
AND 0 <> |C |CC | +-----------+
(SELECT COUNT(*) +-------+ "-" = null
FROM TABLE2
WHERE T2B >= 'X'); ANSWER
======
SELECT * 0 rows
FROM TABLE1
WHERE T1A IN
(SELECT MAX(T2B)
FROM TABLE2
WHERE T2B >= 'X'
HAVING COUNT(DISTINCT T2B) = 1);
Figure 472, Sub-queries, true if all match, and at least one value found
R1 R1 R1 R1 R1 R1
UNION UNION INTERSECT INTERSECT EXCEPT EXCEPT
R2 ALL R2 ALL R2 ALL
R1 R2 R2 R2 R2
-- -- ----- ----- --------- ----- ------ ------
A A A A A A E A
A A B A B A C
A B C A C B C
B B D A B E
B B E A C
C C B
C D B
C B
E B
B
C
C
C
C
D
E
Figure 473, Examples of Union, Except, and Intersect
Figure 474, Union, Except, and Intersect syntax
CREATE VIEW R1 (R1)
AS VALUES ('A'),('A'),('A'),('B'),('B'),('C'),('C'),('C'),('E');
CREATE VIEW R2 (R2)
AS VALUES ('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 475, Query sample views
SELECT R1 R1 R2 UNION UNION ALL
FROM R1 -- -- ===== =========
UNION A A A A
SELECT R2 A A B A
FROM R2 A B C A
ORDER BY 1; B B D A
B B E A
C C B
SELECT R1 C D B
FROM R1 C B
UNION ALL E B
SELECT R2 B
FROM R2 C
ORDER BY 1; C
C
C
D
E
Figure 476, Union and Union All SQL
SELECT R1 R1 R2 INTERSECT INTERSECT ALL
FROM R1 -- -- ========= =============
INTERSECT A A A A
SELECT R2 A A B A
FROM R2 A B C B
ORDER BY 1; B B B
B B C
SELECT R1 C C
FROM R1 C D
INTERSECT ALL C
SELECT R2 E
FROM R2
ORDER BY 1;
Figure 477, Intersect and Intersect All SQL
SELECT R1 R1 R1
FROM R1 EXCEPT EXCEPT ALL
EXCEPT R1 R2 R2 R2
SELECT R2 -- -- ===== ==========
FROM R2 A A E A
ORDER BY 1; A A C
A B C
SELECT R1 B B E
FROM R1 B B
EXCEPT ALL C C
SELECT R2 C D
FROM R2 C
ORDER BY 1; E
Figure 478, Except and Except All SQL (R1 on top)
SELECT R2 R2 R2
FROM R2 EXCEPT EXCEPT ALL
EXCEPT R1 R2 R1 R1
SELECT R1 -- -- ===== ==========
FROM R1 A A D B
ORDER BY 1; A A D
A B
SELECT R2 B B
FROM R2 B B
EXCEPT ALL C C
SELECT R1 C D
FROM R1 C
ORDER BY 1; E
Figure 479, Except and Except All SQL (R2 on top)
SELECT R1 (SELECT R1 SELECT R1 R1 R2
FROM R1 FROM R1 FROM R1 -- --
UNION UNION UNION A A
SELECT R2 SELECT R2 (SELECT R2 A A
FROM R2 FROM R2 FROM R2 A B
EXCEPT )EXCEPT EXCEPT B B
SELECT R2 SELECT R2 SELECT R2 B B
FROM R2 FROM R2 FROM R2 C C
ORDER BY 1; ORDER BY 1; )ORDER BY 1; C D
C
E
ANSWER ANSWER ANSWER
====== ====== ======
E E A
B
C
E
Figure 480, Use of parenthesis in Union
CREATE VIEW VVVV (COL1, COL2) AS
SELECT COL1, COL2 FROM TABLE1
UNION ALL
SELECT COL1, COL3 FROM TABLE2
EXCEPT
SELECT COL1, COL1 FROM TABLE1;
Figure 481, View containing Union All
SELECT *
FROM VVVV
WHERE COL2 > 'BB';
Figure 482, Select from view that contains Union All
CREATE TABLE FRED.STAFF_SUMMARY AS
(SELECT DEPT
,COUNT(*) AS COUNT_ROWS
,SUM(ID) AS SUM_ID
FROM FRED.STAFF
GROUP BY DEPT
)DATA INITIALLY DEFERRED REFRESH IMMEDIATE
Figure 483, Sample Summary Table DDL
ORIGINAL QUERY OPTIMIZED QUERY
============== =================================
SELECT DEPT SELECT Q1.DEPT AS "DEPT"
,AVG(ID) ,Q1.SUM_ID / Q1.COUNT_ROWS
FROM FRED.STAFF FROM FRED.STAFF_SUMMARY AS Q1
GROUP BY DEPT
Figure 484, Original and Optimized queries
Figure 485, Summary Table DDL, Syntax Diagram
CREATE SUMMARY TABLE STAFF_COPY AS
(SELECT *
FROM STAFF)
DEFINITION ONLY;
Figure 486, Definition-Only Summary Table DDL - simple SQL
CREATE TABLE STAFF_COPY LIKE STAFF;
Figure 487, Create copy of table using LIKE syntax
CREATE SUMMARY TABLE STAFF_SUBSET AS
(SELECT S1.ID
,S1.DEPT
,S1.COMM / 12 AS MONTY_COMM
,(SELECT MAX(S2.SALARY)
FROM STAFF S2
WHERE S2.DEPT = S1.DEPT)
AS MAX_SALARY
FROM STAFF S1
WHERE S1.ID > 10
AND S1.COMM >
(SELECT MIN(COMM)
FROM STAFF))
DEFINITION ONLY
Figure 488, Definition-Only Summary Table DDL - complex SQL
CREATE TABLE STAFF_NAMES AS
(SELECT NAME
,COUNT(*) AS COUNT_ROWS
,SUM(SALARY) AS SUM_SALARY
,AVG(SALARY) AS AVG_SALARY
,MAX(SALARY) AS MAX_SALARY
,MIN(SALARY) AS MIN_SALARY
,STDDEV(SALARY) AS STD_SALARY
,VARIANCE(SALARY) AS VAR_SALARY
,CURRENT TIMESTAMP AS LAST_CHANGE
FROM STAFF
WHERE TRANSLATE(NAME) LIKE '%A%'
AND SALARY > 10000
GROUP BY NAME
HAVING COUNT(*) = 1)
DATA INITIALLY DEFERRED REFRESH DEFERRED
Figure 489, Refresh Deferred Summary 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 490, Refresh Immediate Summary 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 491, Query that uses summary 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 492, Query that uses summary table (2 of 3)
SELECT #EMPS
,DEC(SUM(SUM_SAL),9,2) AS SAL_SAL
,SMALLINT(COUNT(*)) AS #DEPTS
FROM (SELECT EMP.WORKDEPT
,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 493, Query that uses summary table (3 of 3)
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 494, Query that doesn't use summary 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 495, Query that doesn't use summary table (2 of 2)
REFRESH TABLE EMP_SUMMARY;
COMMIT;
SET INTEGRITY FOR EMP_SUMMARY IMMEDIATE CHECKED;
COMMIT;
Figure 496, Summary table refresh commands
CREATE TABLE DEPT_EMP_SUMMARY AS
(SELECT EMP.WORKDEPT
,DPT.DEPTNAME
,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
,DEPARTMENT DPT
WHERE DPT.DEPTNO = EMP.WORKDEPT
GROUP BY EMP.WORKDEPT
,DPT.DEPTNAME
)DATA INITIALLY DEFERRED REFRESH IMMEDIATE;
Figure 497, Multi-table Summary 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 498, Query that uses summary table
SELECT Q2.$C0 AS "DEPTNAME"
,Q2.$C1 AS "DEPTNO"
,Q2.$C2 AS "AVG_SAL"
,Q2.$C3 AS "#EMPS"
FROM (SELECT Q1.DEPTNAME AS $C0
,Q1.WORKDEPT AS $C1
,DEC((Q1.SUM_SALARY / Q1.NUM_SALARY),7,2) AS $C2
,SMALLINT(Q1.NUM_ROWS) AS $C3
FROM DEPT_EMP_SUMMARY AS Q1
WHERE (Q1.DEPTNAME LIKE '%S%')
AND (4000 < Q1.SUM_COMM)
)AS Q2
ORDER BY Q2.$C2 DESC;
Figure 499, DB2 generated query to use summary table
CREATE TABLE DPT_EMP_ACT_SUMRY AS
(SELECT EMP.WORKDEPT
,DPT.DEPTNAME
,EMP.EMPNO
,EMP.FIRSTNME
,SUM(ACT.EMPTIME) AS SUM_TIME
,COUNT(ACT.EMPTIME) AS NUM_TIME
,COUNT(*) AS NUM_ROWS
FROM DEPARTMENT DPT
,EMPLOYEE EMP
,EMP_ACT ACT
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 500, Three-table Summary 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 501, Query that uses summary 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 502, DB2 generated query to use summary 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 503, Indexes for DPT_EMP_ACT_SUMRY summary 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 504, 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 505, Sample query that uses NUM_ROWS index
SOURCE TABLE SUMMARY TABLE
============================== ==============================
CREATE TABLE FRED.STAFF CREATE TABLE FRED.STAFF_DEPT
(ID SMALLINT NOT NULL (DEPT SMALLINT
,NAME VARCHAR(9) ,COUNT_ROWS SMALLINT
,DEPT SMALLINT ,SUM_SALARY DECIMAL(9,2)
,JOB CHAR(5) ,AVG_SALARY DECIMAL(7,2)
,YEARS SMALLINT ,MAX_SALARY DECIMAL(7,2)
,SALARY DECIMAL(7,2) ,MIN_SALARY DECIMAL(7,2)
,COMM DECIMAL(7,2) ,STD_SALARY DECIMAL(7,2)
,PRIMARY KEY (ID)) ,VAR_SALARY DOUBLE
,LAST_CHANGE TIMESTAMP)
Figure 506, Source and Summary table DDL
CREATE TRIGGER FRED.STAFF_INS
AFTER INSERT ON FRED.STAFF
REFERENCING NEW AS NNN
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
-----------------------------------------
--- DELETE OLD DEPT ROW ---
-----------------------------------------
DELETE
FROM FRED.STAFF_DEPT
WHERE DEPT = NNN.DEPT
OR (DEPT IS NULL
AND NNN.DEPT IS NULL);
-----------------------------------------
--- INSERT NEW DEPT ROW ---
-----------------------------------------
INSERT
INTO FRED.STAFF_DEPT
SELECT DEPT
,COUNT(*) AS COUNT_ROWS
,SUM(SALARY) AS SUM_SALARY
,AVG(SALARY) AS AVG_SALARY
Figure 507, INSERT Trigger, part 1 of 2
,MAX(SALARY) AS MAX_SALARY
,MIN(SALARY) AS MIN_SALARY
,STDDEV(SALARY) AS STD_SALARY
,VARIANCE(SALARY) AS VAR_SALARY
,CURRENT TIMESTAMP AS LAST_CHANGE
FROM FRED.STAFF
WHERE DEPT = NNN.DEPT
OR (DEPT IS NULL
AND NNN.DEPT IS NULL)
GROUP BY DEPT;
END
Figure 508, INSERT Trigger, part 2 of 2
CREATE TRIGGER FRED.STAFF_UPD
AFTER
UPDATE OF SALARY, DEPT, COMM ON FRED.STAFF
REFERENCING OLD AS OOO
NEW AS NNN
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
-----------------------------------------
--- DELETE OLD DEPT ROW(S) ---
-----------------------------------------
DELETE
FROM FRED.STAFF_DEPT
WHERE DEPT = NNN.DEPT
OR DEPT = OOO.DEPT
OR (DEPT IS NULL
AND (NNN.DEPT IS NULL
OR OOO.DEPT IS NULL));
-----------------------------------------
--- INSERT NEW DEPT ROW(S) ---
-----------------------------------------
INSERT
INTO FRED.STAFF_DEPT
SELECT DEPT
,COUNT(*) AS COUNT_ROWS
,SUM(SALARY) AS SUM_SALARY
,AVG(SALARY) AS AVG_SALARY
,MAX(SALARY) AS MAX_SALARY
,MIN(SALARY) AS MIN_SALARY
,STDDEV(SALARY) AS STD_SALARY
,VARIANCE(SALARY) AS VAR_SALARY
,CURRENT TIMESTAMP AS LAST_CHANGE
FROM FRED.STAFF
WHERE DEPT = NNN.DEPT
OR DEPT = OOO.DEPT
OR (DEPT IS NULL
AND (NNN.DEPT IS NULL
OR OOO.DEPT IS NULL))
GROUP BY DEPT;
END
Figure 509, UPDATE Trigger
CREATE TRIGGER FRED.STAFF_DEL
AFTER
DELETE ON FRED.STAFF
REFERENCING OLD AS OOO
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
-----------------------------------------
--- DELETE OLD DEPT ROW ---
-----------------------------------------
Figure 510, DELETE Trigger, part 1 of 2
DELETE
FROM FRED.STAFF_DEPT
WHERE DEPT = OOO.DEPT
OR (DEPT IS NULL
AND OOO.DEPT IS NULL);
-----------------------------------------
--- INSERT NEW DEPT ROW ---
-----------------------------------------
INSERT
INTO FRED.STAFF_DEPT
SELECT DEPT
,COUNT(*) AS COUNT_ROWS
,SUM(SALARY) AS SUM_SALARY
,AVG(SALARY) AS AVG_SALARY
,MAX(SALARY) AS MAX_SALARY
,MIN(SALARY) AS MIN_SALARY
,STDDEV(SALARY) AS STD_SALARY
,VARIANCE(SALARY) AS VAR_SALARY
,CURRENT TIMESTAMP AS LAST_CHANGE
FROM FRED.STAFF
WHERE DEPT = OOO.DEPT
OR (DEPT IS NULL
AND OOO.DEPT IS NULL)
GROUP BY DEPT;
END
Figure 511, DELETE Trigger, part 2 of 2
INSERT
INTO FRED.STAFF_DEPT
SELECT DEPT
,COUNT(*) AS COUNT_ROWS
,SUM(SALARY) AS SUM_SALARY
,AVG(SALARY) AS AVG_SALARY
,MAX(SALARY) AS MAX_SALARY
,MIN(SALARY) AS MIN_SALARY
,STDDEV(SALARY) AS STD_SALARY
,VARIANCE(SALARY) AS VAR_SALARY
,CURRENT TIMESTAMP AS LAST_CHANGE
FROM FRED.STAFF
GROUP BY DEPT;
Figure 512, Initial population of STAFF_DATA table
SOURCE TABLE SUMMARY TABLE
============================== ====================================
CREATE TABLE FRED.STAFF CREATE TABLE FRED.STAFF_DEPT
(ID SMALLINT NOT NULL (DEPT SMALLINT NOT NULL
,NAME VARCHAR(9) ,COUNT_ROWS SMALLINT NOT NULL
,DEPT SMALLINT NOT NULL ,SUM_SALARY DECIMAL(9,2) NOT NULL
,JOB CHAR(5) ,AVG_SALARY DECIMAL(7,2) NOT NULL
,YEARS SMALLINT ,MAX_SALARY DECIMAL(7,2) NOT NULL
,SALARY DECIMAL(7,2) NOT NULL ,MIN_SALARY DECIMAL(7,2) NOT NULL
,COMM DECIMAL(7,2) ,#ROWS_CHANGED INTEGER NOT NULL
,PRIMARY KEY (ID)) ,#CHANGING_SQL INTEGER NOT NULL
,LAST_CHANGE TIMESTAMP NOT NULL
,CREATE_DEPT TIMESTAMP NOT NULL
,PRIMARY KEY (DEPT))
Figure 513, Source and Summary table DDL
CREATE TRIGGER FRED.STAFF_INS
AFTER INSERT ON FRED.STAFF
REFERENCING NEW AS NNN
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
-----------------------------------------
--- INSERT IF NEW DEPT ---
-----------------------------------------
INSERT
INTO FRED.STAFF_DEPT
SELECT NNN.DEPT
,CAST(0 AS SMALLINT) AS COUNT_ROWS
,CAST(0 AS SMALLINT) AS SUM_SALARY
,CAST(0 AS SMALLINT) AS AVG_SALARY
,NNN.SALARY AS MAX_SALARY
,NNN.SALARY AS MIN_SALARY
,CAST(0 AS INTEGER) AS #ROWS_CHANGED
,CAST(1 AS INTEGER) AS #CHANGING_SQL
,CURRENT TIMESTAMP AS LAST_CHANGE
,CURRENT TIMESTAMP AS CREATE_DEPT
FROM FRED.STAFF
WHERE ID = NNN.ID
AND NNN.DEPT NOT IN
(SELECT DEPT
FROM FRED.STAFF_DEPT);
-----------------------------------------
--- UPDATE DEPT ROW, INCREMENT ---
-----------------------------------------
UPDATE FRED.STAFF_DEPT
SET COUNT_ROWS = COUNT_ROWS + 1
,SUM_SALARY = SUM_SALARY + NNN.SALARY
,AVG_SALARY =(SUM_SALARY + NNN.SALARY)
/(COUNT_ROWS + 1)
,MAX_SALARY = CASE
WHEN NNN.SALARY <= MAX_SALARY
THEN MAX_SALARY
ELSE NNN.SALARY
END
,MIN_SALARY = CASE
WHEN NNN.SALARY >= MIN_SALARY
THEN MIN_SALARY
ELSE NNN.SALARY
END
,#ROWS_CHANGED = #ROWS_CHANGED + 1
,#CHANGING_SQL = CASE
WHEN LAST_CHANGE = CURRENT TIMESTAMP
THEN #CHANGING_SQL
ELSE #CHANGING_SQL + 1
END
,LAST_CHANGE = CURRENT TIMESTAMP
WHERE DEPT = NNN.DEPT;
END
Figure 514, INSERT Trigger
CREATE TRIGGER FRED.STAFF_UPD
AFTER UPDATE OF SALARY, DEPT, COMM ON FRED.STAFF
REFERENCING OLD AS OOO
NEW AS NNN
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
-----------------------------------------
--- INSERT IF NEW DEPT ---
-----------------------------------------
INSERT
INTO FRED.STAFF_DEPT
SELECT NNN.DEPT
,CAST(0 AS SMALLINT) AS COUNT_ROWS
,CAST(0 AS SMALLINT) AS SUM_SALARY
,CAST(0 AS SMALLINT) AS AVG_SALARY
,NNN.SALARY AS MAX_SALARY
,NNN.SALARY AS MIN_SALARY
,CAST(0 AS INTEGER) AS #ROWS_CHANGED
,CAST(1 AS INTEGER) AS #CHANGING_SQL
,CURRENT TIMESTAMP AS LAST_CHANGE
,CURRENT TIMESTAMP AS CREATE_DEPT
Figure 515, UPDATE Trigger, Part 1 of 3
FROM FRED.STAFF
WHERE ID = NNN.ID
AND NNN.DEPT NOT IN
(SELECT DEPT
FROM FRED.STAFF_DEPT);
-----------------------------------------
--- DELETE IF LAST ROW IN DEPT ---
-----------------------------------------
DELETE
FROM FRED.STAFF_DEPT
WHERE NNN.DEPT <> OOO.DEPT
AND DEPT = OOO.DEPT
AND COUNT_ROWS = 1;
-----------------------------------------
--- UPDATE DEPT, WHEN NOT CHANGED ---
-----------------------------------------
UPDATE FRED.STAFF_DEPT
SET SUM_SALARY = SUM_SALARY + NNN.SALARY - OOO.SALARY
,AVG_SALARY =(SUM_SALARY + NNN.SALARY - OOO.SALARY)
/ COUNT_ROWS
,MAX_SALARY = CASE
WHEN NNN.SALARY >= MAX_SALARY
THEN NNN.SALARY
ELSE (SELECT MAX(SALARY)
FROM FRED.STAFF
WHERE DEPT = NNN.DEPT)
END
,MIN_SALARY = CASE
WHEN NNN.SALARY <= MIN_SALARY
THEN NNN.SALARY
ELSE (SELECT MIN(SALARY)
FROM FRED.STAFF
WHERE DEPT = NNN.DEPT)
END
,#ROWS_CHANGED = #ROWS_CHANGED + 1
,#CHANGING_SQL = CASE
WHEN LAST_CHANGE = CURRENT TIMESTAMP
THEN #CHANGING_SQL
ELSE #CHANGING_SQL + 1
END
,LAST_CHANGE = CURRENT TIMESTAMP
WHERE NNN.DEPT = OOO.DEPT
AND NNN.DEPT = DEPT;
-----------------------------------------
--- UPDATE NEW, WHEN DEPT CHANGED ---
-----------------------------------------
UPDATE FRED.STAFF_DEPT
SET COUNT_ROWS = COUNT_ROWS + 1
,SUM_SALARY = SUM_SALARY + NNN.SALARY
,AVG_SALARY =(SUM_SALARY + NNN.SALARY)
/(COUNT_ROWS + 1)
,MAX_SALARY = CASE
WHEN NNN.SALARY <= MAX_SALARY
THEN MAX_SALARY
ELSE NNN.SALARY
END
,MIN_SALARY = CASE
WHEN NNN.SALARY >= MIN_SALARY
THEN MIN_SALARY
ELSE NNN.SALARY
END
,#ROWS_CHANGED = #ROWS_CHANGED + 1
,#CHANGING_SQL = CASE
WHEN LAST_CHANGE = CURRENT TIMESTAMP
THEN #CHANGING_SQL
ELSE #CHANGING_SQL + 1
Figure 516, UPDATE Trigger, Part 2 of 3
END
,LAST_CHANGE = CURRENT TIMESTAMP
WHERE NNN.DEPT <> OOO.DEPT
AND NNN.DEPT = DEPT;
-----------------------------------------
--- UPDATE OLD, WHEN DEPT CHANGED ---
-----------------------------------------
UPDATE FRED.STAFF_DEPT
SET COUNT_ROWS = COUNT_ROWS - 1
,SUM_SALARY = SUM_SALARY - OOO.SALARY
,AVG_SALARY = (SUM_SALARY - OOO.SALARY)
/(COUNT_ROWS - 1)
,MAX_SALARY = CASE
WHEN OOO.SALARY < MAX_SALARY
THEN MAX_SALARY
ELSE (SELECT COALESCE(MAX(SALARY),0)
FROM FRED.STAFF
WHERE DEPT = OOO.DEPT)
END
,MIN_SALARY = CASE
WHEN OOO.SALARY > MIN_SALARY
THEN MIN_SALARY
ELSE (SELECT COALESCE(MIN(SALARY),0)
FROM FRED.STAFF
WHERE DEPT = OOO.DEPT)
END
,#ROWS_CHANGED = #ROWS_CHANGED + 1
,#CHANGING_SQL = CASE
WHEN LAST_CHANGE = CURRENT TIMESTAMP
THEN #CHANGING_SQL
ELSE #CHANGING_SQL + 1
END
,LAST_CHANGE = CURRENT TIMESTAMP
WHERE NNN.DEPT <> OOO.DEPT
AND OOO.DEPT = DEPT;
END
Figure 517, UPDATE Trigger, Part 3 of 3
CREATE TRIGGER FRED.STAFF_DEL
AFTER DELETE ON FRED.STAFF
REFERENCING OLD AS OOO
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
-----------------------------------------
--- DELETE IF LAST ROW IN DEPT ---
-----------------------------------------
DELETE
FROM FRED.STAFF_DEPT
WHERE DEPT = OOO.DEPT
AND COUNT_ROWS = 1;
Figure 518, DELETE Trigger, part 1 of 2
-----------------------------------------
--- UPDATE OLD DEPT ROW, DECREMENT ---
-----------------------------------------
UPDATE FRED.STAFF_DEPT
SET COUNT_ROWS = COUNT_ROWS - 1
,SUM_SALARY = SUM_SALARY - OOO.SALARY
,AVG_SALARY = (SUM_SALARY - OOO.SALARY)
/(COUNT_ROWS - 1)
,MAX_SALARY = CASE
WHEN OOO.SALARY < MAX_SALARY
THEN MAX_SALARY
ELSE (SELECT COALESCE(MAX(SALARY),0)
FROM FRED.STAFF
WHERE DEPT = OOO.DEPT)
END
,MIN_SALARY = CASE
WHEN OOO.SALARY > MIN_SALARY
THEN MIN_SALARY
ELSE (SELECT COALESCE(MIN(SALARY),0)
FROM FRED.STAFF
WHERE DEPT = OOO.DEPT)
END
,#ROWS_CHANGED = #ROWS_CHANGED + 1
,#CHANGING_SQL = CASE
WHEN LAST_CHANGE = CURRENT TIMESTAMP
THEN #CHANGING_SQL
ELSE #CHANGING_SQL + 1
END
,LAST_CHANGE = CURRENT TIMESTAMP
WHERE OOO.DEPT = DEPT;
END
Figure 519, DELETE Trigger, part 2 of 2
Figure 520, Identity Column syntax
CREATE TABLE INVOICE_DATA
(INVOICE# INTEGER NOT NULL
GENERATED ALWAYS AS IDENTITY
(START WITH 100
,INCREMENT BY 1
,NO CACHE)
,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 521, Identity column, definition
INSERT INTO INVOICE_DATA
VALUES (DEFAULT,'2001-11-22','ABC',123,100,10);
INSERT INTO INVOICE_DATA
(SALE_DATE,CUSTOMER_ID,PRODUCT_ID,QUANTITY,PRICE)
VALUES ('2001-11-23','DEF',123,100,10);
Figure 522, Invoice table, sample inserts
INVOICE# SALE_DATE CUSTOMER_ID PRODUCT_ID QUANTITY PRICE
-------- ---------- ----------- ---------- -------- -----
100 11/22/2001 ABC 123 100 10.00
101 11/23/2001 DEF 123 100 10.00
Figure 523, Invoice table, after inserts
ALTER TABLE INVOICE_DATA
ALTER COLUMN INVOICE# RESTART WITH 1000;
Figure 524, Invoice table, restart identity column value
INSERT INTO INVOICE_DATA
VALUES (DEFAULT,'2001-11-24','XXX',123,100,10)
,(DEFAULT,'2001-11-25','YYY',123,100,10);
Figure 525, Invoice table, more sample inserts
INVOICE# SALE_DATE CUSTOMER_ID PRODUCT_ID QUANTITY PRICE
-------- ---------- ----------- ---------- -------- -----
100 11/22/2001 ABC 123 100 10.00
101 11/23/2001 DEF 123 100 10.00
1000 11/24/2001 XXX 123 100 10.00
1001 11/25/2001 YYY 123 100 10.00
Figure 526, Invoice table, after second inserts
CREATE TABLE CUSTOMERS
(CUST# INTEGER NOT NULL
GENERATED BY DEFAULT AS IDENTITY (NO CACHE)
,CNAME CHAR(10) NOT NULL
,CTYPE CHAR(03) NOT NULL
,PRIMARY KEY (CUST#));
COMMIT;
INSERT INTO CUSTOMERS
VALUES (DEFAULT,'FRED','XXX');
SELECT * <<< ANSWER
FROM CUSTOMERS ===================
ORDER BY 1; CUST# CNAME CTYPE
----- ----- -----
ROLLBACK; 1 FRED XXX
INSERT INTO CUSTOMERS
VALUES (1,'FRED','XXX');
SELECT * <<< ANSWER
FROM CUSTOMERS ===================
ORDER BY 1; CUST# CNAME CTYPE
----- ----- -----
COMMIT; 1 FRED XXX
Figure 527, Overriding the default identity value
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 528, 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 529, 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 530, Sample inserts, roll your own sequence#
CREATE TABLE INVOICE_TABLE
(INVOICE# INTEGER NOT NULL
GENERATED ALWAYS AS IDENTITY
,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#));
COMMIT;
INSERT INTO INVOICE_TABLE
VALUES (DEFAULT,'2000-11-22','ABC',123,100,10);
WITH TEMP (ID) AS <<< ANSWER
(VALUES (IDENTITY_VAL_LOCAL())) ======
SELECT * ID
FROM TEMP; ----
1
COMMIT;
WITH TEMP (ID) AS <<< ANSWER
(VALUES (IDENTITY_VAL_LOCAL())) ======
SELECT * ID
FROM TEMP; ----
1
Figure 531, 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); ANSWER
==================
SELECT INVOICE# AS INV# INV# SALE_DATE ID
,SALE_DATE ---- ---------- --
,IDENTITY_VAL_LOCAL() AS ID 1 11/22/2000 2
FROM INVOICE_TABLE 2 11/23/2000 2
ORDER BY 1; 3 11/24/2000 2
COMMIT; 4 11/25/2000 2
Figure 532, IDENTITY_VAL_LOCAL function examples
SELECT INVOICE# AS INV# ANSWER
,SALE_DATE ==================
,IDENTITY_VAL_LOCAL() AS ID INV# SALE_DATE ID
FROM INVOICE_TABLE ---- ---------- --
WHERE ID = IDENTITY_VAL_LOCAL(); 2 11/23/2000 2
Figure 533, IDENTITY_VAL_LOCAL usage in SET statement
CREATE TABLE INVOICE_DATA
(INVOICE# INTEGER NOT NULL
GENERATED ALWAYS AS IDENTITY
(START WITH 100
,INCREMENT BY 1
,CACHE 5)
,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 534, Record multi-row inserts - data table
CREATE TABLE CURRENT_INVOICE
(INVOICE# INTEGER NOT NULL
,CURRENT_TS TIMESTAMP NOT NULL
,USERID VARCHAR(128) NOT NULL
,PRIMARY KEY (USERID, INVOICE#));
Figure 535, Record multi-row inserts - record table
--#SET DELIMITER !
CREATE TRIGGER INVOICE_INSERT
AFTER INSERT
ON INVOICE_DATA
REFERENCING NEW_TABLE AS NEW_ROWS
FOR EACH STATEMENT
MODE DB2SQL
BEGIN ATOMIC
DELETE
FROM CURRENT_INVOICE
WHERE USERID = USER;
INSERT
INTO CURRENT_INVOICE
SELECT INVOICE#
,CURRENT TIMESTAMP
,USER
FROM NEW_ROWS;
END!
--#SET DELIMITER ;
COMMIT;
Figure 536, Record multi-row inserts - record trigger
INSERT INTO INVOICE_DATA
(SALE_DATE,CUSTOMER_ID,PRODUCT_ID,QUANTITY,PRICE)
VALUES ('2000-11-23','DEF',123,100,10)
,('2000-11-23','XXX',123,100,10)
,('2000-11-23','ZZZ',123,100,10);
COMMIT;
SELECT MIN(INVOICE#) AS MIN_INV
,MAX(INVOICE#) AS MAX_INV
,COUNT(*) AS #ROWS ANSWER
,CURRENT_TS ================================
FROM CURRENT_INVOICE MIN_INV MAX_INV #ROWS CURRENT_TS
WHERE USERID = USER ------- ------- ----- ----------
GROUP BY CURRENT_TS; 101 103 3 2001-etc..
Figure 537, Record multi-row inserts - usage example
SELECT MIN(INVOICE#) AS MIN_INV
,MAX(INVOICE#) AS MAX_INV
,COUNT(*) AS #ROWS
,CURRENT_TS
FROM INVOICE_DATA
WHERE USERID = USER
AND CURRENT_TS >= ANY
(SELECT MAX(CURRENT_TS)
FROM INVOICE_DATA
WHERE USERID = USER)
GROUP BY CURRENT_TS;
Figure 538, Track multi-row inserts - by adding fields to data table
HIERARCHY AAA
+---------------+ |
|PKEY |CKEY |NUM| +-----+-----+
|-----|-----|---| | | |
|AAA |BBB | 1| BBB CCC DDD
|AAA |CCC | 5| | |
|AAA |DDD | 20| +-+ +-+--+
|CCC |EEE | 33| | | |
|DDD |EEE | 44| EEE FFF
|DDD |FFF | 5| |
|FFF |GGG | 5| |
+---------------+ GGG
Figure 539, Sample Table description - Recursion
WITH PARENT (PKEY, CKEY) AS ANSWER
(SELECT PKEY, CKEY ========= PROCESSING
FROM HIERARCHY PKEY CKEY SEQUENCE
WHERE PKEY = 'AAA' ---- ---- ==========
UNION ALL AAA BBB < 1st pass
SELECT C.PKEY, C.CKEY AAA CCC ""
FROM HIERARCHY C AAA DDD ""
,PARENT P CCC EEE < 2nd pass
WHERE P.CKEY = C.PKEY DDD EEE < 3rd pass
) DDD FFF ""
SELECT PKEY, CKEY FFF GGG < 4th pass
FROM PARENT;
Figure 540, SQL that does Recursion
Figure 541, 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 542, Sample Table DDL - Recursion
WITH PARENT (CKEY) AS ANSWER HIERARCHY
(SELECT CKEY ====== +---------------+
FROM HIERARCHY CKEY |PKEY |CKEY |NUM|
WHERE PKEY = 'AAA' ---- |-----|-----|---|
UNION ALL BBB |AAA |BBB | 1|
SELECT C.CKEY CCC |AAA |CCC | 5|
FROM HIERARCHY C DDD |AAA |DDD | 20|
,PARENT P EEE |CCC |EEE | 33|
WHERE P.CKEY = C.PKEY EEE |DDD |EEE | 44|
) FFF |DDD |FFF | 5|
SELECT CKEY GGG |FFF |GGG | 5|
FROM PARENT; +---------------+
WITH PARENT (CKEY) AS ANSWER HIERARCHY
(SELECT DISTINCT PKEY ====== +---------------+
FROM HIERARCHY CKEY |PKEY |CKEY |NUM|
WHERE PKEY = 'AAA' ---- |-----|-----|---|
UNION ALL AAA |AAA |BBB | 1|
SELECT C.CKEY BBB |AAA |CCC | 5|
FROM HIERARCHY C CCC |AAA |DDD | 20|
,PARENT P DDD |CCC |EEE | 33|
WHERE P.CKEY = C.PKEY EEE |DDD |EEE | 44|
) EEE |DDD |FFF | 5|
SELECT CKEY FFF |FFF |GGG | 5|
FROM PARENT; GGG +---------------+
Figure 544, List all children of AAA
WITH PARENT (CKEY) AS ANSWER HIERARCHY
(SELECT DISTINCT PKEY ====== +---------------+
FROM HIERARCHY CKEY |PKEY |CKEY |NUM|
WHERE PKEY = 'AAA' ---- |-----|-----|---|
UNION ALL AAA |AAA |BBB | 1|
SELECT C.CKEY BBB |AAA |CCC | 5|
FROM HIERARCHY C CCC |AAA |DDD | 20|
,PARENT P DDD |CCC |EEE | 33|
WHERE P.CKEY = C.PKEY EEE |DDD |EEE | 44|
) FFF |DDD |FFF | 5|
SELECT DISTINCT CKEY GGG |FFF |GGG | 5|
FROM PARENT; +---------------+
Figure 545, List distinct children of AAA
WITH PARENT (CKEY) AS ANSWER HIERARCHY
(SELECT DISTINCT PKEY ====== +---------------+
FROM HIERARCHY CKEY |PKEY |CKEY |NUM|
WHERE PKEY = 'AAA' ---- |-----|-----|---|
UNION ALL AAA |AAA |BBB | 1|
SELECT C.CKEY BBB |AAA |CCC | 5|
FROM HIERARCHY C CCC |AAA |DDD | 20|
,PARENT P DDD |CCC |EEE | 33|
WHERE P.CKEY = C.PKEY EEE |DDD |EEE | 44|
) FFF |DDD |FFF | 5|
,DISTINCT_PARENT (CKEY) AS GGG |FFF |GGG | 5|
(SELECT DISTINCT CKEY +---------------+
FROM PARENT
)
SELECT CKEY
FROM DISTINCT_PARENT;
Figure 546, List distinct children of AAA
WITH PARENT (CKEY, LVL) AS ANSWER AAA
(SELECT DISTINCT PKEY, 0 ======== |
FROM HIERARCHY CKEY LVL +-----+-----+
WHERE PKEY = 'AAA' ---- --- | | |
UNION ALL AAA 0 BBB CCC DDD
SELECT C.CKEY, P.LVL +1 BBB 1 | |
FROM HIERARCHY C CCC 1 +-+ +-+--+
,PARENT P DDD 1 | | |
WHERE P.CKEY = C.PKEY EEE 2 EEE FFF
) EEE 2 |
SELECT CKEY, LVL FFF 2 |
FROM PARENT; GGG 3 GGG
Figure 547, Show item level in hierarchy
WITH PARENT (CKEY, LVL) AS ANSWER HIERARCHY
(SELECT DISTINCT PKEY, 0 ======== +---------------+
FROM HIERARCHY CKEY LVL |PKEY |CKEY |NUM|
WHERE PKEY = 'AAA' ---- --- |-----|-----|---|
UNION ALL AAA 0 |AAA |BBB | 1|
SELECT C.CKEY, P.LVL +1 BBB 1 |AAA |CCC | 5|
FROM HIERARCHY C CCC 1 |AAA |DDD | 20|
,PARENT P DDD 1 |CCC |EEE | 33|
WHERE P.CKEY = C.PKEY EEE 2 |DDD |EEE | 44|
) EEE 2 |DDD |FFF | 5|
SELECT CKEY, LVL FFF 2 |FFF |GGG | 5|
FROM PARENT +---------------+
WHERE LVL < 3;
Figure 548, Select rows where LEVEL < 3
WITH PARENT (CKEY, LVL) AS ANSWER AAA
(SELECT DISTINCT PKEY, 0 ======== |
FROM HIERARCHY CKEY LVL +-----+-----+
WHERE PKEY = 'AAA' ---- --- | | |
UNION ALL AAA 0 BBB CCC DDD
SELECT C.CKEY, P.LVL +1 BBB 1 | |
FROM HIERARCHY C CCC 1 +-+ +-+--+
,PARENT P DDD 1 | | |
WHERE P.CKEY = C.PKEY EEE 2 EEE FFF
AND P.LVL+1 < 3 EEE 2 |
) FFF 2 |
SELECT CKEY, LVL GGG
FROM PARENT;
Figure 549, Select rows where LEVEL < 3
WITH PARENT (CKEY, LVL) AS ANSWER HIERARCHY
(SELECT DISTINCT PKEY, 0 ======== +---------------+
FROM HIERARCHY CKEY LVL |PKEY |CKEY |NUM|
WHERE PKEY = 'AAA' ---- --- |-----|-----|---|
UNION ALL EEE 2 |AAA |BBB | 1|
SELECT C.CKEY, P.LVL +1 EEE 2 |AAA |CCC | 5|
FROM HIERARCHY C FFF 2 |AAA |DDD | 20|
,PARENT P |CCC |EEE | 33|
WHERE P.CKEY = C.PKEY |DDD |EEE | 44|
AND P.LVL+1 < 3 |DDD |FFF | 5|
) |FFF |GGG | 5|
SELECT CKEY, LVL +---------------+
FROM PARENT
WHERE LVL = 2;
Figure 550, Select rows where LEVEL = 2
WITH TEMP1 (CKEY, LVL) AS ANSWER AAA
(SELECT DISTINCT PKEY, 1 ======== |
FROM HIERARCHY CKEY LVL +-----+-----+
WHERE PKEY = 'AAA' ---- --- | | |
UNION ALL GGG 4 BBB CCC DDD
SELECT C.CKEY, P.LVL +1 FFF 3 | |
FROM HIERARCHY C DDD 2 +-+ +-+--+
,TEMP1 P AAA 1 | | |
WHERE P.CKEY = C.PKEY EEE FFF
AND P.LVL < 4 |
) |
,TEMP2 (CKEY, LVL) AS GGG
(SELECT CKEY, LVL
FROM TEMP1
WHERE LVL = 4
UNION ALL
SELECT C.PKEY, D.LVL -1
FROM HIERARCHY C
,TEMP2 D
WHERE D.CKEY = C.CKEY
)
SELECT *
FROM TEMP2;
Figure 551, Find all values in paths that are at least four deep
WITH TEMP1 (N1) AS ANSWER
(SELECT ID ======
FROM STAFF N1
WHERE ID = 10 --
UNION ALL warn
SELECT N1 +10 10
FROM TEMP1 20
WHERE N1 < 50 30
) 40
SELECT * 50
FROM TEMP1;
Figure 552, Recursion - with warning message
WITH TEMP1 (N1) AS ANSWER
(SELECT INT(ID) ======
FROM STAFF N1
WHERE ID = 10 --
UNION ALL 10
SELECT N1 +10 20
FROM TEMP1 30
WHERE N1 < 50 40
) 50
SELECT *
FROM TEMP1;
Figure 553, Recursion - without warning message
DIVERGENT CONVERGENT RECURSIVE BALANCED UNBALANCED
========= ========== ========= ======== ==========
AAA AAA AAA<--+ AAA AAA
| | | | | |
+-+-+ +-+-+ +-+-+ | +-+-+ +-+-+
| | | | | | | | | | |
BBB CCC BBB CCC BBB CCC>+ BBB CCC BBB CCC
| | | | | | |
+-+-+ +-+-+-+ +-+-+ | +---+ +-+-+
| | | | | | | | | | |
DDD EEE DDD EEE DDD EEE DDD EEE FFF DDD EEE
Figure 554, Hierarchy Flavours
OBJECTS_RELATES AAA
+---------------------+ |
|KEYO |PKEY |NUM|PRICE| +-----+-----+
|-----|-----|---|-----| | | |
|AAA | | | $10| BBB CCC DDD
|BBB |AAA | 1| $21| |
|CCC |AAA | 5| $23| +--+--+
|DDD |AAA | 20| $25| | |
|EEE |DDD | 44| $33| EEE FFF
|FFF |DDD | 5| $34| |
|GGG |FFF | 5| $44| |
+---------------------+ GGG
Figure 555, Divergent Hierarchy - Table and Layout
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 556, Convergent Hierarchy - Tables and Layout
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 |AAA | 99| EEE FFF
|FFF | $34| |DDD |FFF | 5| |
|GGG | $44| |DDD |EEE | 44| |
+-----------+ |FFF |GGG | 5| GGG
+---------------+
Figure 557, Recursive Hierarchy - Tables and Layout
AAA << Balanced Hierarchy AAA
| Unbalanced Hierarchy >> |
+-----+-----+ +---+----+
| | | | | |
BBB CCC DDD | CCC DDD
| | | | | |
| | +-+-+ | +-+ +-+-+
| | | | | | | |
EEE FFF GGG HHH FFF GGG HHH
|
|
III
Figure 558, 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 559, Recursive Hierarchy - Sample Table and Layout
CREATE TABLE TROUBLE
(PKEY CHAR(03) NOT NULL
,CKEY CHAR(03) NOT NULL
,CONSTRAINT TBX1 PRIMARY KEY(PKEY, CKEY)
,CONSTRAINT TBC1 CHECK (PKEY <> CKEY)
,CONSTRAINT TBC2 CHECK (LOCATE('>',PKEY)=0)
,CONSTRAINT TBC3 CHECK (LOCATE('>',CKEY)=0));
CREATE UNIQUE INDEX TBLE_X1 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 560, Sample Table DDL - Recursive Hierarchy
WITH PARENT (CKEY, LVL) AS ANSWER TROUBLE
(SELECT DISTINCT PKEY, 0 ======== +---------+
FROM TROUBLE CKEY LVL |PKEY|CKEY|
WHERE PKEY = 'AAA' ---- --- |----|----|
UNION ALL AAA 0 |AAA |BBB |
SELECT C.CKEY, P.LVL +1 BBB 1 |AAA |CCC |
FROM TROUBLE C CCC 1 |AAA |DDD |
,PARENT P DDD 1 |CCC |EEE |
WHERE P.CKEY = C.PKEY EEE 2 |DDD |AAA |
AND P.LVL+1 < 4 AAA 2 |DDD |FFF |
) EEE 2 |DDD |EEE |
SELECT CKEY, LVL FFF 2 |FFF |GGG |
FROM PARENT; BBB 3 +---------+
CCC 3
DDD 3
GGG 3
Figure 561, Stop Recursive SQL after "n" levels
WITH PARENT (CKEY, LVL) AS ANSWER
(SELECT DISTINCT PKEY, 0 ============
FROM TROUBLE CKEY LVL NUM
WHERE PKEY = 'AAA' ---- --- ---
UNION ALL AAA 0 2
SELECT C.CKEY, P.LVL +1 BBB 1 2
FROM TROUBLE C CCC 1 2
,PARENT P DDD 1 2
WHERE P.CKEY = C.PKEY EEE 2 2
AND P.LVL+1 < 4 AAA 2 1
) GGG 3 1
,NO_DUPS (CKEY, LVL, NUM) AS
(SELECT CKEY, MIN(LVL), COUNT(*)
FROM PARENT
GROUP BY CKEY
)
SELECT CKEY, LVL, NUM
FROM NO_DUPS; TROUBLE
+---------+ AAA <------+
|PKEY|CKEY| | |
|----|----| +-----+-----+ |
|AAA |BBB | | | | |
|AAA |CCC | BBB CCC DDD>-+
|AAA |DDD | | |
|CCC |EEE | +-+ +-+--+
This row ===> |DDD |AAA | | | |
points back to |DDD |FFF | EEE FFF
the hierarchy |DDD |EEE | |
parent. |FFF |GGG | |
+---------+ GGG
Figure 562, Stop Recursive SQL after "n" levels, Remove duplicates
WITH PARENT (CKEY,LVL,PATH,LOC) AS ANSWER
(SELECT DISTINCT PKEY, 0 ===========================
,VARCHAR(PKEY,20) CKEY LVL PATH LOC
,0 ---- --- -------------- ---
FROM TROUBLE AAA 0 AAA 0
WHERE PKEY = 'AAA' BBB 1 AAA>BBB 0
UNION ALL CCC 1 AAA>CCC 0
SELECT C.CKEY, P.LVL +1 DDD 1 AAA>DDD 0
,P.PATH||'>'||C.CKEY EEE 2 AAA>CCC>EEE 0
,LOCATE(C.CKEY||'>',P.PATH) AAA 2 AAA>DDD>AAA 1
FROM TROUBLE C EEE 2 AAA>DDD>EEE 0
,PARENT P FFF 2 AAA>DDD>FFF 0
WHERE P.CKEY = C.PKEY BBB 3 AAA>DDD>AAA>BBB 0
AND P.LVL+1 < 4 CCC 3 AAA>DDD>AAA>CCC 0
) DDD 3 AAA>DDD>AAA>DDD 5
SELECT CKEY, LVL, PATH, LOC GGG 3 AAA>DDD>FFF>GGG 0
FROM PARENT;
Figure 563, Stop Recursive SQL after "n" levels, Show data paths
WITH PARENT (CKEY,LVL,PATH) AS ANSWER
(SELECT DISTINCT PKEY, 0 ========================
,VARCHAR(PKEY,20) CKEY LVL PATH
FROM TROUBLE ---- --- --------------
WHERE PKEY = 'AAA' AAA 0 AAA
UNION ALL BBB 1 AAA>BBB
SELECT C.CKEY, P.LVL +1 CCC 1 AAA>CCC
,P.PATH||'>'||C.CKEY DDD 1 AAA>DDD
FROM TROUBLE C EEE 2 AAA>CCC>EEE
,PARENT P EEE 2 AAA>DDD>EEE
WHERE P.CKEY = C.PKEY FFF 2 AAA>DDD>FFF
AND LOCATE(C.CKEY||'>',P.PATH)=0 GGG 3 AAA>DDD>FFF>GGG
)
SELECT CKEY, LVL, PATH
FROM PARENT;
Figure 564, Recursive SQL, Ignore data loops (don't retrieve)
WITH PARENT (CKEY, LVL, PATH) AS ANSWER
(SELECT DISTINCT PKEY, 0 ========================
,VARCHAR(PKEY,20) CKEY LVL PATH
FROM TROUBLE ---- --- ---------------
WHERE PKEY = 'AAA' AAA 0 AAA
UNION ALL BBB 1 AAA>BBB
SELECT CASE CCC 1 AAA>CCC
WHEN LOCATE(C.CKEY||'>',P.PATH)>0 DDD 1 AAA>DDD
THEN CHAR('>>>',3) EEE 2 AAA>CCC>EEE
ELSE C.CKEY >>> 2 AAA>DDD>AAA
END EEE 2 AAA>DDD>EEE
,P.LVL +1 FFF 2 AAA>DDD>FFF
,P.PATH||'>'||C.CKEY GGG 3 AAA>DDD>FFF>GGG
FROM TROUBLE C
,PARENT P
WHERE P.CKEY = C.PKEY
)
SELECT CKEY, LVL, PATH
FROM PARENT;
Figure 565, Recursive SQL, Mark data loops
WITH PARENT (CKEY, PATH) AS ANSWER TROUBLE
(SELECT DISTINCT PKEY ============ +---------+
,VARCHAR(PKEY,20) PATH |PKEY|CKEY|
FROM TROUBLE ------------ |----|----|
WHERE PKEY = 'AAA' AAA>DDD>AAA |AAA |BBB |
UNION ALL |AAA |CCC |
SELECT CASE |AAA |DDD |
WHEN LOCATE(C.CKEY||'>',P.PATH)>0 |CCC |EEE |
THEN CHAR('>>>',3) |DDD |AAA |
ELSE C.CKEY |DDD |FFF |
END |DDD |EEE |
,P.PATH||'>'||C.CKEY |FFF |GGG |
FROM TROUBLE C +---------+
,PARENT P
WHERE P.CKEY = C.PKEY
)
SELECT PATH
FROM PARENT
WHERE CKEY = '>>>';
Figure 566, Recursive SQL, List data loops
WITH PARENT ANSWER TROUBLE
(CKEY, LVL, PATH) AS ====== +---------+
(SELECT DISTINCT CKEY... |PKEY|CKEY|
PKEY ---- |----|----|
,0 |AAA |BBB |
,VARCHAR(PKEY,20) |AAA |CCC |
FROM TROUBLE |AAA |DDD |
WHERE PKEY = 'AAA' |CCC |EEE |
UNION ALL |DDD |AAA |
SELECT CASE |DDD |FFF |
WHEN LOCATE(C.CKEY||'>',P.PATH) > 0 |DDD |EEE |
THEN RAISE_ERROR('70001', |FFF |GGG |
'ERROR: LOOP IN DATABASE FOUND') +---------+
ELSE C.CKEY
END
,P.LVL +1
,P.PATH||'>'||C.CKEY
FROM TROUBLE C
,PARENT P
WHERE P.CKEY = C.PKEY
)
SELECT CKEY, LVL, PATH
FROM PARENT;
Figure 567, Recursive SQL, Set error if data loop found
WITH PARENT ANSWER TROUBLE
(CKEY, LVL, PATH) AS ====== +---------+
(SELECT DISTINCT CKEY... |PKEY|CKEY|
PKEY ---- |----|----|
,0 AAA |AAA |BBB |
,VARCHAR(PKEY,20) BBB |AAA |CCC |
FROM TROUBLE CCC |AAA |DDD |
WHERE PKEY = 'AAA' DDD |CCC |EEE |
UNION ALL EEE |DDD |AAA |
SELECT CASE |DDD |FFF |
WHEN LOCATE(C.CKEY||'>',P.PATH) > 0 |DDD |EEE |
THEN CHAR('>>>',3) |FFF |GGG |
ELSE C.CKEY +---------+
END
,P.LVL +1
,P.PATH||'>'||C.CKEY
FROM TROUBLE C
,PARENT P
WHERE P.CKEY = C.PKEY
)
SELECT CASE
WHEN LOCATE('>',CKEY) > 0
THEN RAISE_ERROR('70001',
'ERROR: LOOP IN DATABASE FOUND')
ELSE CKEY
END AS CKEY
,LVL, PATH
FROM PARENT;
Figure 568, Recursive SQL, Set error if data loop found
WITH TEMP (COL1) AS ANSWER
(VALUES (SMALLINT(1)) ======
UNION ALL COL1
SELECT COL1 + 1 ----
FROM TEMP) 1
SELECT COL1 2
FROM TEMP 3
FETCH FIRST 5 ROWS ONLY; 4
5
Figure 569, Stop recursion using FETCH FIRST n ROWS ONLY, works
WITH TEMP (COL1) AS ANSWER
(VALUES (SMALLINT(1)) ======
UNION ALL error
SELECT COL1 + 1
FROM TEMP)
SELECT COL1
FROM TEMP
ORDER BY COL1
FETCH FIRST 5 ROWS ONLY;
Figure 570, Stop recursion using FETCH FIRST n ROWS ONLY, not work
HIERARCHY#1 EXPLODED#1
AAA +--------------------+ +-------------+
| |KEYY|PKEY|DATA | |PKEY|CKEY|LVL|
BBB |----|----|----------| |----|----|---|
| |AAA |AAA |SOME DATA | |AAA |AAA | 0|
+-----+ |BBB |AAA |MORE DATA | |AAA |BBB | 1|
| | |CCC |BBB |MORE JUNK | |AAA |CCC | 2|
CCC EEE |DDD |CCC |MORE JUNK | |AAA |DDD | 3|
| |EEE |BBB |JUNK DATA | |AAA |EEE | 2|
DDD +--------------------+ |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 571, Data Hierarchy, with normalized and exploded representations
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 572, 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 573, 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 574, 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 575, Trigger to maintain exploded table after delete in hierarchy table
SELECT *
FROM EXPLODED#1
WHERE PKEY = :host-var
ORDER BY PKEY
,CKEY
,LVL;
Figure 576, 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 577, 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 578, 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 579, 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 580, 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 581, 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 EXPLODED#2
WHERE 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 582, 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 583, Trigger to run after update of PKEY in hierarchy table (part 2 of 2)
SELECT *
FROM EXPLODED#2
WHERE PKEY = :host-var
ORDER BY PKEY
,CKEY
,LVL;
Figure 584, Querying the exploded table
WITH TEMP1 (COL1) AS ANSWER
(VALUES 0 ======
) COL1
SELECT * ----
FROM TEMP1; 0
Figure 585, Select one row/column using VALUES
WITH TEMP1 (COL1, COL2, COL3) AS ANSWER
(VALUES ( 0, 'AA', 0.00) ==============
,( 1, 'BB', 1.11) COL1 COL2 COL3
,( 2, 'CC', 2.22) ---- ---- ----
) 0 AA 0.00
SELECT * 1 BB 1.11
FROM TEMP1; 2 CC 2.22
Figure 586, Select multiple rows/columns using VALUES
WITH TEMP1 (COL1) AS ANSWER
(VALUES 0 ======
UNION ALL COL1
SELECT COL1 + 1 ----
FROM TEMP1 0
WHERE COL1 + 1 < 100 1
) 2
SELECT * 3
FROM TEMP1; etc
Figure 587, Use recursion to get list of one hundred numbers
WITH TEMP1 (C0,C1,C2,C3,C4,C5,C6,C7,C8,C9) AS
(VALUES ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
UNION ALL
SELECT C0+10, C1+10, C2+10, C3+10, C4+10
,C5+10, C6+10, C7+10, C8+10, C9+10
FROM TEMP1
WHERE C0+10 < 100
)
SELECT *
FROM TEMP1;
Figure 588, Recursive SQL used to make an array of numbers (1 of 2)
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9
---- ---- ---- ---- ---- ---- ---- ---- ---- ----
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99
Figure 589, Answer - array of numbers made using recursive SQL
WITH TEMP1 (C0) AS
(VALUES ( 0)
UNION ALL
SELECT C0+10
FROM TEMP1
WHERE C0+10 < 100
)
SELECT C0
,C0+1 AS C1, C0+2 AS C2, C0+3 AS C3, C0+4 AS C4, C0+5 AS C5
,C0+6 AS C6, C0+7 AS C7, C0+8 AS C8, C0+9 AS C9
FROM TEMP1;
Figure 590, Recursive SQL used to make an array of numbers (2 of 2)
WITH TEMP1 (DEGREE) AS
(VALUES SMALLINT(0)
UNION ALL
SELECT SMALLINT(DEGREE + 1)
FROM TEMP1
WHERE DEGREE < 89
)
SELECT DEGREE
,DEC(COS(RADIANS(DEGREE + 0.0)),4,3) AS POINT0
,DEC(COS(RADIANS(DEGREE + 0.1)),4,3) AS POINT1
,DEC(COS(RADIANS(DEGREE + 0.2)),4,3) AS POINT2
,DEC(COS(RADIANS(DEGREE + 0.3)),4,3) AS POINT3
,DEC(COS(RADIANS(DEGREE + 0.4)),4,3) AS POINT4
,DEC(COS(RADIANS(DEGREE + 0.5)),4,3) AS POINT5
,DEC(COS(RADIANS(DEGREE + 0.6)),4,3) AS POINT6
,DEC(COS(RADIANS(DEGREE + 0.7)),4,3) AS POINT7
,DEC(COS(RADIANS(DEGREE + 0.8)),4,3) AS POINT8
,DEC(COS(RADIANS(DEGREE + 0.9)),4,3) AS POINT9
FROM TEMP1;
Figure 591, SQL to make Cosine vs. Degree table
DEGREE POINT0 POINT1 POINT2 POINT3 POINT4 POINT5 POINT6 POINT7 etc....
------ ------ ------ ------ ------ ------ ------ ------ ------
0 1.000 0.999 0.999 0.999 0.999 0.999 0.999 0.999
1 1.000 0.999 0.999 0.999 0.999 0.999 0.999 0.999
2 0.999 0.999 0.999 0.999 0.999 0.999 0.999 0.999
3 0.999 0.999 0.999 0.999 0.999 0.999 0.998 0.998
4 0.998 0.998 0.998 0.998 0.998 0.998 0.998 0.997
5 0.997 0.997 0.997 0.997 0.997 0.996 0.996 0.996
6 0.994 0.994 0.994 0.993 0.993 0.993 0.993 0.993
7 0.992 0.992 0.992 0.991 0.991 0.991 0.991 0.990
8 0.990 0.990 0.989 0.989 0.989 0.989 0.988 0.988
.
.
88 0.052 0.050 0.048 0.047 0.045 0.043 0.041 0.040
89 0.034 0.033 0.031 0.029 0.027 0.026 0.024 0.022
Figure 592, Cosine vs. Degree SQL output
WITH TEMP1 (S1, R1) AS ANSWER
(VALUES (0, RAND(1)) ============
UNION ALL SEQ# RAN1
SELECT S1+1, RAND() ---- -----
FROM TEMP1 0 0.001
WHERE S1+1 < 5 1 0.563
) 2 0.193
SELECT SMALLINT(S1) AS SEQ# 3 0.808
,DECIMAL(R1,5,3) AS RAN1 4 0.585
FROM TEMP1;
Figure 593, Use RAND to create pseudo-random numbers
WITH TEMP1 (S1, R1) AS ANSWER
(VALUES (0, RAND(2)) ========================
UNION ALL SEQ# RAN2 RAN1 RAN3
SELECT S1+1, RAND() ---- ---- ------ ----
FROM TEMP1 0 13 0.0013 0
WHERE S1+1 < 5 1 8916 0.8916 8
) 2 7384 0.7384 7
SELECT SMALLINT(S1) AS SEQ# 3 5430 0.5430 5
,SMALLINT(R1*10000) AS RAN2 4 8998 0.8998 8
,DECIMAL(R1,6,4) AS RAN1
,SMALLINT(R1*10) AS RAN3
FROM TEMP1;
Figure 594, Make differing ranges of random numbers
WITH TEMP1 (S1, R1) AS ANSWER
(VALUES (0, RAND(2)) ===================
UNION ALL SEQ# RAN2 RAN3 RAN4
SELECT S1+1, RAND() ---- ---- ---- ----
FROM TEMP1 0 65 A 65
WHERE S1+1 < 5 1 88 X 88
) 2 84 T 84
SELECT SMALLINT(S1) AS SEQ# 3 79 O 79
,SMALLINT(R1*26+65) AS RAN2 4 88 X 88
,CHR(SMALLINT(R1*26+65)) AS RAN3
,CHAR(SMALLINT(R1*26)+65) AS RAN4
FROM TEMP1;
Figure 595, Converting RAND output from number to character
WITH TEMP1 (S1,R1,R2,R3,R4) AS ANSWER
(VALUES (0 ==============================
,RAND(2) S# RAN1 RAN2 RAN3 RAN4
,RAND()+(RAND()/1E5) -- ------ ------ ------ ------
,RAND()* RAND() 0 1373 169599 182618 215387
,RAND()* RAND()* RAND()) 1 326700 445273 539604 357592
UNION ALL 2 909848 981267 7140 81553
SELECT S1 + 1 3 454573 577320 309318 166436
,RAND() 4 875942 257823 207873 9628
,RAND()+(RAND()/1E5)
,RAND()* RAND()
,RAND()* RAND()* RAND()
FROM TEMP1
WHERE S1 + 1 < 5
)
SELECT SMALLINT(S1) AS S#
,INTEGER(R1*1E6) AS RAN1, INTEGER(R2*1E6) AS RAN2
,INTEGER(R3*1E6) AS RAN3, INTEGER(R4*1E6) AS RAN4
FROM TEMP1;
Figure 596, Create RAND data with different distributions
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# > 0)
,CONSTRAINT PE02 CHECK (LOCATE(' ',SOCSEC#) = 0)
,CONSTRAINT PE03 CHECK (LOCATE('-',SOCSEC#,1) = 4)
,CONSTRAINT PE04 CHECK (LOCATE('-',SOCSEC#,5) = 7)
,CONSTRAINT PE05 CHECK (JOB_FTN <> '')
,CONSTRAINT PE06 CHECK (DEPT BETWEEN 1 AND 99)
,CONSTRAINT PE07 CHECK (SALARY BETWEEN 0 AND 99999)
,CONSTRAINT PE08 CHECK (FST_NAME <> '')
,CONSTRAINT PE09 CHECK (LST_NAME <> '')
,CONSTRAINT PE10 CHECK (DATE_BN >= '1900-01-01' ));
COMMIT;
CREATE UNIQUE INDEX PEX2 ON PERSONNEL (SOCSEC#);
CREATE UNIQUE INDEX PEX3 ON PERSONNEL (DEPT, EMP#);
COMMIT;
Figure 597, 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
Figure 598, Production-like test table INSERT (part 1 of 2)
,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 599, Production-like test table INSERT (part 2 of 2)
EMP# SOCSEC# JOB_ DEPT SALARY DATE_BN F_NME L_NME
------ ----------- ---- ---- --------- ---------- --------- ---------
100000 484-10-9999 WKR 47 13.63 01/01/1979 Ammaef Mimytmbi
100001 449-38-9998 SEC 53 35758.87 04/10/1962 Ilojff Liiiemea
100002 979-90-9997 WKR 1 8155.23 01/03/1975 Xzacaa Zytaebma
100003 580-50-9993 WKR 31 16643.50 02/05/1971 Lpiedd Pimmeeat
100004 264-87-9994 WKR 21 962.87 01/01/1979 Wgfacc Geimteei
100005 661-84-9995 WKR 19 4648.38 01/02/1977 Wrebbc Rbiybeet
100006 554-53-9990 WKR 8 375.42 01/01/1979 Mobaaa Oiiaiaia
100007 482-23-9991 SEC 36 23170.09 03/07/1968 Emjgdd Mimtmamb
100008 536-41-9992 WKR 6 10514.11 02/03/1974 Jnbcaa Nieebayt
Figure 600, Production-like test table, Sample Output
CREATE TABLE STATS
(KEY1 SMALLINT NOT NULL CHECK(KEY1 >= 0)
,DAT1 SMALLINT NOT NULL CHECK(DAT1 >= 0)
,DAT2 SMALLINT NOT NULL CHECK(DAT2 >= 0)
,DAT3 SMALLINT NOT NULL CHECK(DAT3 >= 0)
,SEX CHAR(01) NOT NULL CHECK(SEX IN ('F','M'))
,CONSTRAINT STX1 PRIMARY KEY (KEY1) );
COMMIT;
CREATE INDEX STX2 ON STATS (DAT1);
COMMIT;
INSERT INTO STATS
WITH TEMP1 (K1,R1,R2) AS
(VALUES (0,RAND(1),RAND() )
UNION ALL
SELECT K1+1, RAND(), RAND()
FROM TEMP1
WHERE K1+1 < 1000
)
SELECT K1 AS KEY1
,INT(R1 * 32767) AS DAT1
,INT(R2 * 32767) AS DAT2
,INT(POWER(R2,2)*32767) AS DAT3
,CASE
WHEN R1+0.4 > 1 THEN 'M'
ELSE 'F'
END AS SEX
FROM TEMP1;
Figure 601, Sample table DDL - Statistical Analysis
Mean = sum(values)
---------------------
num-rows (not null)
Figure 602, Get the Mean - Formula
SELECT AVG(DAT1) ANSWER
FROM STATS; ======
16271
Figure 603, Get the Mean - SQL
SELECT DAT1 ANSWER
,COUNT(*) AS CNT =========
FROM STATS DAT1 CNT
GROUP BY DAT1 ----- ---
HAVING COUNT(*) >= ALL 28 2
(SELECT COUNT(*) 1626 2
FROM STATS 3093 2
GROUP BY DAT1) 4313 2
ORDER BY 1; etc..
Figure 604, Get the Mode - SQL
Avg Deviation = sum( absolute(value - mean))
----------------------------
num-rows (not null)
Figure 605, Get the Average Deviation - Formula
WITH MEAN (MEAN) AS ANSWER
(SELECT AVG(DAT1) ======
FROM STATS 8207
)
SELECT SUM(ABS(DAT1 - MEAN)) / COUNT(*)
FROM STATS
,MEAN;
Figure 606, Get the Average Deviation - SQL
WITH MEAN (MEAN) AS ANSWER
(SELECT AVG(DAT1) ======
FROM STATS 8207
)
SELECT AVG(ABS(DAT1 - MEAN))
FROM STATS
,MEAN;
Figure 607, Get the Average Deviation - SQL
Variance = sum( square( absolute(value - mean)))
-------------------------------------
num-rows (not null)
Figure 608, Get the Variance - Formula
SELECT VARIANCE(DAT1) ANSWER
,BIGINT(VARIANCE(DAT1)) ===============================
FROM STATS; 1 2
---------------------- --------
+8.93711402817241e+007 89371140
Figure 609, Get the Variance - SQL
Std Deviation = sqroot( sum( square( absolute(value - mean))))
----------------------------------------------
num-rows
Figure 610, Get the Standard Deviation - Formula
SELECT STDDEV(DAT1) ANSWER
,INTEGER(STDDEV(DAT1)) ===========================
FROM STATS; 1 2
---------------------- ----
+9.45363106333879e+003 9453
Figure 611, Get the Standard Deviation - SQL
*****
*** | ***
*** | ***
*** | ***
*** | | | ***
**** | | | ****
***** | 34% | 34% | *****
****** | 14% | | | 14% | ******
<<<--------------------------------------------------------------->>>
-2S -1S M +1S +2S
Figure 612, Normal distribution data divided into standard deviations
WITH STD_DV (NUM,M,M_N1,M_N2,M_P1,M_P2) AS ANSWER
(SELECT COUNT(*) * 1E0 =======================
,AVG(DAT1) SUB2 SUB1 ADD1 ADD1
,AVG(DAT1) -(1*(STDDEV(DAT1))) ----- ----- ----- -----
,AVG(DAT1) -(2*(STDDEV(DAT1))) 0.21 0.27 0.29 0.21
,AVG(DAT1) +(1*(STDDEV(DAT1)))
,AVG(DAT1) +(2*(STDDEV(DAT1)))
FROM STATS
)
SELECT DECIMAL(SUM(CASE
WHEN DAT1 BETWEEN M_N2 AND M_N1 THEN 1
ELSE 0
END) / AVG(NUM),3,2) AS SUB2
,DECIMAL(SUM(CASE
WHEN DAT1 BETWEEN M_N1 AND M THEN 1
ELSE 0
END) / AVG(NUM),3,2) AS SUB1
,DECIMAL(SUM(CASE
WHEN DAT1 BETWEEN M AND M_P1 THEN 1
ELSE 0
END) / AVG(NUM),3,2) AS ADD1
,DECIMAL(SUM(CASE
WHEN DAT1 BETWEEN M_P1 AND M_P2 THEN 1
ELSE 0
END) / AVG(NUM),3,2) AS ADD1
FROM STATS ,STD_DV;
Figure 613, See if data has normal data distribution
Std Error = Std-deviation
----------------
sqroot(num-rows)
Figure 614, Get the Standard Error - Formula
SELECT INT(STDDEV(DAT1) ANSWER
/SQRT(COUNT(*))) ======
FROM STATS; 298
Figure 615, Get the Standard Error - SQL
Pearsons PMC = sum((value1 - mean1) * (value2 - mean2))
----------------------------------------
num-rows * std-dev1 * std-dev2
Figure 616, Get the Pearson Product-Moment Coefficient - Formula
WITH DATA (M1,S1,M2,S2,M3,S3) AS ANSWER
(SELECT AVG(DAT1), STDDEV(DAT1) ============
,AVG(DAT2), STDDEV(DAT2) PP1-2 PP2-3
,AVG(DAT3), STDDEV(DAT3) ------ -----
FROM STATS -0.010 0.968
)
SELECT DEC(SUM(1E0 * (DAT1 - M1) * (DAT2 - M2))
/(COUNT(*) * AVG(S1) * AVG(S2)),4,3) AS "PP1-2"
,DEC(SUM(1E0 * (DAT2 - M2) * (DAT3 - M3))
/(COUNT(*) * AVG(S2) * AVG(S3)),4,3) AS "PP2-3"
FROM STATS,DATA;
Figure 617, Get the Pearson Product-Moment Coefficient - SQL
CREATE TABLE TIME_SERIES
(KYY CHAR(03) NOT NULL
,BGN_DT DATE NOT NULL
,END_DT DATE NOT NULL
,CONSTRAINT TSX1 PRIMARY KEY(KYY,BGN_DT)
,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 618, Sample Table DDL - Time Series
Figure 619, Overlapping Time-Series rows - Definition
SELECT KYY ANSWER
,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 620, Find overlapping rows in time-series
SELECT A.KYY TIME_SERIES
,A.BGN_DT +-------------------------+
,A.END_DT |KYY|BGN_DT |END_DT |
,B.BGN_DT |---|----------|----------|
,B.END_DT |AAA|1995-10-01|1995-10-04|
,DAYS(B.BGN_DT) - |AAA|1995-10-06|1995-10-06|
DAYS(A.END_DT) |AAA|1995-10-07|1995-10-07|
AS DIFF |AAA|1995-10-15|1995-10-19|
FROM TIME_SERIES A |BBB|1995-10-01|1995-10-01|
,TIME_SERIES B |BBB|1995-10-03|1995-10-03|
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 621, Find gap in Time-Series, SQL
KEYCOL BGN_DT END_DT BGN_DT END_DT DIFF
------ ---------- ---------- ---------- ---------- ----
AAA 10/01/1995 10/04/1995 10/06/1995 10/06/1995 2
AAA 10/07/1995 10/07/1995 10/15/1995 10/19/1995 8
BBB 10/01/1995 10/01/1995 10/03/1995 10/03/1995 2
Figure 622, Find gap in Time-Series, Answer
SELECT A.KYY TIME_SERIES
,A.END_DT + 1 DAY +-------------------------+
AS BGN_GAP |KYY|BGN_DT |END_DT |
,B.BGN_DT - 1 DAY |---|----------|----------|
AS END_GAP |AAA|1995-10-01|1995-10-04|
,(DAYS(B.BGN_DT) - |AAA|1995-10-06|1995-10-06|
DAYS(A.END_DT) - 1) |AAA|1995-10-07|1995-10-07|
AS GAP_SIZE |AAA|1995-10-15|1995-10-19|
FROM TIME_SERIES A |BBB|1995-10-01|1995-10-01|
,TIME_SERIES B |BBB|1995-10-03|1995-10-03|
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 623, Find gap in Time-Series, SQL
KEYCOL BGN_GAP END_GAP GAP_SIZE
------ ---------- ---------- --------
AAA 10/05/1995 10/05/1995 1
AAA 10/08/1995 10/14/1995 7
BBB 10/02/1995 10/02/1995 1
Figure 624, Find gap in Time-Series, Answer
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 10/05/1995 1
,GAP_DT + 1 DAY AAA 10/08/1995 7
,GSIZE - 1 AAA 10/09/1995 6
FROM TEMP AAA 10/10/1995 5
WHERE GSIZE > 1 AAA 10/11/1995 4
) AAA 10/12/1995 3
SELECT * AAA 10/13/1995 2
FROM TEMP AAA 10/14/1995 1
ORDER BY 1,2; BBB 10/02/1995 1
Figure 625, Show each day in Time-Series gap
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 626, Covert Character to Numeric - SQL
INPUT STRING COMPATIBLE FUNCTIONS
============ ==========================================
" 1234" DOUBLE, DECIMAL, INTEGER, SMALLINT, BIGINT
" 12.4" DOUBLE, DECIMAL
" 12E4" DOUBLE
Figure 627, Acceptable conversion values
WITH TEMP1 (C1) AS (VALUES ' 123','456 ',' 1 2',' 33%',NULL)
SELECT C1
,CHAR(RTRIM(LTRIM(C1)),4)
,CHAR(TRANSLATE(RTRIM(LTRIM(C1)),'$',' 0123456789'),4)
,CASE
WHEN TRANSLATE(RTRIM(LTRIM(C1)),'$',' 0123456789') = ''
THEN SMALLINT(C1)
ELSE SMALLINT(0)
END
FROM TEMP1;
Figure 628, Covert Character to Numeric (check input), SQL
C1 2 3 4
---- ---- ---- ------
123 123 123
456 456 456
1 2 1 2 $ 0
33% 33% % 0
- - - 0
Figure 629, Covert Character to Numeric (check input), Answer
WITH TEMP1 (C1) AS (VALUES '.123','4.6.',' 1.2',' 33.',NULL)
SELECT C1
,CHAR(RTRIM(LTRIM(C1)),4)
,CHAR(TRANSLATE(RTRIM(LTRIM(C1)),'$',' 0123456789'),4)
,CASE
WHEN LTRIM(TRANSLATE(RTRIM(LTRIM(C1)),'$',' 0123456789'))
= '' THEN DECIMAL(C1,7,3)
WHEN LTRIM(TRANSLATE(RTRIM(LTRIM(C1)),'$',' 0123456789'))
= '.' AND LTRIM(C1) <> '.' THEN DECIMAL(C1,7,3)
ELSE DECIMAL( 0,7,3)
END
FROM TEMP1;
Figure 630, Covert Character to Decimal (check input), SQL
C1 2 3 4
---- ---- ---- -------
.123 .123 . 0.123
4.6. 4.6. . . 0.000
1.2 1.2 . 1.200
33. 33. . 33.000
- - - 0.000
Figure 631, Covert Character to Decimal (check input), Answer
WITH TAB1(TS1) AS
(VALUES CAST('1998-11-22-03.44.55.123456' AS TIMESTAMP))
SELECT TS1 => 1998-11-22-03.44.55.123456
, HEX(TS1) => 19981122034455123456
, DEC(HEX(TS1),20) => 19981122034455123456.
,FLOAT(DEC(HEX(TS1),20)) => 1.99811220344551e+019
,REAL (DEC(HEX(TS1),20)) => 1.998112e+019
FROM TAB1;
Figure 632, Covert Timestamp to number
SELECT EMPNO
,FIRSTNME
,LASTNAME
,JOB
FROM EMPLOYEE
WHERE EMPNO < '000100'
ORDER BY EMPNO;
Figure 633, 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 634, Sample query with column control
WITH TEMP1 (COL1) AS (VALUES 12, 22, 33, 16, 0, 44, 15, 15)
SELECT COL1
,SUBSTR(TRANSLATE(CHAR(' ',50),'*',' '),1,COL1)
AS PRETTY_CHART
FROM TEMP1;
Figure 635, Make chart using SQL
COL1 PRETTY_CHART
---- --------------------------------------------------
12 ************
22 **********************
33 *********************************
16 ****************
0
44 ********************************************
15 ***************
15 ***************
Figure 636, Make charts using SQL, Answer
WITH TEMP1 (COL1) AS (VALUES 12, 22, 33, 16, 0, 66, 15, 15)
SELECT COL1
,CASE
WHEN COL1 < 48
THEN SUBSTR(TRANSLATE(CHAR(' ',50),'*',' '),1,COL1)
ELSE TRANSLATE(CHAR(' ',47),'*',' ')||'>>>'
END AS PRETTY_CHART
FROM TEMP1;
Figure 637, Make charts using SQL
COL1 PRETTY_CHART
---- --------------------------------------------------
12 ************
22 **********************
33 *********************************
16 ****************
0
66 ***********************************************>>>
15 ***************
15 ***************
Figure 638, Make charts using SQL, Answer
SELECT SEX ANSWER >> SEX NUM
,COUNT(*) AS NUM --- ---
FROM STATS F 595
GROUP BY SEX M 405
ORDER BY SEX;
Figure 639, Use GROUP BY to get counts
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 640, Use Common Table Expression to get counts
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 641, 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 642, Use CASE and SUM to get counts
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
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 643, 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 644, Multiple counts in one pass, Answer
SELECT YEARS ANSWER
,COUNT(*) AS #STAFF =============
FROM STAFF YEARS #STAFF
WHERE UCASE(NAME) LIKE '%E%' ----- ------
AND YEARS <= 5 1 1
GROUP BY YEARS; 4 2
5 3
Figure 645, Count staff joined per year
WITH LIST_YEARS (YEAR#) AS ANSWER
(VALUES (0),(1),(2),(3),(4),(5) ============
) YEARS #STAFF
SELECT YEAR# AS YEARS ----- ------
,COALESCE(#STFF,0) AS #STAFF 0 0
FROM LIST_YEARS 1 1
LEFT OUTER JOIN 2 0
(SELECT YEARS 3 0
,COUNT(*) AS #STFF 4 2
FROM STAFF 5 3
WHERE UCASE(NAME) LIKE '%E%'
AND YEARS <= 5
GROUP BY YEARS
)AS XXX
ON YEAR# = YEARS
ORDER BY 1;
Figure 646, Count staff joined per year, all years
WITH LIST_YEARS (YEAR#) AS ANSWER
(VALUES SMALLINT(0) ============
UNION ALL YEARS #STAFF
SELECT YEAR# + 1 ----- ------
FROM LIST_YEARS 0 0
WHERE YEAR# < 5) 1 1
SELECT YEAR# AS YEARS 2 0
,COALESCE(#STFF,0) AS #STAFF 3 0
FROM LIST_YEARS 4 2
LEFT OUTER JOIN 5 3
(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 647, Count staff joined per year, all years
WITH LIST_YEARS (YEAR#) AS ANSWER
(VALUES SMALLINT(0) ======
UNION ALL YEAR#
SELECT YEAR# + 1 -----
FROM LIST_YEARS 0
WHERE YEAR# < 5) 2
SELECT YEAR# 3
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 648, List years when no staff joined
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 649, 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 650, 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 A.DEPT = B.DEPT
AND A.NAME > B.NAME
AND A.NAME =
(SELECT MIN(C.NAME)
FROM STAFF C
WHERE C.DEPT = B.DEPT
AND C.NAME > B.NAME)
)
SELECT *
FROM TEMP1 D
WHERE W# =
(SELECT MAX(W#)
FROM TEMP1 E
WHERE D.DEPT = E.DEPT)
ORDER BY DEPT;
Figure 651, Denormalize Normalized Data - SQL
DEPT W# 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 652, Denormalize Normalized Data - Answer
WITH TEMP1 (N1) AS ANSWER
(VALUES (-0124),(+0000),(+0001) ===========
,(+0456),(+6789),(+9999)) N1 2
SELECT N1 ----- -----
,( ((N1/ 1)-(N1/ 10)*10) *1000) + -124 -4210
( ((N1/ 10)-(N1/ 100)*10) * 100) + 0 0
( ((N1/ 100)-(N1/ 1000)*10) * 10) + 1 1000
( ((N1/1000)-(N1/10000)*10) * 1) 456 6540
FROM TEMP1; 6789 9876
9999 9999
Figure 653, Reverse digits in four-byte integer field - assume leading zeros
WITH TEMP1 (N1) AS ANSWER
(VALUES (-0124),(+0000),(+0001) ===========
,(+0456),(+6789),(+9999)) N1 2
SELECT N1 ----- -----
,(( ((N1/ 1)-(N1/ 10)*10) *1000) + -124 -421
( ((N1/ 10)-(N1/ 100)*10) * 100) + 0 0
( ((N1/ 100)-(N1/ 1000)*10) * 10) + 1 1
( ((N1/1000)-(N1/10000)*10) * 1))/ 456 654
CASE 6789 9876
WHEN ABS(N1) < 10 THEN 1000 9999 9999
WHEN ABS(N1) < 100 THEN 100
WHEN ABS(N1) < 1000 THEN 10
ELSE 1
END
FROM TEMP1;
Figure 654, Reverse digits in four-byte integer field - assume no leading zeros
SELECT JOB ANSWER
,SUBSTR(JOB,8,1) || SUBSTR(JOB,7,1) =================
|| SUBSTR(JOB,6,1) || SUBSTR(JOB,5,1) JOB BOJ
|| SUBSTR(JOB,4,1) || SUBSTR(JOB,3,1) -------- --------
|| SUBSTR(JOB,2,1) || SUBSTR(JOB,1,1) ANALYST TSYLANA
AS BOJ CLERK KRELC
FROM EMPLOYEE DESIGNER RENGISED
GROUP BY JOB; FIELDREP PERDLEIF
MANAGER REGANAM
OPERATOR ROTAREPO
PRES SERP
SALESREP PERSELAS
Figure 655, Reverse characters - keep trailing blanks
SELECT JOB ANSWER
,CHAR(LTRIM( =================
SUBSTR(JOB,8,1) || SUBSTR(JOB,7,1) JOB BOJ
|| SUBSTR(JOB,6,1) || SUBSTR(JOB,5,1) -------- --------
|| SUBSTR(JOB,4,1) || SUBSTR(JOB,3,1) ANALYST TSYLANA
|| SUBSTR(JOB,2,1) || SUBSTR(JOB,1,1) CLERK KRELC
),8) AS BOJ DESIGNER RENGISED
FROM EMPLOYEE FIELDREP PERDLEIF
GROUP BY JOB; MANAGER REGANAM
OPERATOR ROTAREPO
PRES SERP
SALESREP PERSELAS
Figure 656, Reverse characters - discard trailing blanks
WITH TEMP (OLD_NAME, NEW_NAME, REST) AS ANSWER
(SELECT NAME =================
,SUBSTR(NAME,LENGTH(NAME)) OLD_NAME NEW_NAME
,SUBSTR(NAME,1,LENGTH(NAME)-1) -------- --------
FROM STAFF Hanes senaH
WHERE ID < 100 James semaJ
UNION ALL Koonitz ztinooK
SELECT OLD_NAME Marenghi ihgneraM
,NEW_NAME CONCAT O'Brien neirB'O
SUBSTR(REST,LENGTH(REST)) Pernal lanreP
,SUBSTR(REST,1,LENGTH(REST)-1) Quigley yelgiuQ
FROM TEMP Rothman namhtoR
WHERE LENGTH(REST) > 0 Sanders srednaS
)
SELECT OLD_NAME
,NEW_NAME
FROM TEMP
WHERE REST = ''
ORDER BY OLD_NAME;
Figure 657, Reverse character field using recursion
WITH TEMP (TXT) AS
(VALUES ('HAS TRAILING ZEROS 0000')
,('HAS 0 IN MIDDLE 0000')
,('HAS TEMP ~ CHAR 0000'))
SELECT TXT
,TRANSLATE(
TRANSLATE(
LTRIM(
RTRIM(
TRANSLATE(
TRANSLATE(TXT,'~',' ')
,' ','0')
)
)
,'0',' ')
,' ','~') AS TXT_STRIPPED
FROM TEMP
WHERE CASE LOCATE('~',TXT)
WHEN 0 THEN ''
ELSE RAISE_ERROR('80001','FOUND ~ YOU IDIOT!')
END = '';
ANSWER
===============================================
TXT TXT_STRIPPED
----------------------- -------------------
HAS TRAILING ZEROS 0000 HAS TRAILING ZEROS
HAS 0 IN MIDDLE 0000 HAS 0 IN MIDDLE
error 80001, "FOUND ~ YOU IDIOT!"
Figure 658, Stripping non-blank characters
SELECT NAME AS OLD_NAME ANSWER
,REPLACE(NAME,'e','') AS NEW_NAME ==================
FROM STAFF OLD_NAME NEW_NAME
WHERE ID < 50; -------- --------
Sanders Sandrs
Pernal Prnal
Marenghi Marnghi
O'Brien O'Brin
Figure 659, Strip characters from text
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 660, Run query for four seconds
WITH TEMP1 (C1,T1,T2) AS (VALUES ANSWER
('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 661, Timestamp comparison - Incorrect
WITH TEMP1 (C1,T1,T2) AS (VALUES ANSWER
('A' ======
,TIMESTAMP('1996-05-01-24.00.00.000000') C1
,TIMESTAMP('1996-05-02-00.00.00.000000') )) --
SELECT C1 A
FROM TEMP1
WHERE T1 + 0 MICROSECOND = T2 + 0 MICROSECOND;
Figure 662, Timestamp comparison - Correct
SELECT CREATOR ANSWER
FROM SYSIBM.SYSTABLES ========
WHERE CREATOR = 'ZZZ';
Figure 663, Query with no matching rows (1 of 8)
SELECT MAX(CREATOR) ANSWER
FROM SYSIBM.SYSTABLES ======
WHERE CREATOR = 'ZZZ';
Figure 664, Query with no matching rows (2 of 8)
SELECT MAX(CREATOR) ANSWER
FROM SYSIBM.SYSTABLES ========
WHERE CREATOR = 'ZZZ'
HAVING MAX(CREATOR) IS NOT NULL;
Figure 665, Query with no matching rows (3 of 8)
SELECT MAX(CREATOR) ANSWER
FROM SYSIBM.SYSTABLES ========
WHERE CREATOR = 'ZZZ'
HAVING MAX(CREATOR) = 'ZZZ';
Figure 666, Query with no matching rows (4 of 8)
SELECT MAX(CREATOR) ANSWER
FROM SYSIBM.SYSTABLES ========
WHERE CREATOR = 'ZZZ'
GROUP BY CREATOR;
Figure 667, Query with no matching rows (5 of 8)
SELECT CREATOR ANSWER
FROM SYSIBM.SYSTABLES ========
WHERE CREATOR = 'ZZZ'
GROUP BY CREATOR;
Figure 668, Query with no matching rows (6 of 8)
SELECT COUNT(*) ANSWER
FROM SYSIBM.SYSTABLES ========
WHERE CREATOR = 'ZZZ'
GROUP BY CREATOR;
Figure 669, Query with no matching rows (7 of 8)
SELECT COUNT(*) ANSWER
FROM SYSIBM.SYSTABLES ======
WHERE CREATOR = 'ZZZ'; 0
Figure 670, Query with no matching rows (8 of 8)
SELECT DATE('2001-09-22') ANSWER
FROM SYSIBM.SYSDUMMY1; ==========
09/22/2001
Figure 671, Convert value to DB2 date, right
SELECT DATE(2001-09-22) ANSWER
FROM SYSIBM.SYSDUMMY1; ==========
05/24/0006
Figure 672, Convert value to DB2 date, wrong
SELECT ID ANSWER
,NAME ===========
FROM STAFF ID NAME
WHERE ID <= 100 -- --------
AND ID = (INT(RAND()* 10) * 10) + 10 30 Marenghi
ORDER BY ID; 60 Quigley
Figure 673, Get random rows - Incorrect
WITH TEMP AS ANSWER
(SELECT ID ====================
,NAME ID NAME RAN EQL
,(INT(RAND(0)* 10) * 10) + 10 AS RAN --- -------- --- ---
FROM STAFF 10 Sanders 10 Y
WHERE ID <= 100 20 Pernal 30
) 30 Marenghi 70
SELECT T.* 40 O'Brien 10
,CASE ID 50 Hanes 30
WHEN RAN THEN 'Y' 60 Quigley 40
ELSE ' ' 70 Rothman 30
END AS EQL 80 James 100
FROM TEMP T 90 Koonitz 40
ORDER BY ID; 100 Plotz 100 Y
Figure 674, Get random rows - Explanation
WITH ANSWER
STAFF_NUMBERED AS ===========
(SELECT S.* ID NAME
,ROW_NUMBER() OVER() AS ROW# --- -------
FROM STAFF S 10 Sanders
WHERE ID <= 100 20 Pernal
), 90 Koonitz
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 675, Get random rows - Non-distinct
SELECT ID ANSWER
,NAME ===========
FROM (SELECT S.* ID NAME
,ROW_NUMBER() OVER(ORDER BY RAND()) AS R -- --------
FROM STAFF S 10 Sanders
WHERE ID <= 100 40 O'Brien
)AS XXX 60 Quigley
WHERE R <= 3
ORDER BY ID;
Figure 676, 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 END_TSTAMP
-------------------------- ------- --------------------------
2001-01-15-01.02.03.000000 1.234 2001-01-15-01.02.04.000000
2001-01-15-01.02.03.123456 1.234 2001-01-15-01.02.04.123456
Figure 677, Date/Time manipulation - wrong
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 END_TSTAMP
-------------------------- ------- --------------------------
2001-01-15-01.02.03.000000 1.234 2001-01-15-01.02.04.234000
2001-01-15-01.02.03.123456 1.234 2001-01-15-01.02.04.357456
Figure 678, Date/Time manipulation - right
WITH TEMP1 (C0,C1,V1) AS (VALUES ANSWER
('A',CHAR(' ',1),VARCHAR(' ',1)), ======
('B',CHAR(' ',1),VARCHAR('' ,1))) C0
SELECT C0 --
FROM TEMP1 A
WHERE C1 = V1 B
AND C1 LIKE ' ';
Figure 679, Use LIKE on CHAR field
WITH TEMP1 (C0,C1,V1) AS (VALUES ANSWER
('A',CHAR(' ',1),VARCHAR(' ',1)), ======
('B',CHAR(' ',1),VARCHAR('' ,1))) C0
SELECT C0 --
FROM TEMP1 A
WHERE C1 = V1
AND V1 LIKE ' ';
Figure 680, Use LIKE on VARCHAR field
WITH TEMP1 (C0,C1,V1) AS (VALUES ANSWER
('A',CHAR(' ',1),VARCHAR(' ',1)), ======
('B',CHAR(' ',1),VARCHAR('' ,1))) C0
SELECT C0 --
FROM TEMP1 A
WHERE C1 = V1 B
AND RTRIM(V1) LIKE '';
Figure 681, Use RTRIM to remove trailing blanks
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 682, Comparing week 33 over 10 years
SELECT SUM(INTEGER(SALARY)) AS S1 ANSWER
,INTEGER(SUM(SALARY)) AS S2 =============
FROM STAFF; S1 S2
------ ------
583633 583647
Figure 683, DB2 data truncation
SELECT SUM(INTEGER(ROUND(SALARY,-1))) AS S1 ANSWER
,INTEGER(SUM(SALARY)) AS S2 =============
FROM STAFF; S1 S2
------ ------
583640 583647
Figure 684, DB2 data rounding
SELECT LASTNAME ANSWER
,SEX =================
,CASE LASTNAME SX SXX
WHEN SEX >= 'F' THEN 'FEM' ---------- -- ---
WHEN SEX >= 'M' THEN 'MAL' JEFFERSON M FEM
END AS SXX JOHNSON F FEM
FROM EMPLOYEE JONES M FEM
WHERE LASTNAME LIKE 'J%'
ORDER BY 1;
Figure 685, Case WHEN Processing - Incorrect
SELECT LASTNAME ANSWER
,SEX =================
,CASE LASTNAME SX SXX
WHEN SEX >= 'M' THEN 'MAL' ---------- -- ---
WHEN SEX >= 'F' THEN 'FEM' JEFFERSON M MAL
END AS SXX JOHNSON F FEM
FROM EMPLOYEE JONES M MAL
WHERE LASTNAME LIKE 'J%'
ORDER BY 1;
Figure 686, Case WHEN Processing - Correct
SELECT AVG(SALARY) / AVG(COMM) AS A1 ANSWER >>> A1 A2
,AVG(SALARY / COMM) AS A2 -- -----
FROM STAFF; 32 61.98
Figure 687, Use LIKE on VARCHAR field
SELECT HIREDATE ANSWER
FROM EMPLOYEE ==========
WHERE HIREDATE < '1960-01-01' 05/05/1947
ORDER BY 1; 08/17/1949
05/16/1958
Figure 688, DATE output in year, month, day order
SELECT CHAR(HIREDATE,USA) ANSWER
FROM EMPLOYEE ==========
WHERE HIREDATE < '1960-01-01' 05/05/1947
ORDER BY 1; 05/16/1958
08/17/1949
Figure 689, DATE output in month, day, year order
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 690, Ambiguous Cursor
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 691, 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 692, 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 693, 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 694, 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 695, Comparing float and decimal division
WITH TEMP (F1, D1) AS
(VALUES (FLOAT(1.23456789)
,DEC(1.23456789,20,10))
UNION ALL
SELECT F1 * 10
,D1 * 10
FROM TEMP
WHERE F1 < 1E9
)
SELECT F1
,D1
,CASE
WHEN D1 = F1 THEN 'SAME'
ELSE 'DIFF'
END AS COMPARE
FROM TEMP;
Figure 696, 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 697, 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 698, Internal representation of "one tenth" in floating-point
CREATE VIEW DAMN_LAWYERS (DB2 ,V5) AS
(VALUES (0001,2)
,(1234,2));
Figure 699, Sample view definition
SELECT DB2/V5 AS ANSWER ANSWER
FROM DAMN_LAWYERS; ------
0
617
Figure 700, Trademark Invalid SQL
SELECT DB2 / V5 AS ANSWER ANSWER
FROM DAMN_LAWYERS; ------
0
617
Figure 701, Trademark Valid SQL