SlideShare a Scribd company logo
Oracle Database 12c Application Development
SQL and PL/SQL New Features

-Saurabh K. Gupta
Author of "Oracle Advanced PL/SQL Developer Professional Guide"
Table of Contents
SQL New features.................................................................................................................................3
a) Oracle 12c Temporal Support ................................................................................................3
b) Querying a table using SQL Row-Limiting Clause................................................................4
c) Generate Identity Columns in SQL.........................................................................................6
d) SQL Pattern Matching............................................................................................................8
PL/SQL New features.........................................................................................................................10
a) Using Boolean, Record and Collection type as Parameters in Subprograms.......................10
b) The ACCESSIBLE BY Clause.............................................................................................11
c) PL/SQL functions run faster in SQL.....................................................................................12
SQL New features
a) Oracle 12c Temporal Support
1. Connect to the SCOTT user in the NONCDB database
[oracle@localhost ~]$ . oraenv
ORACLE_SID = [cdb1] ? noncdb
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@localhost ~]$ sqlplus scott/tiger

2. Create a table with a valid time dimension
CREATE TABLE my_emp(
empno NUMBER,
last_name VARCHAR2(30),
start_time date,
end_time date,
PERIOD FOR user_valid_time (start_time, end_time))
/

3. Populate the table MY_EMP with the test data
INSERT INTO my_emp VALUES (100, 'Ames', to_date('01-JAN-2010','DD-MON-YYYY'),
to_date('30-JUN-2011','DD-MON-YYYY'))
/
INSERT INTO my_emp VALUES (101, 'Burton', to_date('01-JAN-2011','DD-MON-YYYY'),
to_date('30-JUN-2011','DD-MON-YYYY'))
/
INSERT INTO my_emp VALUES (102, 'Chen', to_date('01-JAN-2012','DD-MON-YYYY'),
null)
/

4. Display all records from MY_EMP table
SELECT * FROM my_emp;
EMPNO
---------100
101
102

LAST_NAME
-----------------------------Ames
Burton
Chen

START_TIM
--------01-JAN-10
01-JAN-11
01-JAN-12

END_TIME
--------30-JUN-11
30-JUN-11

5. Run the query to which are valid during 01st June, 2010
SELECT *
FROM my_emp
AS OF PERIOD FOR user_valid_time to_date('01-JUN-2010','DD-MON-YYYY')
/
EMPNO LAST_NAME
START_TIM END_TIME
---------- ------------------- --------- --------100 Ames
01-JAN-10 30-JUN-11
6. Run the query to which are valid between 01st June, 2010 and 01st June, 2011
SELECT *
from my_emp versions
PERIOD FOR user_valid_time BETWEEN
to_date('01-JUN-2010','DD-MON-YYYY') and to_date('01-JUN-2011','DD-MON-YYYY')
/
EMPNO
---------100
101

LAST_NAME
START_TIM END_TIME
------------------------------ --------- --------Ames
01-JAN-10 30-JUN-11
Burton
01-JAN-11 30-JUN-11

7. Use DBMS_FLASHBACK_ARCHIVE package to set the visibility of records. As
SYSDBA, grant EXECUTE privilege on the package to user SCOTT.
7a. Set the visibility to CURRENT and query the records in the MY_EMP table
EXEC dbms_flashback_archive.enable_at_valid_time('CURRENT');
PL/SQL procedure successfully completed.
SELECT * FROM my_emp;
EMPNO LAST_NAME
START_TIM END_TIME
---------- ------------------------------ --------- --------102 Chen
01-JAN-12

7a. Set the visibility to ALL and query the records in the MY_EMP table
EXEC dbms_flashback_archive.enable_at_valid_time('ALL');
PL/SQL procedure successfully completed.
SELECT * FROM my_emp;
EMPNO
---------100
101
102

LAST_NAME
-----------------------------Ames
Burton
Chen

START_TIM
--------01-JAN-10
01-JAN-11
01-JAN-12

END_TIME
--------30-JUN-11
30-JUN-11

b) Querying a table using SQL Row-Limiting Clause
1. Connect to the SCOTT user in the CDB1 database
[oracle@localhost ~]$ . oraenv
ORACLE_SID = [noncdb] ? cdb1
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@localhost ~]$ sqlplus scott/tiger@pdb1

2. Create a test table EMP_TEST for demonstration
CREATE TABLE emp_test
(empno VARCHAR2(30),
deptno NUMBER,
sal NUMBER,
hiredate DATE);
3. Populate the table EMP_TEST with the test data
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/

into emp_test values ('Emp1',10,1200,'01-JAN-1985')
into emp_test values ('Emp2',20,1500,'01-APR-1989')
into emp_test values ('Emp3',10,1830,'01-JUN-1993')
into emp_test values ('Emp4',10,1367,'01-DEC-1975')
into emp_test values ('Emp5',20,1344,'01-MAY-1984')
into emp_test values ('Emp6',30,1643,'01-FEB-1989')
into emp_test values ('Emp7',10,1621,'01-JUL-1988')
into emp_test values ('Emp8',30,1764,'01-AUG-1995')
into emp_test values ('Emp8',20,3245,'01-SEP-1986')
into emp_test values ('Emp9',10,3214,'01-JAN-1988')
into emp_test values ('Emp10',20,1245,'01-FEB-1989')
into emp_test values ('Emp11',10,6533,'01-MAR-1990')
into emp_test values ('Emp12',30,1324,'01-NOV-1991')
into emp_test values ('Emp13',20,6342,'01-JAN-1997')
into emp_test values ('Emp14',20,7223,'01-OCT-1983')
into emp_test values ('Emp15',30,2355,'01-NOV-1985')

4. Select the employee details of the first 5 employees ordered by their salaries.
SELECT *
FROM emp_test
ORDER BY sal DESC
FETCH FIRST 5 ROWS ONLY
/
EMPNO
DEPTNO
AL HIREDATE
--------------- ---------- ------- --------Emp14
20
7223 01-OCT-83
Emp11
10
6533 01-MAR-90
Emp16
30
6532 01-MAY-92
Emp13
20
6342 01-JAN-97
Emp20
10
4563 01-AUG-88
5. Select the employee details of the top 25% employees ordered by their salaries.
SELECT *
FROM emp_test
ORDER BY sal DESC
FETCH FIRST 25 PERCENT ROW ONLY
/
EMPNO
DEPTNO
AL HIREDATE
--------------- ---------- ------- --------Emp14
20
7223 01-OCT-83
Emp11
10
6533 01-MAR-90
Emp16
30
6532 01-MAY-92
Emp13
20
6342 01-JAN-97
Emp20
10
4563 01-AUG-88

