SlideShare a Scribd company logo
1 of 60
Download to read offline
SQL Scripting Sorcery


RMOUG Training Days 2002
     Denver, CO
Overview

•   Basic Concepts
•   Inline Query
•   DECODE
•   CASE
•   Stupid SQL Tricks
•   Special Surprise
Row Source

• Access Path
• Result Set
• ROWNUM pseudocolumn
  – Order in result set, before explicit sorting
  – After predicate is applied
     • ‘WHERE’ clause
Row Source

• All data is retrieved from a row source
• May be a base object or the result set from a
  previous operation
• Oracle will use no more than 2 row sources
  for any single operation
• Result set may be row source for other
  operations
Access Paths

• What is an access path
• How access paths affect result sets
• Using different access paths
Access Paths
EMP    PK_EMPNO
How Access Paths Affect Result
                            Sets
• Table
  – Physical Order in datafile(s)
  – ROWID order
• Index
  – ‘Sorted’ order
  – Even if table is accessed
• Other
  – Order of result set
Using Different Access Paths

• Using/Suppressing an Index
• Hints
• Join Order
Result Sets

• The output of an operation
• Records are processed as a group
Sorting the Result Set

• Explicit Sorting
  – ORDER BY
• Implicit Sorting
  – DISTINCT
  – GROUP BY
  – UNION/INTERSECT/MINUS
Inline Query

•   What is an Inline Query?
•   Hierarchical Query Joins
•   Top N Queries
•   Sampling
What is an Inline Query?
• FROM clause contains a ‘SELECT’
  statement instead of a table or view
  – New in 7.2
• Cannot contain ORDER BY
  – Now Allowed in 8i
• Predicate cannot be dependent upon
  external condition
  – Cannot be a correlated subquery
Inline Query
select e2.ename2,
       e2.empno2
from (select ename ename2,
             empno empno2
      from emp) e2;
Hierarchical Query Joins

• Basic Hierarchical Query uses one and only
  one table
• Join cannot occur in Hierarchical Query
• Push query to inline query…it becomes just
  another result set!
Base Hierarchical Query
SELECT level,
       LPAD(' ',2*level-2)||emp.ename ename,
       emp.empno,
       emp.mgr,
       emp.deptno
FROM emp
CONNECT BY PRIOR emp.empno = emp.mgr
START WITH emp.mgr is null;

LEVEL      ENAME                EMPNO        MGR     DEPTNO
---------- --------------- ---------- ---------- ----------
         1 KING                  7839                    10
         2   JONES               7566       7839         20
         3     SCOTT             7788       7566         20
         4       ADAMS           7876       7788         20
         3     FORD              7902       7566         20
         2   BLAKE               7698       7839         30
         3     ALLEN             7499       7698         30
Joining a Hierarchical Query
SELECT level,
       LPAD(' ',2*level-2)||emp.ename ename,
       emp.empno,
       emp.mgr,
       dept.dname
FROM emp, dept
where emp.deptno = dept.deptno
CONNECT BY PRIOR emp.empno = emp.mgr
START WITH emp.mgr is null;
FROM emp, dept
     *
ERROR at line 2:
ORA-01437: cannot have join with CONNECT BY
Joining A Hierarchical Query
select e.e_level,
       e.ename,
       e.empno,
       e.mgr,
       d.dname
from dept d,
     (SELECT level e_level,
              LPAD(' ',2*level-2)||emp.ename ename,
              emp.empno empno,
              emp.mgr mgr,
              emp.deptno deptno
      FROM emp
      CONNECT BY PRIOR emp.empno = emp.mgr
      START WITH emp.mgr is null) e
where e.deptno = d.deptno;
Joining A Hierarchical Query
E_LEVEL ENAME               EMPNO        MGR DNAME
------- -------------- ---------- ---------- --------------
      1 KING                 7839            ACCOUNTING
      2   CLARK              7782       7839 ACCOUNTING
      3      MILLER          7934       7782 ACCOUNTING
      2   JONES              7566       7839 RESEARCH
      3      SCOTT           7788       7566 RESEARCH
      4        ADAMS         7876       7788 RESEARCH
      3      FORD            7902       7566 RESEARCH
Top N Queries

• What are the Top N values?
• Rownum and result set are key
• New features introduced in Oracle8i
  – ORDER BY in inline query
Top N Values

• Limited number of records based upon a
  value or set of values
  – Top 2 salaries in the company
  – Top 2 salaries in each department
  – What happens in the case of a tie?
• Implemented in other platforms
Top 2 Salaries
         Oracle 8.0.6                   Oracle 8.1.6
select ename,                  select *
       empno,                  from (select ename,
       sal,                                 empno,
       deptno,                              sal,
       hiredate                             deptno,
from (select distinct 0-sal,                hiredate
             ename,                  from emp
             empno,                  order by sal desc)
             sal,              where rownum <= 2;
             deptno,
             hiredate
       from emp)
