Call now: 252-767-6166  
Oracle Training Oracle Support Development Oracle Apps

 
 Home
 E-mail Us
 Oracle Articles
New Oracle Articles


 Oracle Training
 Oracle Tips

 Oracle Forum
 Class Catalog


 Remote DBA
 Oracle Tuning
 Emergency 911
 RAC Support
 Apps Support
 Analysis
 Design
 Implementation
 Oracle Support


 SQL Tuning
 Security

 Oracle UNIX
 Oracle Linux
 Monitoring
 Remote s
upport
 Remote plans
 Remote
services
 Application Server

 Applications
 Oracle Forms
 Oracle Portal
 App Upgrades
 SQL Server
 Oracle Concepts
 Software Support

 Remote S
upport  
 Development  

 Implementation


 Consulting Staff
 Consulting Prices
 Help Wanted!

 


 Oracle Posters
 Oracle Books

 Oracle Scripts
 Ion
 Excel-DB  

Don Burleson Blog 


 

 

 


 

 

 

 
 

Advanced Oracle SQL: Set Operators

Oracle Tips by Laurent Schneider

 

Laurent Schneider is considered one of the top Oracle SQL experts, and he is the author of the book "Advanced SQL Programming" by Rampant TechPress.  The following is an excerpt from the book.

 

1.    UNION ALL

UNION ALL selects all rows from all queries:

SELECT
   1 N
FROM
   DUAL
UNION ALL
SELECT
   2 N
FROM
   DUAL
UNION ALL

SELECT
   2 N
FROM
   DUAL;
 

         N
----------
         1
         2
         2

-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     3 |     6  (67)| 00:00:01 |
|   1 |  UNION-ALL       |      |       |            |          |
|   2 |   FAST DUAL      |      |     1 |     2   (0)| 00:00:01 |
|   3 |   FAST DUAL      |      |     1 |     2   (0)| 00:00:01 |
|   4 |   FAST DUAL      |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------

All rows are returned. Each query must have the same number of columns and the datatypes must be the same or compatible.

The partition views feature (Oracle 7.3) does not allow inserts or updates and the partitioning is done manually.

partview.sql

-- Id     : $Id: partview.sql,v 1.3 2015/01/18 17:16:30 lsc Exp $
-- Author : $Author: lsc $
-- Date   : $Date: 2015/01/18 17:16:30 $
--
-- Create EMP10 to EMP40 in current schema
-- 

WHENEVER SQLERROR EXIT 

EXEC EXECUTE IMMEDIATE 'DROP TABLE EMP10'; EXCEPTION WHEN OTHERS THEN NULL
EXEC EXECUTE IMMEDIATE 'DROP TABLE EMP20'; EXCEPTION WHEN OTHERS THEN NULL
EXEC EXECUTE IMMEDIATE 'DROP TABLE EMP30'; EXCEPTION WHEN OTHERS THEN NULL
EXEC EXECUTE IMMEDIATE 'DROP TABLE EMP40'; EXCEPTION WHEN OTHERS THEN NULL 

CREATE TABLE
   EMP10
AS SELECT
   *
FROM
   EMP
WHERE
   DEPTNO=10
/
CREATE TABLE
   EMP20
AS SELECT
   *
FROM
   EMP
WHERE
   DEPTNO=20
/
CREATE TABLE
   EMP30
AS SELECT
   *
FROM
   EMP
WHERE
   DEPTNO=30
/
CREATE TABLE
   EMP40
AS SELECT
   *
FROM
   EMP
WHERE
   DEPTNO=40
/
ALTER TABLE
   EMP10
ADD CONSTRAINT
   EMP10_PK
PRIMARY KEY
   (EMPNO)
/
ALTER TABLE
   EMP10
ADD CONSTRAINT
   CHECK10
CHECK
   (DEPTNO=10)
/
ALTER TABLE
   EMP20
ADD CONSTRAINT
   EMP20_PK
PRIMARY KEY
   (EMPNO)
/
ALTER TABLE
   EMP20
ADD CONSTRAINT
   CHECK20
CHECK
   (DEPTNO=20)
/
ALTER TABLE
   EMP30
ADD CONSTRAINT
   EMP30_PK