6. Select the employee details of the next 2 employees ordered by their salaries after the
top-5 employees.
SELECT *
FROM emp_test
ORDER BY SAL DESC
OFFSET 5 ROWS FETCH NEXT 2 ROWS ONLY
/
EMPNO
DEPTNO
SAL HIREDATE
--------------- ---------- ------- --------Emp19
20
3456 01-DEC-87
Emp8
20
3245 01-SEP-86

c) Generate Identity Columns in SQL
1. Connect to the SCOTT user in the CDB1 database
[oracle@localhost ~]$ . oraenv
ORACLE_SID = [noncdb] ? cdb1
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@localhost ~]$ sqlplus scott/tiger@pdb1

2. Create the test table T_GEN_IDTY and include an column ID which generates as
identity
CREATE TABLE t_gen_idty
(id
NUMBER GENERATED AS IDENTITY,
name VARCHAR2(20))
/

3. View the identity column properties in USER_TAB_COLS and
USER_TAB_IDENTITY_COLS dictionary views.
Observe that the DATA_DEFAULT column in USER_TAB_COLS shows a sequence has
been implicitly created by Oracle to supply values to the identity column.
Observe that the IDENTITY_OPTIONS column in USER_TAB_IDENTITY_COLS shows
the sequence characteristics i.e. START WITH, INCREMENT BY, MAX VALUE, MIN
VALUE, CYCLE FLAG, CACHE SIZE and ORDER FLAG.
col column_name format a10
col data_default format a35
SELECT column_name,data_default,user_generated,default_on_null,identity_column
FROM user_tab_cols
WHERE table_name='T_GEN_IDTY'
/
COLUMN_NAM DATA_DEFAULT
---------- ----------------------------------ID
"SCOTT"."ISEQ$$_92720".nextval
NAME

USE DEF IDE
--- --- --YES NO YES
YES NO NO

SELECT table_name,column_name, generation_type,identity_options
FROM user_tab_identity_cols
WHERE table_name = 'T_GEN_IDTY'
/

4. Populate the table T_GEN_IDTY with the test data
insert
/
insert
/
insert
/
insert
/
insert
/
insert
/

into t_gen_idty (name) values ('Allen')
into t_gen_idty (name) values ('Matthew')
into t_gen_idty (name) values ('Peter')
into t_gen_idty (name) values ('John')
into t_gen_idty (name) values ('King')
into t_gen_idty (name) values ('Freddy')

5. Select the ID and NAME columns from the table
SELECT id,name
FROM t_gen_idty
/
ID
-------1
2
3
4
5
6

NAME
-------------------Allen
Matthew
Peter
John
King
Freddy

6 rows selected.

6. Manually, try to insert values in ID column. Oracle raises ORA-32795 to restrict manual
inserts on the Identity Columns.
INSERT INTO t_gen_idty VALUES (7,'Steyn');
insert into t_gen_idty values (7,'Steyn')
*
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column
d) SQL Pattern Matching
1. Connect to the SCOTT user in the CDB1 database
[oracle@localhost ~]$ . oraenv
ORACLE_SID = [noncdb] ? cdb1
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@localhost ~]$ sqlplus scott/tiger@pdb1

2. Create a test table for demonstration
CREATE TABLE ticker
(product VARCHAR2(10),
tstamp DATE,
price
NUMBER)
/

3. Populate the table TICKER with the test data
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/
INSERT
/

INTO ticker VALUES('ACME', '01-Apr-11', 12)
INTO ticker VALUES('ACME', '02-Apr-11', 17)
INTO ticker VALUES('ACME', '03-Apr-11', 19)
INTO ticker VALUES('ACME', '04-Apr-11', 21)
INTO ticker VALUES('ACME', '05-Apr-11', 25)
INTO ticker VALUES('ACME', '06-Apr-11', 12)
INTO ticker VALUES('ACME', '07-Apr-11', 15)
INTO ticker VALUES('ACME', '08-Apr-11', 20)
INTO ticker VALUES('ACME', '09-Apr-11', 24)
INTO ticker VALUES('ACME', '10-Apr-11', 25)
INTO ticker VALUES('ACME', '11-Apr-11', 19)
INTO ticker VALUES('ACME', '12-Apr-11', 15)
INTO ticker VALUES('ACME', '13-Apr-11', 25)
INTO ticker VALUES('ACME', '14-Apr-11', 25)
INTO ticker VALUES('ACME', '15-Apr-11', 14)
INTO ticker VALUES('ACME', '16-Apr-11', 12)
INTO ticker VALUES('ACME', '17-Apr-11', 14)
INTO ticker VALUES('ACME', '18-Apr-11', 24)
INTO ticker VALUES('ACME', '19-Apr-11', 23)
INTO ticker VALUES('ACME', '20-Apr-11', 22)
4. Pattern matching: Look for double bottom patterns ('W' shape)
SELECT product, first_x,first_y,last_w,last_z
FROM Ticker MATCH_RECOGNIZE (
PARTITION BY product
ORDER BY tstamp
MEASURES
first(X.tstamp) as first_x,
first(Y.tstamp) as first_y,
last(Y.tstamp) as last_y,
first(W.tstamp) as last_w,
last(Z.tstamp) as last_z
ONE ROW PER MATCH
PATTERN (X+ Y+ W+ Z+)
DEFINE
X AS (price < PREV(price)),
Y AS (price > PREV(price)),
W AS (price < PREV(price)),
Z AS (price > PREV(price)AND Z.tstamp - FIRST(x.tstamp) <= 7 ))
/
PRODUCT
FIRST_X
FIRST_Y
LAST_W LAST_Z
---------- --------- --------- --------- --------ACME
06-APR-11 07-APR-11 11-APR-11 13-APR-11