where rownum <= 2;
Top 2 Salaries
ENAME           EMPNO        SAL     DEPTNO HIREDATE
---------- ---------- ---------- ---------- -----------
KING             7839       5000         10 17-NOV-1981
SCOTT            7788       3000         20 09-DEC-1982


• Only 2 records returned
• ….but there are 2 employees with $3000
  salary
• Should 3 records be returned?
Top 2 Salaries, part 2
         Oracle 8.0.6                       Oracle 8.1.6
select ename,                      select ename,
       empno,                             empno,
       sal,                               sal,
       deptno,                            deptno,
       hiredate                           hiredate
from emp                           from emp
where sal >=                       where sal >=
   (select min(i_sal)                 (select min(i_sal)
    from (select                       from
           distinct 0-sal r_sal,         (select sal i_sal
           sal i_sal                      from emp
          from emp)                       order by i_sal desc)
    where rownum <= 2);                   where rownum <= 2);
Top 2 Salaries
ENAME           EMPNO        SAL     DEPTNO HIREDATE
---------- ---------- ---------- ---------- -----------
KING             7839       5000         10 17-NOV-1981
FORD             7902       3000         20 03-DEC-1981
SCOTT            7788       3000         20 09-DEC-1982

• 3 records are returned
• ….for the top 2 salaries
• Is this the correct result?
Top 2 Salaries per Department

• Extraction of data is dependent upon data
  within query
• Move inline query into correlated subquery
Top 2 Salaries per Department
select m.ename,                                   select m.ename,
       m.sal,                                            m.sal,
       m.deptno                                          m.deptno
from emp m                                        from emp m
where m.sal >=                                    where m.sal >=
    (select distinct o.sal                            (select distinct o.sal
     from emp o                                        from emp o
     where (o.sal,2) in                                where (o.sal,2) in
              (select i.sal,                                    (select i.sal,
                      rownum                                            rownum
               from (select                                      from (select
                       distinct 0-i2.sal r_sal,                          i2.deptno,
                       i2.deptno,                                        i2.sal
                       i2.sal,                                         from emp i2
                       i2.rowid                                        order by i2.sal desc,
                     from emp i2) i                                             i2.deptno) i
               where i.deptno = m.deptno))                       where i.deptno = m.deptno))
order by deptno, sal desc;                        order by deptno, sal desc;
Top 2 Salaries per Department
ENAME             SAL     DEPTNO
---------- ---------- ----------
KING             5000         10
CLARK            2450         10
SCOTT            3000         20
FORD             3000         20
BLAKE            2850         30
ALLEN            1600         30
TURNER           1600         30
RANK

• Added in Oracle8i
  – Added for analytical functions
• Will include ties, but will skip ranks
• Can this be used for Top N Queries?
RANK
SELECT deptno, ename, sal, comm,
   RANK() OVER (PARTITION BY deptno
                ORDER BY sal DESC, comm) as rk
   FROM emp
where RANK() OVER (PARTITION BY deptno
                   ORDER BY sal DESC, comm) <= 2;

where RANK() OVER (PARTITION BY deptno ORDER BY sal
   DESC, comm) <= 2
      *
ERROR at line 4:
ORA-30483: window functions are not allowed here
RANK
select *
from (SELECT deptno, ename, sal, comm,
              RANK() OVER (PARTITION BY deptno
                           ORDER BY sal DESC, comm) as rk
      FROM emp )
where rk <=2;

    DEPTNO   ENAME             SAL       COMM         RK
----------   ---------- ---------- ---------- ----------
        10   KING             5000                     1
        10   CLARK            2450                     2
        20   JONES            3000                     1
        20   FORD             3000                     1
        30   BLAKE            3000                     1
        30   ALLEN            1600        300          2
DECODE

•   Deconstructing DECODE
•   Cross-tab reporting
•   Conditional DML
•   Simple menu
•   Duplicating a CASE function
Deconstructing Decode

• DECODE is a crude decision-making
  construct
• Implement
  – IF-THEN-ELSE
  – CASE
• Comparison must be equality
  – One or more values