PRIMARY KEY
   (EMPNO)
/
ALTER TABLE
   EMP30
ADD CONSTRAINT
   CHECK30
CHECK
   (DEPTNO=30)
/
ALTER TABLE
   EMP40
ADD CONSTRAINT
   EMP40_PK
PRIMARY KEY
   (EMPNO)
/
ALTER TABLE
   EMP40
ADD CONSTRAINT
   CHECK40
CHECK
   (DEPTNO=40)
/
CREATE OR REPLACE VIEW
   V_EMP
AS
   SELECT
      *
   FROM
      EMP10
   UNION ALL
   SELECT
      *
   FROM
      EMP20
   UNION ALL
   SELECT
      *
   FROM
      EMP30
   UNION ALL
   SELECT
      *
   FROM
      EMP40

Four tables and a view are created. The optimizer recognizes this view as a partition view and chooses an efficient plan to retrieve data:

SELECT
   ENAME
FROM
   V_EMP
WHERE
   DEPTNO=20
   AND
   SAL>2000; 

ENAME
----------
JONES
SCOTT
FORD

------------------------------------------------------------------------------
| Id  | Operation            | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |       |     4 |    56 |     3   (0)| 00:00:01 |
|   1 |  VIEW                | V_EMP |     4 |    56 |     3   (0)| 00:00:01 |
|   2 |   UNION-ALL PARTITION|       |       |       |            |          |
|*  3 |    FILTER            |       |       |       |            |          |
|*  4 |     TABLE ACCESS FULL| EMP10 |     1 |    13 |     2   (0)| 00:00:01 |
|*  5 |    TABLE ACCESS FULL | EMP20 |     2 |    26 |     2   (0)| 00:00:01 |
|*  6 |    FILTER            |       |       |       |            |          |
|*  7 |     TABLE ACCESS FULL| EMP30 |     1 |    14 |     2   (0)| 00:00:01 |
|*  8 |    FILTER            |       |       |       |            |          |
|*  9 |     TABLE ACCESS FULL| EMP40 |     1 |    33 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------
   3 - filter(NULL IS NOT NULL)
   4 - filter("DEPTNO"=20 AND "SAL">2000)
   5 - filter("SAL">2000 AND "DEPTNO"=20)
   6 - filter(NULL IS NOT NULL)
   7 - filter("DEPTNO"=20 AND "SAL">2000)
   8 - filter(NULL IS NOT NULL)
   9 - filter("DEPTNO"=20 AND "SAL">2000)

Note the UNION-ALL PARTITION operation.

Table partitioning (Oracle 8.0 and later) is much more efficient.

parttable.sql

-- Id     : $Id: parttable.sql,v 1.3 2015/01/18 17:52:53 lsc Exp $
-- Author : $Author: lsc $
-- Date   : $Date: 2015/01/18 17:52:53 $
--
-- Create EMP_PART in current schema
-- 

WHENEVER SQLERROR EXIT 

EXEC EXECUTE IMMEDIATE 'DROP TABLE EMP_PART'; EXCEPTION WHEN OTHERS THEN NULL 

CREATE TABLE
   EMP_PART
PARTITION BY LIST

(
   DEPTNO
)
(
   PARTITION EMP_P10 VALUES(10),
   PARTITION EMP_P20 VALUES(20),
   PARTITION EMP_P30 VALUES(30),
  
PARTITION EMP_P40 VALUES(40)
)
AS SELECT
   *
FROM
   EMP
/
ALTER TABLE
   EMP_PART
ADD CONSTRAINT
   EMP_PART_PK
PRIMARY KEY
   (EMPNO)
/
 

Only one table is created with four partitions. The optimizer avoids accessing partitions:

SELECT
   ENAME
FROM
   EMP_PART
WHERE
   DEPTNO=20
   AND
   SAL>2000;

ENAME
----------
JONES
SCOTT
FORD
-------------------------------------------------------------------------------------------| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT      |          |     3 |    39 |     2   (0)| 00:00:01 |      
|       |
|   1 |  PARTITION LIST SINGLE|          |     3 |    39 |     2   (0)| 00:00:01 |     2
|     2 |
|*  2 |   TABLE ACCESS FULL   | EMP_PART |     3 |    39 |     2   (0)| 00:00:01 |     2
|     2 |
-------------------------------------------------------------------------------------------
   2 - filter("SAL">2000)