5. Pattern matching: Look for V-shape patterns
SELECT product, start_tstamp,bottom_tstamp, end_tstamp
FROM Ticker MATCH_RECOGNIZE (
PARTITION BY product
ORDER BY tstamp
MEASURES STRT.tstamp AS start_tstamp,
LAST(DOWN.tstamp) AS bottom_tstamp,
LAST(UP.tstamp) AS end_tstamp
ONE ROW PER MATCH
AFTER MATCH SKIP TO LAST UP
PATTERN (STRT DOWN+ UP+)
DEFINE
DOWN AS DOWN.price < PREV(DOWN.price),
UP AS UP.price > PREV(UP.price)
) MR
ORDER BY MR.product, MR.start_tstamp
/
PRODUCT
START_TST BOTTOM_TS END_TSTAM
---------- --------- --------- --------ACME
05-APR-11 06-APR-11 10-APR-11
ACME
10-APR-11 12-APR-11 13-APR-11
ACME
14-APR-11 16-APR-11 18-APR-11
PL/SQL New features
a) Using Boolean, Record and Collection type as Parameters in
Subprograms
Connect to the SCOTT user in the CDB1 database
[oracle@localhost ~]$ . oraenv
ORACLE_SID = [noncdb] ? cdb1
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@localhost ~]$ sqlplus scott/tiger@pdb1

i) For BOOLEAN datatype
1. Create a procedure with BOOLEAN type parameter.
CREATE OR REPLACE PROCEDURE p_demo_boolean_bind (p_var IN boolean) IS
BEGIN
IF p_var THEN
DBMS_OUTPUT.PUT_LINE('I am true');
ELSE
DBMS_OUTPUT.PUT_LINE('I am false');
END IF;
END;
/

2. Invoke the procedure in an anonymous block using EXECUTE IMMEDIATE to pass the
boolean argument as a bind variable.
set serveroutput on
DECLARE
l_var BOOLEAN := true;
BEGIN
EXECUTE IMMEDIATE 'begin p_demo_boolean_bind(:1); end;' using l_var;
END;
/

ii) For a collection type variable
1. Create a package with a local nested table collection and a member procedure which
uses the local collection type as the input argument.
CREATE OR REPLACE PACKAGE pkg_collection_bind IS
TYPE t is table of number;
PROCEDURE p_coll_bind (p_var t);
END;
/
CREATE OR REPLACE PACKAGE BODY pkg_collection_bind IS
PROCEDURE p_coll_bind (p_var t) is
BEGIN
FOR i in 1..p_var.count
LOOP
DBMS_OUTPUT.PUT_LINE('Element '||i||' is '||p_var(i));
END LOOP;
END;
END;
/
2. Invoke the packaged subprogram in an anonymous block using EXECUTE IMMEDIATE
to pass the collection argument as a bind variable.
set serveroutput on
DECLARE
l_var pkg_collection_bind.t := pkg_collection_bind.t (10,20,30,40,50,60,70);
BEGIN
EXECUTE IMMEDIATE 'begin pkg_collection_bind.p_coll_bind(:1); end;' USING
l_var;
END;
/

b) The ACCESSIBLE BY Clause
1. Create a procedure with an ACCESSIBLE BY clause. Specify the "white list" of trusted
subprograms in the clause who can invoke this procedure. However, it is not mandatory
that the list of subprograms specified must exist in the schema.
CREATE OR REPLACE PROCEDURE p_demo_accessible
AUTHID CURRENT_USER
ACCESSIBLE BY (package coll_pkg, procedure p_white_list, function f_white_list)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Testing ACCESSIBLE BY clause in Oracle 12c');
END;
/

2. Create the "white list" procedure which invokes the above procedure. Invoke the
procedure P_WHITE_LIST to verify the access to P_DEMO_ACCESSIBLE procedure.
CREATE OR REPLACE PROCEDURE p_white_list is
BEGIN
DBMS_OUTPUT.PUT_LINE('Invoking P_DEMO_ACCESSIBLE..');
P_DEMO_ACCESSIBLE;
END;
/
SET SERVEROUTPUT ON
BEGIN
p_white_list;
END;
/
Invoking P_DEMO_ACCESSIBLE..
Testing ACCESSIBLE BY clause in oracle 12c
PL/SQL procedure successfully completed.

3. Try invoking the procedure P_DEMO_ACCESSIBLE in an anonymous block.
begin
P_DEMO_ACCESSIBLE;
end;
/
BEGIN P_DEMO_ACCESSIBLE; END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00904: insufficient privilege to access object P_DEMO_ACCESSIBLE;
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

c) PL/SQL functions run faster in SQL
1. Create a test table T
CREATE TABLE
(
PK integer
n1 integer
n2 integer
n3 integer
constraint
)
/

t
not null,
not null,
not null,
not null,
t_PK primary key(PK)

2. Populate the table T by generating the random data using the below PL/SQL program
DECLARE
commit_count constant pls_integer := 100000;
nof_Rows constant pls_integer := 20*commit_count;
Zero constant integer not null := 0;
THS
constant integer not null := 1000;
MIL
constant integer not null := THS*THS;
BIL
constant integer not null := MIL*THS;
TIL
constant integer not null := BIL*THS;
M1
constant integer not null := 2*THS;
M2
constant integer not null := 2*BIL;
Hi
constant integer not null := 2*TIL;
BEGIN
DBMS_Random.Seed(To_Char(Sysdate, 'MM-DD-YYYY HH24:MI:SS'));
for j in 1..Nof_Rows loop
declare
n1 integer not null := DBMS_Random.Value(Zero, M1);
n2 integer not null := DBMS_Random.Value(M1, M2);
n3 integer not null := DBMS_Random.Value(M2, Hi);
begin
insert into t(PK, n1, n2, n3) values(j, n1, n2, n3);
end;
if Mod(j, commit_count) = 0 then
commit;
end if;
end loop;
commit;
END;

/
3. Gather the table stats for the table T
begin
DBMS_Stats.Gather_Table_Stats('SCOTT', 'T');
end;
/
4. Create the PL/SQL function logic to pretty print an integer as a multiple of appropriate
unit of "Thousand", "Million","Billion" or "Trillion". We shall do this activity in different
fashion to measure the compare the performance. Record the timing at each stage to do
the comparison
a) Using a conventional pre 12c standalone function to set the base line
CREATE OR REPLACE FUNCTION F_ShowVal_pre12c(n IN integer) return varchar2 is
THS
constant integer not null := 1000;
MIL
constant integer not null := THS*THS;
BIL
constant integer not null := MIL*THS;
TIL
constant integer not null := BIL*THS;
BEGIN
RETURN
CASE
WHEN n
<= 999 then To_Char(n, '999999')||' units'
WHEN n/THS <= 999 then To_Char(n/THS, '999999')||' Thousand'
WHEN n/MIL <= 999 then To_Char(n/MIL, '999999')||' Million'
WHEN n/BIL <= 999 then To_Char(n/BIL, '999999')||' Billion'
ELSE
To_Char(n/TIL, '999999')||' Trillion'
END;
END F_ShowVal_pre12c;
/
SET TIMING ON
SELECT F_ShowVal_pre12c(n1) n1, F_ShowVal_pre12c(n2) n2, F_ShowVal_pre12c(n3) n3
FROM t
/

