Your SlideShare is downloading. ×
  • Like
  • Save
Oracle Database 12c Application Development
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Oracle Database 12c Application Development

  • 298 views
Published

Oracle Database 12c Application Development New Features. Includes scripts on SQL and PL/SQL New features.

Oracle Database 12c Application Development New Features. Includes scripts on SQL and PL/SQL New features.

Published in Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
298
On SlideShare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
1
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 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