Only a single partition is accessed.

2.      UNION

The UNION set operator selects all rows and removes duplicates:

SELECT
   1 N
FROM
   DUAL
UNION
SELECT
   2 N
FROM
   DUAL
UNION
SELECT
   2 N
FROM
   DUAL; 

         N
----------
         1
         2

-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     3 |     9  (78)| 00:00:01 |
|   1 |  SORT UNIQUE     |      |     3 |     9  (78)| 00:00:01 |
|   2 |   UNION-ALL      |      |       |            |          |
|   3 |    FAST DUAL     |      |     1 |     2   (0)| 00:00:01 |
|   4 |    FAST DUAL     |      |     1 |     2   (0)| 00:00:01 |
|   5 |    FAST DUAL     |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------

All unique rows are returned. The UNION is shown actually doing a UNION ALL operation before removing the duplicates with a SORT UNIQUE. Due to that additional operation, UNION ALL performs better.

3.      MINUS

The MINUS set operator selects from the first query the rows that are not in the second query and removes any duplicates:

SELECT
   DEPTNO
FROM
   DEPT
MINUS
SELECT
   DEPTNO
FROM
   EMP;
 

    DEPTNO
----------
        40

-------------------------------------------------------------------------------
| Id  | Operation           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |         |     4 |    54 |     5  (80)| 00:00:01 |
|   1 |  MINUS              |         |       |       |            |          |
|   2 |   SORT UNIQUE NOSORT|         |     4 |    12 |     2  (50)| 00:00:01 |
|   3 |    INDEX FULL SCAN  | PK_DEPT |     4 |    12 |     1   (0)| 00:00:01 |
|   4 |   SORT UNIQUE       |         |    14 |    42 |     3  (34)| 00:00:01 |
|   5 |    TABLE ACCESS FULL| EMP     |    14 |    42 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Only department 40 remains because the other ones exist in EMP.

4.      INTERSECT

INTERSECT selects the distinct rows from the queries:

SELECT
   DEPTNO
FROM
   EMP
INTERSECT
SELECT
   DEPTNO
FROM
   DEPT;
    DEPTNO
----------
        10
        20
        30

-------------------------------------------------------------------------------
| Id  | Operation           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |         |     4 |    54 |     5  (60)| 00:00:01 |
|   1 |  INTERSECTION       |         |       |       |            |          |
|   2 |   SORT UNIQUE       |         |    14 |    42 |     3  (34)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| EMP     |    14 |    42 |     2   (0)| 00:00:01 |
|   4 |   SORT UNIQUE NOSORT|         |     4 |    12 |     2  (50)| 00:00:01 |
|   5 |    INDEX FULL SCAN  | PK_DEPT |     4 |    12 |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Departments 10, 20 and 30 are in both tables. Intersect is particularly useful when a very large number of columns must be compared. This way, the optimizer does not have to figure out how to join the tables and the parsing can be quicker.


 

 

��  
 
 
Oracle Training at Sea
 
 
 
 
oracle dba poster
 

 
Follow us on Twitter 
 
Oracle performance tuning software 
 
Oracle Linux poster
 
 
 

 

Burleson is the American Team

Note: This Oracle documentation was created as a support and Oracle training reference for use by our DBA performance tuning consulting professionals.  Feel free to ask questions on our Oracle forum.

Verify experience! Anyone considering using the services of an Oracle support expert should independently investigate their credentials and experience, and not rely on advertisements and self-proclaimed expertise. All legitimate Oracle experts publish their Oracle qualifications.

Errata?  Oracle technology is changing and we strive to update our BC Oracle support information.  If you find an error or have a suggestion for improving our content, we would appreciate your feedback.  Just  e-mail:  

and include the URL for the page.


                    









Burleson Consulting

The Oracle of Database Support

Oracle Performance Tuning

Remote DBA Services


 

Copyright © 1996 -  2020

All rights reserved by Burleson

Oracle ® is the registered trademark of Oracle Corporation.