b) Using Pure SQL
SET TIMING ON
SELECT PK,
case

case

n1
n1/1000
n1/1000000
n1/1000000000

<= 999 then To_Char(n1, '999999')||' units'
<= 999 then To_Char(n1/1000, '999999')||' Thousand'
<= 999 then To_Char(n1/1000000, '999999')||' Million'
<= 999 then To_Char(n1/1000000000, '999999')||' Billion'
To_Char(n1/1000000000000, '999999')||' Trillion'

when
when
when
when
Else

end,
case

when
when
when
when
Else

n2
n2/1000
n2/1000000
n2/1000000000

<= 999 then To_Char(n2, '999999')||' units'
<= 999 then To_Char(n2/1000, '999999')||' Thousand'
<=999 then To_Char(n2/1000000, '999999')||' Million'
<=999 then To_Char(n2/1000000000, '999999')||' Billion'
To_Char(n2/1000000000000, '999999')||' Trillion'

when
when
when
when
Else

n3
n3/1000
n3/1000000
n3/1000000000

<= 999 then To_Char(n3, '999999')||' units'
<= 999 then To_Char(n3/1000, '999999')||' Thousand'
<= 999 then To_Char(n3/1000000, '999999')||' Million'
<= 999 then To_Char(n3/1000000000, '999999')||' Billion'
To_Char(n3/1000000000000, '999999')||' Trillion'

end,

end
FROM t
/

c) Declaring the PL/SQL function in the subquery's WITH clause
SET TIMING ON
WITH
function ShowVal(n IN integer) return varchar2 is
THS
constant integer not null := 1000;
MIL
constant integer not null := THS*THS;
BIL
constant integer not null := MIL*THS;
TIL
constant integer not null := BIL*THS;
Begin
return
case
when n
when n/THS
when n/MIL
when n/BIL
Else
end;
end ShowVal;
SELECT showVal(n1) n1,
FROM t
/

<= THS-1 then To_Char(n, '999999')||' units'
<= THS-1 then To_Char(n/THS, '999999')||' Thousand'
<= THS-1 then To_Char(n/MIL, '999999')||' Million'
<= THS-1 then To_Char(n/BIL, '999999')||' Billion'
To_Char(n/TIL, '999999')||' Trillion'
showVal(n2) n2, showVal(n3) n3

d) Declaring the PL/SQL function using PRAGMA UDF
CREATE OR REPLACE FUNCTION F_ShowVal(n IN integer) return varchar2 is
PRAGMA UDF;
THS
constant integer not null := 1000;
MIL
constant integer not null := THS*THS;
BIL
constant integer not null := MIL*THS;
TIL
constant integer not null := BIL*THS;
BEGIN
RETURN
CASE
WHEN n
<= 999 then To_Char(n, '999999')||' units'
WHEN n/THS <= 999 then To_Char(n/THS, '999999')||' Thousand'
WHEN n/MIL <= 999 then To_Char(n/MIL, '999999')||' Million'
WHEN n/BIL <= 999 then To_Char(n/BIL, '999999')||' Billion'
ELSE
To_Char(n/TIL, '999999')||' Trillion'
END;
END F_ShowVal;
/
SET TIMING ON
SELECT F_ShowVal(n1) n1, F_ShowVal(n2) n2, F_ShowVal(n3) n3
FROM t
/

Record your observations from the steps (a), (b), (c) and (d) in the below matrix. Here is
the performance comparison from the above scenarios Method

Timing recorded

Performance gains

(a) Pre 12c Standalone function 565 sec (Baseline)

1X

(b) Pure SQL

210 sec

2.7X

(c) Using WITH clause

315 sec

1.8X

(d) Using PRAGMA UDF

380 sec

1.5 X

More Related Content

PDF
Flashback ITOUG
PDF
Sangam 19 - PLSQL still the coolest
PDF
UKOUG - 25 years of hints and tips
PDF
UKOUG 2019 - SQL features
PDF
Sangam 2019 - The Latest Features
PDF
Sangam 19 - Analytic SQL
PDF
ANSI vs Oracle language
PDF
Database Management System
Flashback ITOUG
Sangam 19 - PLSQL still the coolest
UKOUG - 25 years of hints and tips
UKOUG 2019 - SQL features
Sangam 2019 - The Latest Features
Sangam 19 - Analytic SQL
ANSI vs Oracle language
Database Management System

What's hot (19)

PPTX
SQL techniques for faster applications
PDF
APEX Connect 2019 - array/bulk processing in PLSQL
PDF
Latin America Tour 2019 - 10 great sql features
PDF
Sangam 19 - Successful Applications on Autonomous
PDF
KScope19 - SQL Features
PDF
حل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكل
PDF
Oracle trace data collection errors: the story about oceans, islands, and rivers
DOCX
Oracle 12c far sync standby instance
PDF
Latin America Tour 2019 - pattern matching
PDF
Most important "trick" of performance instrumentation
PDF
Latin America tour 2019 - Flashback
PDF
MERGE SQL Statement: Lesser Known Facets
PPT
PDF
APEX Connect 2019 - SQL Tuning 101
PPTX
Get your moneys worth out of your database
PPTX
Les04 Displaying Data From Multiple Table
DOC
Upgrade 10204-to-10205 on-2-node_rac_linux_x86_64_detail-steps_v0.1
SQL techniques for faster applications
APEX Connect 2019 - array/bulk processing in PLSQL
Latin America Tour 2019 - 10 great sql features
Sangam 19 - Successful Applications on Autonomous
KScope19 - SQL Features
حل اسئلة الكتاب السعودى فى شرح قواعد البيانات اوراكل
Oracle trace data collection errors: the story about oceans, islands, and rivers
Oracle 12c far sync standby instance
Latin America Tour 2019 - pattern matching
Most important "trick" of performance instrumentation
Latin America tour 2019 - Flashback
MERGE SQL Statement: Lesser Known Facets
APEX Connect 2019 - SQL Tuning 101
Get your moneys worth out of your database
Les04 Displaying Data From Multiple Table
Upgrade 10204-to-10205 on-2-node_rac_linux_x86_64_detail-steps_v0.1
Ad

Similar to Oracle Database 12c Application Development (20)

