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