Deconstructing Decode
SELECT ename,                     ENAME         DEPTNO DECODE(DEPTNO
       deptno,                    --------- ---------- -------------
       DECODE(deptno,             TURNER            30 SALES
              10, ‘ACCOUNTING’,   ALLEN             30 SALES
              20, ‘RESEARCH’,
                                  WARD              30 SALES
              30, ‘SALES’,
                                  ADAMS             20 RESEARCH
              ‘NOT INDICATED’)
                                  JONES             20 RESEARCH
FROM emp;
                                  MARTIN            30 SALES
IF DEPTNO = 10                    CLARK             10 ACCOUNTING
THEN ‘ACCOUNTING’
ELSE IF DEPTNO = 20
THEN ‘RESEARCH’
ELSE IF DEPTNO = 30
THEN ‘SALES’
ELSE ‘NOT INDICATED’
Cross-Tab Reports

• Spreadsheet type report
  – Down and Across
  – Static
  – Summary
• Each column is processed multiple times
  – ‘Ignore’ values not required
• GROUP BY important
Cross-Tab Reports
SELECT deptno DEPTNO,
       SUM(DECODE(to_char(hiredate, 'YYYY'),
                  '1980', SAL+(NVL(COMM,0)),
                  0)) YR_1980,
       SUM(DECODE(to_char(hiredate, 'YYYY'),
                  '1981', SAL+(NVL(COMM,0)),
                  0)) YR_1981,
       SUM(DECODE(to_char(hiredate, 'YYYY'),
                  '1982', SAL+(NVL(COMM,0)),
                  0)) YR_1982,
       SUM(DECODE(to_char(hiredate, 'YYYY'),
                  '1983', SAL+(NVL(COMM,0)),
                  0)) YR_1983
 FROM EMP
 GROUP BY deptno;

    DEPTNO    YR_1980    YR_1981    YR_1982    YR_1983
---------- ---------- ---------- ---------- ----------
        10          0       7450       1300          0
        20        800       5975       3000       1100
        30          0      11600          0          0
Conditional DML
                     Dynamic Select

• Select different column based on dynamic
  values
• Same table, different columns
• Different table, different columns
  – Traditional – UNION
  – Cool – OUTER JOIN and DECODE
Conditional DML
                                    Dynamic Select
select s.segment_name,
       s.segment_type,
       decode(s.segment_type,
              'INDEX', i.last_analyzed,
              'TABLE', t.last_analyzed) analyze_date
from user_segments s,
     user_tables t,
     user_indexes i
where s.segment_name = t.table_name (+)
  and s.segment_name = i.index_name (+);

SEGMENT_NAME                     SEGMENT_TYPE        ANALYZE_DATE
------------------------------   -----------------   ------------
DEPT                             TABLE               06-DEC-2000
EMP                              TABLE               06-DEC-2000
IX_DEPTNO                        INDEX               06-DEC-2000
IX_DNAME                         INDEX               06-DEC-2000
IX_ENAME                         INDEX               06-DEC-2000
Conditional DML
                     Dynamic Update

• Updating records based on dynamic value
• Multiple update statements?
• Single DECODE statement
  – Use GREATEST and LEAST to simulate
    Range Check
Conditional DML
                                              Dynamic Update
select ename,
       hiredate,
       greatest(hiredate, to_date('01-APR-1981')) gt_date,
       least(hiredate, to_date('01-APR-1982')) lt_date,
       decode(greatest(hiredate, to_date('01-APR-1981')),
              least(hiredate, to_date('01-APR-1982')), .1,
               .05) pay_raise
from emp;

ENAME        HIREDATE      GT_DATE       LT_DATE      PAY_RAISE
----------   -----------   -----------   ----------- ----------
ALLEN        20-FEB-1981   01-APR-1981   20-FEB-1981        .05
WARD         22-FEB-1981   01-APR-1981   22-FEB-1981        .05
JONES        02-APR-1981   02-APR-1981   02-APR-1981         .1
FORD         03-DEC-1981   03-DEC-1981   03-DEC-1981         .1
MILLER       23-JAN-1982   23-JAN-1982   23-JAN-1982         .1
SCOTT        09-DEC-1982   09-DEC-1982   01-APR-1982        .05
ADAMS        12-JAN-1983   12-JAN-1983   01-APR-1982        .05
Conditional DML
                        Dynamic Update

• Use CASE instead
  – But we haven’t learned that yet!
• Available Oracle 8.1.6
• Much Cleaner Code
Conditional DML
                    Dynamic Update
select ename,
       hiredate,
       CASE when TRUNC(hiredate)
              between ’01-APR-1981’
                  and ’31-MAR-1982’
            then 0.1
            else
            then 0.05
       END pay_raise
from emp;
CASE

• Finally, a real CASE function!
• New in Oracle8i
  – ANSI-standard
• Limit of 128 comparisons
• Nonequality comparisons
CASE
DECODE Approach                   CASE Approach
SELECT ename,                     SELECT ename,
       deptno,                           deptno,
       DECODE(deptno,                    CASE WHEN deptno = 10
              10, ‘ACCOUNTING’,                 THEN 'ACCOUNTING'
              20, ‘RESEARCH’,                 WHEN deptno = 20
              30, ‘SALES’,                      THEN 'RESEARCH'
              ‘NOT INDICATED’)                WHEN deptno = 30
FROM emp;                                       THEN 'SALES'
                                              ELSE 'NOT INDICATED'
                                         END
                                  FROM emp;
CASE

• Comparisons
  – Any Valid Oracle Expression
  – Do not have to be equality
Decode Approach
select ename,
       sal,
       decode(sign(sal-1000),
              -1, 'Low Pay',
              decode(sign(sal-2500),
                     -1, 'Medium Pay',
                     decode(sign(sal-4000),
                            -1, 'High Pay',
                            'DBA Pay')))
  pay_scale
from emp
Case Approach
select ename,
       sal,
       CASE when sal between 0 and 999
            then 'Low Pay'
            when sal between 1000 and 2500
            then 'Medium Pay'
            when sal between 2500 and 4000
            then 'High Pay'
            when sal > 4001
            then 'DBA Pay'
        END compensation
from emp
CASE
•   May be nested
    select job,
           comm,
           sal,
           CASE when comm is not null
                 then (CASE when comm > 100
                            then sal + comm
                            when comm <= 100
                            then sal + 100
                       END)
                  when job = 'CLERK'
                  then sal
                  else sal * 1.1
           END compensation
    from emp
Abandon Hope All Ye Who Enter
                        Here
I’m Not Kidding…
You Aren’t Ready For What
              Comes Next!
No Looking Ahead…
   Turn Back NOW!
Column Level Selects

• Can you use a select statement in the
  column list or expression?
Using SELECT as an Expression

• What values can be returned from a
  column?
  –   Data
  –   Literal
  –   Result of an Expression
  –   Result of a SELECT statement
Basic Construct
select (select count(*)
        from emp) emp_count
from dual;

 EMP_COUNT
----------
         8
Basic Construct
select (select count(*)
        from emp) emp_count,
        (select count(*)
         from dept) dept_count
from dual;

 EMP_COUNT DEPT_COUNT
---------- -----------
         8           4
Basic Construct

• Subquery can return one and only one row
• Subquery can return one and only one
  column
  – Multiple columns may be concatenated
• The main query will return as many rows as
  there are in the main table
Basic Construct

• Can
  –   restrict using a WHERE
  –   use a GROUP BY
  –   restrict using a HAVING
  –   join multiple tables
  –   be a correlated subquery
Selecting Multiple Values
select (select dname||loc
        from dept
        where deptno = 10)dname_loc
from dual;

DNAME_LOC
---------------------------
ACCOUNTINGNEW YORK
Joining Tables
select (select count(e1.empno)
        from emp e1,
             dept d1
        where d1.loc = 'NEW YORK'
          and d1.deptno = e1.deptno)
        ny_emps
from dual
Using as an expression
select s.segment_name,
       s.segment_type,
       decode(s.segment_type,
              'TABLE', (select t.last_analyzed
                        from user_tables t
                        where t.table_name = s.segment_name),
              'INDEX', (select i.last_analyzed
                        from user_indexes i
                        where i.index_name = s.segment_name),
              NULL) date_analyzed
from user_segments s
Using as an expression
select s.segment_name,
       s.segment_type,
       case when s.segment_type = 'TABLE'
            then (select t.last_analyzed
                  from user_tables t
                  where t.table_name = s.segment_name)
            when s.segment_type = 'INDEX'
            then (select i.last_analyzed
                  from user_indexes i
                  where i.index_name = s.segment_name)
            else NULL
        end date_analyzed
from user_segments s

More Related Content

Similar to SQL Scripting Sorcery: Top SQL Techniques for Extracting Insights

COIS 420 - Practice02
COIS 420 - Practice02COIS 420 - Practice02
COIS 420 - Practice02Angel G Diaz
 
Restricting and sorting data
Restricting and sorting data Restricting and sorting data
Restricting and sorting data HuzaifaMushtaq3
 
Les02[1]Restricting and Sorting Data
Les02[1]Restricting and Sorting DataLes02[1]Restricting and Sorting Data
Les02[1]Restricting and Sorting Datasiavosh kaviani
 
SQL WORKSHOP::Lecture 2
SQL WORKSHOP::Lecture 2SQL WORKSHOP::Lecture 2
SQL WORKSHOP::Lecture 2Umair Amjad
 
12c Mini Lesson - ANSI standard TOP-N query syntax
12c Mini Lesson - ANSI standard TOP-N query syntax12c Mini Lesson - ANSI standard TOP-N query syntax
12c Mini Lesson - ANSI standard TOP-N query syntaxConnor McDonald
 
Using SQL to process hierarchies
Using SQL to process hierarchiesUsing SQL to process hierarchies
Using SQL to process hierarchiesConnor McDonald
 
MERGE SQL Statement: Lesser Known Facets
MERGE SQL Statement: Lesser Known FacetsMERGE SQL Statement: Lesser Known Facets
MERGE SQL Statement: Lesser Known FacetsAndrej Pashchenko
 
Complex queries in sql
Complex queries in sqlComplex queries in sql
Complex queries in sqlCharan Reddy
 
حل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكل
حل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكلحل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكل
حل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكلMohamed Moustafa
 
SQL WORKSHOP::Lecture 4
SQL WORKSHOP::Lecture 4SQL WORKSHOP::Lecture 4
SQL WORKSHOP::Lecture 4Umair Amjad
 

Similar to SQL Scripting Sorcery: Top SQL Techniques for Extracting Insights (20)

COIS 420 - Practice02
COIS 420 - Practice02COIS 420 - Practice02
COIS 420 - Practice02
 
Restricting and sorting data
Restricting and sorting data Restricting and sorting data
Restricting and sorting data
 
chap2 (3).ppt
chap2 (3).pptchap2 (3).ppt
chap2 (3).ppt
 
Sql2
Sql2Sql2
Sql2
 
Les02[1]Restricting and Sorting Data
Les02[1]Restricting and Sorting DataLes02[1]Restricting and Sorting Data
Les02[1]Restricting and Sorting Data
 
Les02.pptx
Les02.pptxLes02.pptx
Les02.pptx
 
SQL WORKSHOP::Lecture 2
SQL WORKSHOP::Lecture 2SQL WORKSHOP::Lecture 2
SQL WORKSHOP::Lecture 2
 
12c Mini Lesson - ANSI standard TOP-N query syntax
12c Mini Lesson - ANSI standard TOP-N query syntax12c Mini Lesson - ANSI standard TOP-N query syntax
12c Mini Lesson - ANSI standard TOP-N query syntax
 
11 things about 11gr2
11 things about 11gr211 things about 11gr2
11 things about 11gr2
 
Chapter 1
Chapter 1Chapter 1
Chapter 1
 
Using SQL to process hierarchies
Using SQL to process hierarchiesUsing SQL to process hierarchies
Using SQL to process hierarchies
 
Les02
Les02Les02
Les02
 
Les02
Les02Les02
Les02
 
Les02 Restricting And Sorting Data
Les02 Restricting And Sorting DataLes02 Restricting And Sorting Data
Les02 Restricting And Sorting Data
 
MERGE SQL Statement: Lesser Known Facets
MERGE SQL Statement: Lesser Known FacetsMERGE SQL Statement: Lesser Known Facets
MERGE SQL Statement: Lesser Known Facets
 
KScope19 - SQL Features
KScope19 - SQL FeaturesKScope19 - SQL Features
KScope19 - SQL Features
 
Complex queries in sql
Complex queries in sqlComplex queries in sql
Complex queries in sql
 
حل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكل
حل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكلحل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكل
حل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكل
 
SQL WORKSHOP::Lecture 4
SQL WORKSHOP::Lecture 4SQL WORKSHOP::Lecture 4
SQL WORKSHOP::Lecture 4
 
7992267.ppt
7992267.ppt7992267.ppt
7992267.ppt
 

More from oracle documents (20)

Applyinga blockcentricapproachtotuning
Applyinga blockcentricapproachtotuningApplyinga blockcentricapproachtotuning
Applyinga blockcentricapproachtotuning
 
Windowsosauthent
WindowsosauthentWindowsosauthent
Windowsosauthent
 
Whatistnsnames
WhatistnsnamesWhatistnsnames
Whatistnsnames
 
Whatisadatabaselink
WhatisadatabaselinkWhatisadatabaselink
Whatisadatabaselink
 
Varraysandnestedtables
VarraysandnestedtablesVarraysandnestedtables
Varraysandnestedtables
 
Usertracing
UsertracingUsertracing
Usertracing
 
Userpasswrd
UserpasswrdUserpasswrd
Userpasswrd
 
Userlimit
UserlimitUserlimit
Userlimit
 
Undo internalspresentation
Undo internalspresentationUndo internalspresentation
Undo internalspresentation
 
Undo internals paper
Undo internals paperUndo internals paper
Undo internals paper
 
Tablespacelmt
TablespacelmtTablespacelmt
Tablespacelmt
 
Tablerename
TablerenameTablerename
Tablerename
 
Sql scripting sorcerypaper
Sql scripting sorcerypaperSql scripting sorcerypaper
Sql scripting sorcerypaper
 
Sql for dbaspresentation
Sql for dbaspresentationSql for dbaspresentation
Sql for dbaspresentation
 
Sequencereset
SequenceresetSequencereset
Sequencereset
 
Rollbacksizes
RollbacksizesRollbacksizes
Rollbacksizes
 
Rollbackshrinks
RollbackshrinksRollbackshrinks
Rollbackshrinks
 
Rollbacklmt
RollbacklmtRollbacklmt
Rollbacklmt
 
Rollbackblocking
RollbackblockingRollbackblocking
Rollbackblocking
 
Rollback1555s
Rollback1555sRollback1555s
Rollback1555s
 

SQL Scripting Sorcery: Top SQL Techniques for Extracting Insights

  • 1. SQL Scripting Sorcery RMOUG Training Days 2002 Denver, CO
  • 2. Overview • Basic Concepts • Inline Query • DECODE • CASE • Stupid SQL Tricks • Special Surprise
  • 3. Row Source • Access Path • Result Set • ROWNUM pseudocolumn – Order in result set, before explicit sorting – After predicate is applied • ‘WHERE’ clause
  • 4. Row Source • All data is retrieved from a row source • May be a base object or the result set from a previous operation • Oracle will use no more than 2 row sources for any single operation • Result set may be row source for other operations
  • 5. Access Paths • What is an access path • How access paths affect result sets • Using different access paths
  • 6. Access Paths EMP PK_EMPNO
  • 7. How Access Paths Affect Result Sets • Table – Physical Order in datafile(s) – ROWID order • Index – ‘Sorted’ order – Even if table is accessed • Other – Order of result set
  • 8. Using Different Access Paths • Using/Suppressing an Index • Hints • Join Order
  • 9. Result Sets • The output of an operation • Records are processed as a group
  • 10. Sorting the Result Set • Explicit Sorting – ORDER BY • Implicit Sorting – DISTINCT – GROUP BY – UNION/INTERSECT/MINUS
  • 11. Inline Query • What is an Inline Query? • Hierarchical Query Joins • Top N Queries • Sampling
  • 12. What is an Inline Query? • FROM clause contains a ‘SELECT’ statement instead of a table or view – New in 7.2 • Cannot contain ORDER BY – Now Allowed in 8i • Predicate cannot be dependent upon external condition – Cannot be a correlated subquery
  • 13. Inline Query select e2.ename2, e2.empno2 from (select ename ename2, empno empno2 from emp) e2;
  • 14. Hierarchical Query Joins • Basic Hierarchical Query uses one and only one table • Join cannot occur in Hierarchical Query • Push query to inline query…it becomes just another result set!
  • 15. Base Hierarchical Query SELECT level, LPAD(' ',2*level-2)||emp.ename ename, emp.empno, emp.mgr, emp.deptno FROM emp CONNECT BY PRIOR emp.empno = emp.mgr START WITH emp.mgr is null; LEVEL ENAME EMPNO MGR DEPTNO ---------- --------------- ---------- ---------- ---------- 1 KING 7839 10 2 JONES 7566 7839 20 3 SCOTT 7788 7566 20 4 ADAMS 7876 7788 20 3 FORD 7902 7566 20 2 BLAKE 7698 7839 30 3 ALLEN 7499 7698 30
  • 16. Joining a Hierarchical Query SELECT level, LPAD(' ',2*level-2)||emp.ename ename, emp.empno, emp.mgr, dept.dname FROM emp, dept where emp.deptno = dept.deptno CONNECT BY PRIOR emp.empno = emp.mgr START WITH emp.mgr is null; FROM emp, dept * ERROR at line 2: ORA-01437: cannot have join with CONNECT BY
  • 17. Joining A Hierarchical Query select e.e_level, e.ename, e.empno, e.mgr, d.dname from dept d, (SELECT level e_level, LPAD(' ',2*level-2)||emp.ename ename, emp.empno empno, emp.mgr mgr, emp.deptno deptno FROM emp CONNECT BY PRIOR emp.empno = emp.mgr START WITH emp.mgr is null) e where e.deptno = d.deptno;
  • 18. Joining A Hierarchical Query E_LEVEL ENAME EMPNO MGR DNAME ------- -------------- ---------- ---------- -------------- 1 KING 7839 ACCOUNTING 2 CLARK 7782 7839 ACCOUNTING 3 MILLER 7934 7782 ACCOUNTING 2 JONES 7566 7839 RESEARCH 3 SCOTT 7788 7566 RESEARCH 4 ADAMS 7876 7788 RESEARCH 3 FORD 7902 7566 RESEARCH
  • 19. Top N Queries • What are the Top N values? • Rownum and result set are key • New features introduced in Oracle8i – ORDER BY in inline query
  • 20. Top N Values • Limited number of records based upon a value or set of values – Top 2 salaries in the company – Top 2 salaries in each department – What happens in the case of a tie? • Implemented in other platforms
  • 21. Top 2 Salaries Oracle 8.0.6 Oracle 8.1.6 select ename, select * empno, from (select ename, sal, empno, deptno, sal, hiredate deptno, from (select distinct 0-sal, hiredate ename, from emp empno, order by sal desc) sal, where rownum <= 2; deptno, hiredate from emp) where rownum <= 2;
  • 22. Top 2 Salaries ENAME EMPNO SAL DEPTNO HIREDATE ---------- ---------- ---------- ---------- ----------- KING 7839 5000 10 17-NOV-1981 SCOTT 7788 3000 20 09-DEC-1982 • Only 2 records returned • ….but there are 2 employees with $3000 salary • Should 3 records be returned?
  • 23. Top 2 Salaries, part 2 Oracle 8.0.6 Oracle 8.1.6 select ename, select ename, empno, empno, sal, sal, deptno, deptno, hiredate hiredate from emp from emp where sal >= where sal >= (select min(i_sal) (select min(i_sal) from (select from distinct 0-sal r_sal, (select sal i_sal sal i_sal from emp from emp) order by i_sal desc) where rownum <= 2); where rownum <= 2);
  • 24. Top 2 Salaries ENAME EMPNO SAL DEPTNO HIREDATE ---------- ---------- ---------- ---------- ----------- KING 7839 5000 10 17-NOV-1981 FORD 7902 3000 20 03-DEC-1981 SCOTT 7788 3000 20 09-DEC-1982 • 3 records are returned • ….for the top 2 salaries • Is this the correct result?
  • 25. Top 2 Salaries per Department • Extraction of data is dependent upon data within query • Move inline query into correlated subquery
  • 26. Top 2 Salaries per Department select m.ename, select m.ename, m.sal, m.sal, m.deptno m.deptno from emp m from emp m where m.sal >= where m.sal >= (select distinct o.sal (select distinct o.sal from emp o from emp o where (o.sal,2) in where (o.sal,2) in (select i.sal, (select i.sal, rownum rownum from (select from (select distinct 0-i2.sal r_sal, i2.deptno, i2.deptno, i2.sal i2.sal, from emp i2 i2.rowid order by i2.sal desc, from emp i2) i i2.deptno) i where i.deptno = m.deptno)) where i.deptno = m.deptno)) order by deptno, sal desc; order by deptno, sal desc;
  • 27. Top 2 Salaries per Department ENAME SAL DEPTNO ---------- ---------- ---------- KING 5000 10 CLARK 2450 10 SCOTT 3000 20 FORD 3000 20 BLAKE 2850 30 ALLEN 1600 30 TURNER 1600 30
  • 28. RANK • Added in Oracle8i – Added for analytical functions • Will include ties, but will skip ranks • Can this be used for Top N Queries?
  • 29. RANK SELECT deptno, ename, sal, comm, RANK() OVER (PARTITION BY deptno ORDER BY sal DESC, comm) as rk FROM emp where RANK() OVER (PARTITION BY deptno ORDER BY sal DESC, comm) <= 2; where RANK() OVER (PARTITION BY deptno ORDER BY sal DESC, comm) <= 2 * ERROR at line 4: ORA-30483: window functions are not allowed here
  • 30. RANK select * from (SELECT deptno, ename, sal, comm, RANK() OVER (PARTITION BY deptno ORDER BY sal DESC, comm) as rk FROM emp ) where rk <=2; DEPTNO ENAME SAL COMM RK ---------- ---------- ---------- ---------- ---------- 10 KING 5000 1 10 CLARK 2450 2 20 JONES 3000 1 20 FORD 3000 1 30 BLAKE 3000 1 30 ALLEN 1600 300 2
  • 31. DECODE • Deconstructing DECODE • Cross-tab reporting • Conditional DML • Simple menu • Duplicating a CASE function
  • 32. Deconstructing Decode • DECODE is a crude decision-making construct • Implement – IF-THEN-ELSE – CASE • Comparison must be equality – One or more values
  • 33. Deconstructing Decode SELECT ename, ENAME DEPTNO DECODE(DEPTNO deptno, --------- ---------- ------------- DECODE(deptno, TURNER 30 SALES 10, ‘ACCOUNTING’, ALLEN 30 SALES 20, ‘RESEARCH’, WARD 30 SALES 30, ‘SALES’, ADAMS 20 RESEARCH ‘NOT INDICATED’) JONES 20 RESEARCH FROM emp; MARTIN 30 SALES IF DEPTNO = 10 CLARK 10 ACCOUNTING THEN ‘ACCOUNTING’ ELSE IF DEPTNO = 20 THEN ‘RESEARCH’ ELSE IF DEPTNO = 30 THEN ‘SALES’ ELSE ‘NOT INDICATED’
  • 34. Cross-Tab Reports • Spreadsheet type report – Down and Across – Static – Summary • Each column is processed multiple times – ‘Ignore’ values not required • GROUP BY important
  • 35. Cross-Tab Reports SELECT deptno DEPTNO, SUM(DECODE(to_char(hiredate, 'YYYY'), '1980', SAL+(NVL(COMM,0)), 0)) YR_1980, SUM(DECODE(to_char(hiredate, 'YYYY'), '1981', SAL+(NVL(COMM,0)), 0)) YR_1981, SUM(DECODE(to_char(hiredate, 'YYYY'), '1982', SAL+(NVL(COMM,0)), 0)) YR_1982, SUM(DECODE(to_char(hiredate, 'YYYY'), '1983', SAL+(NVL(COMM,0)), 0)) YR_1983 FROM EMP GROUP BY deptno; DEPTNO YR_1980 YR_1981 YR_1982 YR_1983 ---------- ---------- ---------- ---------- ---------- 10 0 7450 1300 0 20 800 5975 3000 1100 30 0 11600 0 0
  • 36. Conditional DML Dynamic Select • Select different column based on dynamic values • Same table, different columns • Different table, different columns – Traditional – UNION – Cool – OUTER JOIN and DECODE
  • 37. Conditional DML Dynamic Select select s.segment_name, s.segment_type, decode(s.segment_type, 'INDEX', i.last_analyzed, 'TABLE', t.last_analyzed) analyze_date from user_segments s, user_tables t, user_indexes i where s.segment_name = t.table_name (+) and s.segment_name = i.index_name (+); SEGMENT_NAME SEGMENT_TYPE ANALYZE_DATE ------------------------------ ----------------- ------------ DEPT TABLE 06-DEC-2000 EMP TABLE 06-DEC-2000 IX_DEPTNO INDEX 06-DEC-2000 IX_DNAME INDEX 06-DEC-2000 IX_ENAME INDEX 06-DEC-2000
  • 38. Conditional DML Dynamic Update • Updating records based on dynamic value • Multiple update statements? • Single DECODE statement – Use GREATEST and LEAST to simulate Range Check
  • 39. Conditional DML Dynamic Update select ename, hiredate, greatest(hiredate, to_date('01-APR-1981')) gt_date, least(hiredate, to_date('01-APR-1982')) lt_date, decode(greatest(hiredate, to_date('01-APR-1981')), least(hiredate, to_date('01-APR-1982')), .1, .05) pay_raise from emp; ENAME HIREDATE GT_DATE LT_DATE PAY_RAISE ---------- ----------- ----------- ----------- ---------- ALLEN 20-FEB-1981 01-APR-1981 20-FEB-1981 .05 WARD 22-FEB-1981 01-APR-1981 22-FEB-1981 .05 JONES 02-APR-1981 02-APR-1981 02-APR-1981 .1 FORD 03-DEC-1981 03-DEC-1981 03-DEC-1981 .1 MILLER 23-JAN-1982 23-JAN-1982 23-JAN-1982 .1 SCOTT 09-DEC-1982 09-DEC-1982 01-APR-1982 .05 ADAMS 12-JAN-1983 12-JAN-1983 01-APR-1982 .05
  • 40. Conditional DML Dynamic Update • Use CASE instead – But we haven’t learned that yet! • Available Oracle 8.1.6 • Much Cleaner Code
  • 41. Conditional DML Dynamic Update select ename, hiredate, CASE when TRUNC(hiredate) between ’01-APR-1981’ and ’31-MAR-1982’ then 0.1 else then 0.05 END pay_raise from emp;
  • 42. CASE • Finally, a real CASE function! • New in Oracle8i – ANSI-standard • Limit of 128 comparisons • Nonequality comparisons
  • 43. CASE DECODE Approach CASE Approach SELECT ename, SELECT ename, deptno, deptno, DECODE(deptno, CASE WHEN deptno = 10 10, ‘ACCOUNTING’, THEN 'ACCOUNTING' 20, ‘RESEARCH’, WHEN deptno = 20 30, ‘SALES’, THEN 'RESEARCH' ‘NOT INDICATED’) WHEN deptno = 30 FROM emp; THEN 'SALES' ELSE 'NOT INDICATED' END FROM emp;
  • 44. CASE • Comparisons – Any Valid Oracle Expression – Do not have to be equality
  • 45. Decode Approach select ename, sal, decode(sign(sal-1000), -1, 'Low Pay', decode(sign(sal-2500), -1, 'Medium Pay', decode(sign(sal-4000), -1, 'High Pay', 'DBA Pay'))) pay_scale from emp
  • 46. Case Approach select ename, sal, CASE when sal between 0 and 999 then 'Low Pay' when sal between 1000 and 2500 then 'Medium Pay' when sal between 2500 and 4000 then 'High Pay' when sal > 4001 then 'DBA Pay' END compensation from emp
  • 47. CASE • May be nested select job, comm, sal, CASE when comm is not null then (CASE when comm > 100 then sal + comm when comm <= 100 then sal + 100 END) when job = 'CLERK' then sal else sal * 1.1 END compensation from emp
  • 48. Abandon Hope All Ye Who Enter Here
  • 49. I’m Not Kidding… You Aren’t Ready For What Comes Next!
  • 50. No Looking Ahead… Turn Back NOW!
  • 51. Column Level Selects • Can you use a select statement in the column list or expression?
  • 52. Using SELECT as an Expression • What values can be returned from a column? – Data – Literal – Result of an Expression – Result of a SELECT statement
  • 53. Basic Construct select (select count(*) from emp) emp_count from dual; EMP_COUNT ---------- 8
  • 54. Basic Construct select (select count(*) from emp) emp_count, (select count(*) from dept) dept_count from dual; EMP_COUNT DEPT_COUNT ---------- ----------- 8 4
  • 55. Basic Construct • Subquery can return one and only one row • Subquery can return one and only one column – Multiple columns may be concatenated • The main query will return as many rows as there are in the main table
  • 56. Basic Construct • Can – restrict using a WHERE – use a GROUP BY – restrict using a HAVING – join multiple tables – be a correlated subquery
  • 57. Selecting Multiple Values select (select dname||loc from dept where deptno = 10)dname_loc from dual; DNAME_LOC --------------------------- ACCOUNTINGNEW YORK
  • 58. Joining Tables select (select count(e1.empno) from emp e1, dept d1 where d1.loc = 'NEW YORK' and d1.deptno = e1.deptno) ny_emps from dual
  • 59. Using as an expression select s.segment_name, s.segment_type, decode(s.segment_type, 'TABLE', (select t.last_analyzed from user_tables t where t.table_name = s.segment_name), 'INDEX', (select i.last_analyzed from user_indexes i where i.index_name = s.segment_name), NULL) date_analyzed from user_segments s
  • 60. Using as an expression select s.segment_name, s.segment_type, case when s.segment_type = 'TABLE' then (select t.last_analyzed from user_tables t where t.table_name = s.segment_name) when s.segment_type = 'INDEX' then (select i.last_analyzed from user_indexes i where i.index_name = s.segment_name) else NULL end date_analyzed from user_segments s