PDF
Overview of Oracle database12c for developers
PDF
PPTX
12 things about Oracle 12c
PPT
IEEE Day 2013 Oracle Database 12c: new features for developers
PPTX
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...
PPTX
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...
PPTX
More than 12 More things about Oracle Database 12c
PPTX
OTN TOUR 2016 - DBA Commands and Concepts That Every Developer Should Know
PPTX
OTN TOUR 2016 - DBA Commands and Concepts That Every Developer Should Know
PPTX
OpenWorld Sep14 12c for_developers
PPTX
12c Mini Lesson - Better Defaults
PPTX
Oracle 11g new features for developers
PPTX
DBA Commands and Concepts That Every Developer Should Know
PDF
Oracle12c For Developers
PDF
Oracle12 for Developers - Oracle OpenWorld Preview AMIS
PPTX
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
PPTX
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
PPTX
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
PDF
Oracle 12c Application development
PDF
OOW19 - Ten Amazing SQL features
Overview of Oracle database12c for developers
12 things about Oracle 12c
IEEE Day 2013 Oracle Database 12c: new features for developers
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...
OOW16 - Oracle Database 12c - The Best Oracle Database 12c New Features for D...
More than 12 More things about Oracle Database 12c
OTN TOUR 2016 - DBA Commands and Concepts That Every Developer Should Know
OTN TOUR 2016 - DBA Commands and Concepts That Every Developer Should Know
OpenWorld Sep14 12c for_developers
12c Mini Lesson - Better Defaults
Oracle 11g new features for developers
DBA Commands and Concepts That Every Developer Should Know
Oracle12c For Developers
Oracle12 for Developers - Oracle OpenWorld Preview AMIS
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
Oracle 12c Application development
OOW19 - Ten Amazing SQL features
Ad

Recently uploaded (20)

PPT
Teaching material agriculture food technology
PPTX
Cloud computing and distributed systems.
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Empathic Computing: Creating Shared Understanding
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PPTX
Spectroscopy.pptx food analysis technology
PDF
Machine learning based COVID-19 study performance prediction
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
KodekX | Application Modernization Development
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
NewMind AI Weekly Chronicles - August'25 Week I
Teaching material agriculture food technology
Cloud computing and distributed systems.
Chapter 3 Spatial Domain Image Processing.pdf
Empathic Computing: Creating Shared Understanding
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
sap open course for s4hana steps from ECC to s4
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Review of recent advances in non-invasive hemoglobin estimation
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Spectroscopy.pptx food analysis technology
Machine learning based COVID-19 study performance prediction
Spectral efficient network and resource selection model in 5G networks
Mobile App Security Testing_ A Comprehensive Guide.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Understanding_Digital_Forensics_Presentation.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?
KodekX | Application Modernization Development
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
NewMind AI Weekly Chronicles - August'25 Week I

Oracle Database 12c Application Development

  • 1. Oracle Database 12c Application Development SQL and PL/SQL New Features -Saurabh K. Gupta Author of "Oracle Advanced PL/SQL Developer Professional Guide"
  • 2. Table of Contents SQL New features.................................................................................................................................3 a) Oracle 12c Temporal Support ................................................................................................3 b) Querying a table using SQL Row-Limiting Clause................................................................4 c) Generate Identity Columns in SQL.........................................................................................6 d) SQL Pattern Matching............................................................................................................8 PL/SQL New features.........................................................................................................................10 a) Using Boolean, Record and Collection type as Parameters in Subprograms.......................10 b) The ACCESSIBLE BY Clause.............................................................................................11 c) PL/SQL functions run faster in SQL.....................................................................................12
  • 3. SQL New features a) Oracle 12c Temporal Support 1. Connect to the SCOTT user in the NONCDB database [oracle@localhost ~]$ . oraenv ORACLE_SID = [cdb1] ? noncdb The Oracle base remains unchanged with value /u01/app/oracle [oracle@localhost ~]$ sqlplus scott/tiger 2. Create a table with a valid time dimension CREATE TABLE my_emp( empno NUMBER, last_name VARCHAR2(30), start_time date, end_time date, PERIOD FOR user_valid_time (start_time, end_time)) / 3. Populate the table MY_EMP with the test data INSERT INTO my_emp VALUES (100, 'Ames', to_date('01-JAN-2010','DD-MON-YYYY'), to_date('30-JUN-2011','DD-MON-YYYY')) / INSERT INTO my_emp VALUES (101, 'Burton', to_date('01-JAN-2011','DD-MON-YYYY'), to_date('30-JUN-2011','DD-MON-YYYY')) / INSERT INTO my_emp VALUES (102, 'Chen', to_date('01-JAN-2012','DD-MON-YYYY'), null) / 4. Display all records from MY_EMP table SELECT * FROM my_emp; EMPNO ---------100 101 102 LAST_NAME -----------------------------Ames Burton Chen START_TIM --------01-JAN-10 01-JAN-11 01-JAN-12 END_TIME --------30-JUN-11 30-JUN-11 5. Run the query to which are valid during 01st June, 2010 SELECT * FROM my_emp AS OF PERIOD FOR user_valid_time to_date('01-JUN-2010','DD-MON-YYYY') / EMPNO LAST_NAME START_TIM END_TIME ---------- ------------------- --------- --------100 Ames 01-JAN-10 30-JUN-11
  • 4. 6. Run the query to which are valid between 01st June, 2010 and 01st June, 2011 SELECT * from my_emp versions PERIOD FOR user_valid_time BETWEEN to_date('01-JUN-2010','DD-MON-YYYY') and to_date('01-JUN-2011','DD-MON-YYYY') / EMPNO ---------100 101 LAST_NAME START_TIM END_TIME ------------------------------ --------- --------Ames 01-JAN-10 30-JUN-11 Burton 01-JAN-11 30-JUN-11 7. Use DBMS_FLASHBACK_ARCHIVE package to set the visibility of records. As SYSDBA, grant EXECUTE privilege on the package to user SCOTT. 7a. Set the visibility to CURRENT and query the records in the MY_EMP table EXEC dbms_flashback_archive.enable_at_valid_time('CURRENT'); PL/SQL procedure successfully completed. SELECT * FROM my_emp; EMPNO LAST_NAME START_TIM END_TIME ---------- ------------------------------ --------- --------102 Chen 01-JAN-12 7a. Set the visibility to ALL and query the records in the MY_EMP table EXEC dbms_flashback_archive.enable_at_valid_time('ALL'); PL/SQL procedure successfully completed. SELECT * FROM my_emp; EMPNO ---------100 101 102 LAST_NAME -----------------------------Ames Burton Chen START_TIM --------01-JAN-10 01-JAN-11 01-JAN-12 END_TIME --------30-JUN-11 30-JUN-11 b) Querying a table using SQL Row-Limiting Clause 1. Connect to the SCOTT user in the CDB1 database [oracle@localhost ~]$ . oraenv ORACLE_SID = [noncdb] ? cdb1 The Oracle base remains unchanged with value /u01/app/oracle [oracle@localhost ~]$ sqlplus scott/tiger@pdb1 2. Create a test table EMP_TEST for demonstration CREATE TABLE emp_test (empno VARCHAR2(30), deptno NUMBER, sal NUMBER, hiredate DATE);
  • 5. 3. Populate the table EMP_TEST with the test data insert / insert / insert / insert / insert / insert / insert / insert / insert / insert / insert / insert / insert / insert / insert / insert / into emp_test values ('Emp1',10,1200,'01-JAN-1985') into emp_test values ('Emp2',20,1500,'01-APR-1989') into emp_test values ('Emp3',10,1830,'01-JUN-1993') into emp_test values ('Emp4',10,1367,'01-DEC-1975') into emp_test values ('Emp5',20,1344,'01-MAY-1984') into emp_test values ('Emp6',30,1643,'01-FEB-1989') into emp_test values ('Emp7',10,1621,'01-JUL-1988') into emp_test values ('Emp8',30,1764,'01-AUG-1995') into emp_test values ('Emp8',20,3245,'01-SEP-1986') into emp_test values ('Emp9',10,3214,'01-JAN-1988') into emp_test values ('Emp10',20,1245,'01-FEB-1989') into emp_test values ('Emp11',10,6533,'01-MAR-1990') into emp_test values ('Emp12',30,1324,'01-NOV-1991') into emp_test values ('Emp13',20,6342,'01-JAN-1997') into emp_test values ('Emp14',20,7223,'01-OCT-1983') into emp_test values ('Emp15',30,2355,'01-NOV-1985') 4. Select the employee details of the first 5 employees ordered by their salaries. SELECT * FROM emp_test ORDER BY sal DESC FETCH FIRST 5 ROWS ONLY / EMPNO DEPTNO AL HIREDATE --------------- ---------- ------- --------Emp14 20 7223 01-OCT-83 Emp11 10 6533 01-MAR-90 Emp16 30 6532 01-MAY-92 Emp13 20 6342 01-JAN-97 Emp20 10 4563 01-AUG-88
  • 6. 5. Select the employee details of the top 25% employees ordered by their salaries. SELECT * FROM emp_test ORDER BY sal DESC FETCH FIRST 25 PERCENT ROW ONLY / EMPNO DEPTNO AL HIREDATE --------------- ---------- ------- --------Emp14 20 7223 01-OCT-83 Emp11 10 6533 01-MAR-90 Emp16 30 6532 01-MAY-92 Emp13 20 6342 01-JAN-97 Emp20 10 4563 01-AUG-88 6. Select the employee details of the next 2 employees ordered by their salaries after the top-5 employees. SELECT * FROM emp_test ORDER BY SAL DESC OFFSET 5 ROWS FETCH NEXT 2 ROWS ONLY / EMPNO DEPTNO SAL HIREDATE --------------- ---------- ------- --------Emp19 20 3456 01-DEC-87 Emp8 20 3245 01-SEP-86 c) Generate Identity Columns in SQL 1. Connect to the SCOTT user in the CDB1 database [oracle@localhost ~]$ . oraenv ORACLE_SID = [noncdb] ? cdb1 The Oracle base remains unchanged with value /u01/app/oracle [oracle@localhost ~]$ sqlplus scott/tiger@pdb1 2. Create the test table T_GEN_IDTY and include an column ID which generates as identity CREATE TABLE t_gen_idty (id NUMBER GENERATED AS IDENTITY, name VARCHAR2(20)) / 3. View the identity column properties in USER_TAB_COLS and USER_TAB_IDENTITY_COLS dictionary views. Observe that the DATA_DEFAULT column in USER_TAB_COLS shows a sequence has been implicitly created by Oracle to supply values to the identity column. Observe that the IDENTITY_OPTIONS column in USER_TAB_IDENTITY_COLS shows the sequence characteristics i.e. START WITH, INCREMENT BY, MAX VALUE, MIN
  • 7. VALUE, CYCLE FLAG, CACHE SIZE and ORDER FLAG. col column_name format a10 col data_default format a35 SELECT column_name,data_default,user_generated,default_on_null,identity_column FROM user_tab_cols WHERE table_name='T_GEN_IDTY' / COLUMN_NAM DATA_DEFAULT ---------- ----------------------------------ID "SCOTT"."ISEQ$$_92720".nextval NAME USE DEF IDE --- --- --YES NO YES YES NO NO SELECT table_name,column_name, generation_type,identity_options FROM user_tab_identity_cols WHERE table_name = 'T_GEN_IDTY' / 4. Populate the table T_GEN_IDTY with the test data insert / insert / insert / insert / insert / insert / into t_gen_idty (name) values ('Allen') into t_gen_idty (name) values ('Matthew') into t_gen_idty (name) values ('Peter') into t_gen_idty (name) values ('John') into t_gen_idty (name) values ('King') into t_gen_idty (name) values ('Freddy') 5. Select the ID and NAME columns from the table SELECT id,name FROM t_gen_idty / ID -------1 2 3 4 5 6 NAME -------------------Allen Matthew Peter John King Freddy 6 rows selected. 6. Manually, try to insert values in ID column. Oracle raises ORA-32795 to restrict manual inserts on the Identity Columns. INSERT INTO t_gen_idty VALUES (7,'Steyn'); insert into t_gen_idty values (7,'Steyn') * ERROR at line 1: ORA-32795: cannot insert into a generated always identity column
  • 8. d) SQL Pattern Matching 1. Connect to the SCOTT user in the CDB1 database [oracle@localhost ~]$ . oraenv ORACLE_SID = [noncdb] ? cdb1 The Oracle base remains unchanged with value /u01/app/oracle [oracle@localhost ~]$ sqlplus scott/tiger@pdb1 2. Create a test table for demonstration CREATE TABLE ticker (product VARCHAR2(10), tstamp DATE, price NUMBER) / 3. Populate the table TICKER with the test data INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INSERT / INTO ticker VALUES('ACME', '01-Apr-11', 12) INTO ticker VALUES('ACME', '02-Apr-11', 17) INTO ticker VALUES('ACME', '03-Apr-11', 19) INTO ticker VALUES('ACME', '04-Apr-11', 21) INTO ticker VALUES('ACME', '05-Apr-11', 25) INTO ticker VALUES('ACME', '06-Apr-11', 12) INTO ticker VALUES('ACME', '07-Apr-11', 15) INTO ticker VALUES('ACME', '08-Apr-11', 20) INTO ticker VALUES('ACME', '09-Apr-11', 24) INTO ticker VALUES('ACME', '10-Apr-11', 25) INTO ticker VALUES('ACME', '11-Apr-11', 19) INTO ticker VALUES('ACME', '12-Apr-11', 15) INTO ticker VALUES('ACME', '13-Apr-11', 25) INTO ticker VALUES('ACME', '14-Apr-11', 25) INTO ticker VALUES('ACME', '15-Apr-11', 14) INTO ticker VALUES('ACME', '16-Apr-11', 12) INTO ticker VALUES('ACME', '17-Apr-11', 14) INTO ticker VALUES('ACME', '18-Apr-11', 24) INTO ticker VALUES('ACME', '19-Apr-11', 23) INTO ticker VALUES('ACME', '20-Apr-11', 22)
  • 9. 4. Pattern matching: Look for double bottom patterns ('W' shape) SELECT product, first_x,first_y,last_w,last_z FROM Ticker MATCH_RECOGNIZE ( PARTITION BY product ORDER BY tstamp MEASURES first(X.tstamp) as first_x, first(Y.tstamp) as first_y, last(Y.tstamp) as last_y, first(W.tstamp) as last_w, last(Z.tstamp) as last_z ONE ROW PER MATCH PATTERN (X+ Y+ W+ Z+) DEFINE X AS (price < PREV(price)), Y AS (price > PREV(price)), W AS (price < PREV(price)), Z AS (price > PREV(price)AND Z.tstamp - FIRST(x.tstamp) <= 7 )) / PRODUCT FIRST_X FIRST_Y LAST_W LAST_Z ---------- --------- --------- --------- --------ACME 06-APR-11 07-APR-11 11-APR-11 13-APR-11 5. Pattern matching: Look for V-shape patterns SELECT product, start_tstamp,bottom_tstamp, end_tstamp FROM Ticker MATCH_RECOGNIZE ( PARTITION BY product ORDER BY tstamp MEASURES STRT.tstamp AS start_tstamp, LAST(DOWN.tstamp) AS bottom_tstamp, LAST(UP.tstamp) AS end_tstamp ONE ROW PER MATCH AFTER MATCH SKIP TO LAST UP PATTERN (STRT DOWN+ UP+) DEFINE DOWN AS DOWN.price < PREV(DOWN.price), UP AS UP.price > PREV(UP.price) ) MR ORDER BY MR.product, MR.start_tstamp / PRODUCT START_TST BOTTOM_TS END_TSTAM ---------- --------- --------- --------ACME 05-APR-11 06-APR-11 10-APR-11 ACME 10-APR-11 12-APR-11 13-APR-11 ACME 14-APR-11 16-APR-11 18-APR-11
  • 10. PL/SQL New features a) Using Boolean, Record and Collection type as Parameters in Subprograms Connect to the SCOTT user in the CDB1 database [oracle@localhost ~]$ . oraenv ORACLE_SID = [noncdb] ? cdb1 The Oracle base remains unchanged with value /u01/app/oracle [oracle@localhost ~]$ sqlplus scott/tiger@pdb1 i) For BOOLEAN datatype 1. Create a procedure with BOOLEAN type parameter. CREATE OR REPLACE PROCEDURE p_demo_boolean_bind (p_var IN boolean) IS BEGIN IF p_var THEN DBMS_OUTPUT.PUT_LINE('I am true'); ELSE DBMS_OUTPUT.PUT_LINE('I am false'); END IF; END; / 2. Invoke the procedure in an anonymous block using EXECUTE IMMEDIATE to pass the boolean argument as a bind variable. set serveroutput on DECLARE l_var BOOLEAN := true; BEGIN EXECUTE IMMEDIATE 'begin p_demo_boolean_bind(:1); end;' using l_var; END; / ii) For a collection type variable 1. Create a package with a local nested table collection and a member procedure which uses the local collection type as the input argument. CREATE OR REPLACE PACKAGE pkg_collection_bind IS TYPE t is table of number; PROCEDURE p_coll_bind (p_var t); END; / CREATE OR REPLACE PACKAGE BODY pkg_collection_bind IS PROCEDURE p_coll_bind (p_var t) is BEGIN FOR i in 1..p_var.count LOOP DBMS_OUTPUT.PUT_LINE('Element '||i||' is '||p_var(i)); END LOOP; END; END; /
  • 11. 2. Invoke the packaged subprogram in an anonymous block using EXECUTE IMMEDIATE to pass the collection argument as a bind variable. set serveroutput on DECLARE l_var pkg_collection_bind.t := pkg_collection_bind.t (10,20,30,40,50,60,70); BEGIN EXECUTE IMMEDIATE 'begin pkg_collection_bind.p_coll_bind(:1); end;' USING l_var; END; / b) The ACCESSIBLE BY Clause 1. Create a procedure with an ACCESSIBLE BY clause. Specify the "white list" of trusted subprograms in the clause who can invoke this procedure. However, it is not mandatory that the list of subprograms specified must exist in the schema. CREATE OR REPLACE PROCEDURE p_demo_accessible AUTHID CURRENT_USER ACCESSIBLE BY (package coll_pkg, procedure p_white_list, function f_white_list) IS BEGIN DBMS_OUTPUT.PUT_LINE('Testing ACCESSIBLE BY clause in Oracle 12c'); END; / 2. Create the "white list" procedure which invokes the above procedure. Invoke the procedure P_WHITE_LIST to verify the access to P_DEMO_ACCESSIBLE procedure. CREATE OR REPLACE PROCEDURE p_white_list is BEGIN DBMS_OUTPUT.PUT_LINE('Invoking P_DEMO_ACCESSIBLE..'); P_DEMO_ACCESSIBLE; END; / SET SERVEROUTPUT ON BEGIN p_white_list; END; / Invoking P_DEMO_ACCESSIBLE.. Testing ACCESSIBLE BY clause in oracle 12c PL/SQL procedure successfully completed. 3. Try invoking the procedure P_DEMO_ACCESSIBLE in an anonymous block. begin P_DEMO_ACCESSIBLE; end; / BEGIN P_DEMO_ACCESSIBLE; END; *
  • 12. ERROR at line 1: ORA-06550: line 1, column 7: PLS-00904: insufficient privilege to access object P_DEMO_ACCESSIBLE; ORA-06550: line 1, column 7: PL/SQL: Statement ignored c) PL/SQL functions run faster in SQL 1. Create a test table T CREATE TABLE ( PK integer n1 integer n2 integer n3 integer constraint ) / t not null, not null, not null, not null, t_PK primary key(PK) 2. Populate the table T by generating the random data using the below PL/SQL program DECLARE commit_count constant pls_integer := 100000; nof_Rows constant pls_integer := 20*commit_count; Zero constant integer not null := 0; THS constant integer not null := 1000; MIL constant integer not null := THS*THS; BIL constant integer not null := MIL*THS; TIL constant integer not null := BIL*THS; M1 constant integer not null := 2*THS; M2 constant integer not null := 2*BIL; Hi constant integer not null := 2*TIL; BEGIN DBMS_Random.Seed(To_Char(Sysdate, 'MM-DD-YYYY HH24:MI:SS')); for j in 1..Nof_Rows loop declare n1 integer not null := DBMS_Random.Value(Zero, M1); n2 integer not null := DBMS_Random.Value(M1, M2); n3 integer not null := DBMS_Random.Value(M2, Hi); begin insert into t(PK, n1, n2, n3) values(j, n1, n2, n3); end; if Mod(j, commit_count) = 0 then commit; end if; end loop; commit; END; / 3. Gather the table stats for the table T begin DBMS_Stats.Gather_Table_Stats('SCOTT', 'T'); end; /
  • 13. 4. Create the PL/SQL function logic to pretty print an integer as a multiple of appropriate unit of "Thousand", "Million","Billion" or "Trillion". We shall do this activity in different fashion to measure the compare the performance. Record the timing at each stage to do the comparison a) Using a conventional pre 12c standalone function to set the base line CREATE OR REPLACE FUNCTION F_ShowVal_pre12c(n IN integer) return varchar2 is THS constant integer not null := 1000; MIL constant integer not null := THS*THS; BIL constant integer not null := MIL*THS; TIL constant integer not null := BIL*THS; BEGIN RETURN CASE WHEN n <= 999 then To_Char(n, '999999')||' units' WHEN n/THS <= 999 then To_Char(n/THS, '999999')||' Thousand' WHEN n/MIL <= 999 then To_Char(n/MIL, '999999')||' Million' WHEN n/BIL <= 999 then To_Char(n/BIL, '999999')||' Billion' ELSE To_Char(n/TIL, '999999')||' Trillion' END; END F_ShowVal_pre12c; / SET TIMING ON SELECT F_ShowVal_pre12c(n1) n1, F_ShowVal_pre12c(n2) n2, F_ShowVal_pre12c(n3) n3 FROM t / b) Using Pure SQL SET TIMING ON SELECT PK, case case n1 n1/1000 n1/1000000 n1/1000000000 <= 999 then To_Char(n1, '999999')||' units' <= 999 then To_Char(n1/1000, '999999')||' Thousand' <= 999 then To_Char(n1/1000000, '999999')||' Million' <= 999 then To_Char(n1/1000000000, '999999')||' Billion' To_Char(n1/1000000000000, '999999')||' Trillion' when when when when Else end, case when when when when Else n2 n2/1000 n2/1000000 n2/1000000000 <= 999 then To_Char(n2, '999999')||' units' <= 999 then To_Char(n2/1000, '999999')||' Thousand' <=999 then To_Char(n2/1000000, '999999')||' Million' <=999 then To_Char(n2/1000000000, '999999')||' Billion' To_Char(n2/1000000000000, '999999')||' Trillion' when when when when Else n3 n3/1000 n3/1000000 n3/1000000000 <= 999 then To_Char(n3, '999999')||' units' <= 999 then To_Char(n3/1000, '999999')||' Thousand' <= 999 then To_Char(n3/1000000, '999999')||' Million' <= 999 then To_Char(n3/1000000000, '999999')||' Billion' To_Char(n3/1000000000000, '999999')||' Trillion' end, end FROM t / c) Declaring the PL/SQL function in the subquery's WITH clause SET TIMING ON WITH function ShowVal(n IN integer) return varchar2 is THS constant integer not null := 1000; MIL constant integer not null := THS*THS; BIL constant integer not null := MIL*THS; TIL constant integer not null := BIL*THS;
  • 14. Begin return case when n when n/THS when n/MIL when n/BIL Else end; end ShowVal; SELECT showVal(n1) n1, FROM t / <= THS-1 then To_Char(n, '999999')||' units' <= THS-1 then To_Char(n/THS, '999999')||' Thousand' <= THS-1 then To_Char(n/MIL, '999999')||' Million' <= THS-1 then To_Char(n/BIL, '999999')||' Billion' To_Char(n/TIL, '999999')||' Trillion' showVal(n2) n2, showVal(n3) n3 d) Declaring the PL/SQL function using PRAGMA UDF CREATE OR REPLACE FUNCTION F_ShowVal(n IN integer) return varchar2 is PRAGMA UDF; THS constant integer not null := 1000; MIL constant integer not null := THS*THS; BIL constant integer not null := MIL*THS; TIL constant integer not null := BIL*THS; BEGIN RETURN CASE WHEN n <= 999 then To_Char(n, '999999')||' units' WHEN n/THS <= 999 then To_Char(n/THS, '999999')||' Thousand' WHEN n/MIL <= 999 then To_Char(n/MIL, '999999')||' Million' WHEN n/BIL <= 999 then To_Char(n/BIL, '999999')||' Billion' ELSE To_Char(n/TIL, '999999')||' Trillion' END; END F_ShowVal; / SET TIMING ON SELECT F_ShowVal(n1) n1, F_ShowVal(n2) n2, F_ShowVal(n3) n3 FROM t / Record your observations from the steps (a), (b), (c) and (d) in the below matrix. Here is the performance comparison from the above scenarios Method Timing recorded Performance gains (a) Pre 12c Standalone function 565 sec (Baseline) 1X (b) Pure SQL 210 sec 2.7X (c) Using WITH clause 315 sec 1.8X (d) Using PRAGMA UDF 380 sec 1.5 X