SQL and PL/SQL. Connor McDonald 4/24/2018. The meanest, fastest thing out there. Connor McDonald

Size: px
Start display at page:

Download "SQL and PL/SQL. Connor McDonald 4/24/2018. The meanest, fastest thing out there. Connor McDonald"

Transcription

1 SQL and PL/SQL The meanest, fastest thing out there Connor McDonald 1 Copyright 2017, Oracle and/or its affiliates. All rights reserved. Connor McDonald 1

2 3 4 2

3 Typical speaker ego slide blog connor-mcdonald.com youtube tinyurl.com/connor-tube Copyright 2017, Oracle and/or its affiliates. All rights reserved. asktom.oracle.com 6 3

4 7 why talk about this? # 1 8 4

5 after all

6 NoSQL non relational

7 why talk about this # 2 13 What is cool nowadays 14 7

8 MICROSERVICES 15 SQL invented cool 16 8

9 "fine-grained to perform a single function" "Each service is... minimal, and complete" select COUNT(*) from PEOPLE where GENDER = 'MALE' 17 What is cooler nowadays 18 9

10 API 19 "By abstracting the underlying implementation" "describes the expected behaviour... but can have multiple implementations" procedure MY_PROC is begin open rc for end; select NAME, STREET_NO, ZIP_CODE from PEOPLE p, ADDRESS a where p.age > 50 and p.address_id = a.address_id;

11 key point 21 this session is about

12 18c "new" features 23 18c 11g 12c 24 12

13 this session is not about

14 being a smart-ass 27 we can do anything

15 SQL> with x( s, ind ) as 2 ( select sud, instr( sud, '.' ) 3 from ( select replace(replace( 4 replace(replace(:board,'-'),' '),' '),chr(10)) sud 5 from dual ) 6 union all 7 select substr(s,1,ind-1) z substr(s,ind+1) 8, instr(s,'.',ind+1) 9 from x 10, ( select to_char( rownum ) z 11 from dual connect by rownum <= 9 ) z 12 where ind > 0 13 and not exists ( 14 select null 15 from ( select rownum lp from dual 16 connect by rownum <= 9 ) 17 where z = substr(s,trunc((ind-1)/9)*9+lp,1) or z = substr(s,mod(ind-1,9)-8+lp*9,1) 19 or z = substr(s,mod(trunc((ind-1)/3),3)*3 20 +trunc((ind-1)/27)*27+lp 21 +trunc((lp-1)/3)*6,1) 22 ) 23 ), 24 result as ( 25 select s 26 from x 27 where ind = 0 ) 28 select 29 regexp_replace(substr(s,(idx-1)*9+1,9), 30 '(...)(...)(...)', 31 '\1 \2 \3') 32 case when mod(idx,3)=0 then chr(10) rpad('-',11,'-') end soln 33 from result, 34 ( select level idx 35 from dual 36 connect by level <= 9 ) Ack: Anton Scheffer, 15

16 SQL> variable board varchar2(1000) SQL> begin :board := 2 ' '; 14 end; SOLUTION sud.sql 32 16

17 100% % of developers that will need to solve Sudoku as part of their job % % of developers that need to get real sh#@t done 34 17

18 real stuff

19 some controversy DBA 38 19

20 Public 40 20

21 Public 41 DBA stuff matters oc00.sql 42 21

22 2 43 PL/SQL resolved expressions 44 22

23 12c+ 45 longer names 46 23

24 SQL> create table MY_TABLE 2 ( 3 MY_COLUMN_IS_BETTER_BECAUSE_IT_NOW_HAS_MORE_MEANING DATE 4 ); Table created

25 SQL> create or replace 2 procedure process_tab is 3 l_tab varchar2(30); 4 begin 5 select table_name 6 into l_tab 7 from user_tables 8 where... SQL> exec process_tab; ORA-06502: PL/SQL: numeric or value error: character string buffer too small 25

26 expression in place of literal 52 26

27 SQL> declare 2 c_var_length constant pls_integer := 30; 3 l_str varchar2(c_var_length); 4 begin 5 null; 6 end; 7 / PL/SQL procedure successfully completed. SQL must be resolvable at compile time function 54 27

28 SQL> declare 2 c_var_length constant pls_integer := to_number('30'); 3 l_str varchar2(c_var_length); 4 begin 5 null; 6 end; 7 / l_str varchar2(c_var_length); * ERROR at line 3: ORA-06550: line 3, column 25: PLS-00491: numeric literal required SQL> declare 2 c_var_length constant pls_integer := 30; 3 l_str varchar2(c_var_length); 28

29 SQL> create or replace 2 procedure process_tab is 3 l_str varchar2(ora_max_name_len); 4 begin start today 58 29

30 SQL> create or replace 2 procedure process_tab is 3 4 $if DBMS_DB_VERSION.VER_LE_12_1 $then 5 l_str varchar2(30); 6 $else 7 l_str varchar2(ora_max_name_len); 8 $end 9 10 begin "Wasn't I just supposed to use..." 60 30

31 user_tables.table_name%type yes... but 62 31

32 SQL> create or replace 2 procedure process_tab is 3 l_str varchar2( ); 4 begin 5 select owner '.' table_name 6 into l_str 7 from all_tables 8 where... 9? SQL> create or replace 2 procedure process_tab is 3 l_str varchar2(2*ora_max_name_len+1); 4 begin 5 select owner '.' table_name 6 into l_str 7 from all_tables 8 where

33 3 65 So... let's try that again 66 33

34 longer names 67 compile time resolvable sizes 68 34

35

36

37 73 SQL> desc STORE_SALES Name Type SALES_PK NUMBER(38) DATE_AT_WHICH_CUSTOMER_CAME_INTO_THE_STOP DATE DATE_AT_WHICH_CUSTOMER_CAME_LEFT_THE_STOP DATE DURATION_CUSTOMER_SPENT_BROWSING_SALES_CATALOG_BEFORE_ASKING_FOR_ASSISTANCE_MINS NUMBER(38) ITEM_THAT_CUSTOMER_PURCHASED VARCHAR2(50) AMOUNT_CUSTOMER_TENDERED_TO_CASHIER_IN_50DOLLAR_NOTES NUMBER(38) AMOUNT_CUSTOMER_TENDERED_TO_CASHIER_IN_20DOLLAR_NOTES NUMBER(38) AMOUNT_CUSTOMER_TENDERED_TO_CASHIER_IN_10DOLLAR_NOTES NUMBER(38) AMOUNT_CUSTOMER_TENDERED_TO_CASHIER_IN_5DOLLAR_NOTES NUMBER(38) AMOUNT_CUSTOMER_TENDERED_TO_CASHIER_IN_COINS_IN_TOTAL_CENTS NUMBER(38) LENGTH_IN_MILLIMETERS_OF_THE_RECEIPT_WE_PRINTED_FOR_THE_CUSTOMER NUMBER(38) AVERAGE_LENGTH_OF_SHOELACE_OF_STORE_ASSISTANT_THAT_HELPED_THE_CUSTOMER NUMBER(38)

38 SQL> select table_name, 2 listagg(column_name, ',') within group 3 (order by column_id) cols 4 from user_tab_columns 5 group by table_name; * ERROR at line 1: ORA-01489: result of string concatenation is too long tough to solve 76 38

39 SQL> select 2 column_name, 3 ( select listagg(column_name,',') within group ( order by column_id ) 4 from all_tab_columns 5 where table_name = 'EMP' 6 and owner = 'SCOTT' 7 and column_id <= a.column_id ) cols 8 from all_tab_columns a 9 where table_name = 'EMP' 10 and owner = 'SCOTT' 11 order by column_id; COLUMN_NAME COLS EMPNO EMPNO ENAME EMPNO,ENAME JOB EMPNO,ENAME,JOB MGR EMPNO,ENAME,JOB,MGR HIREDATE EMPNO,ENAME,JOB,MGR,HIREDATE SAL EMPNO,ENAME,JOB,MGR,HIREDATE,SAL COMM EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM DEPTNO EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO 8 rows selected. first principles pipeline function 78 39

40 improved overflow handling 80 40

41 SQL> select table_name, 2 listagg(column_name, ',' on overflow truncate) 3 within group (order by column_id) cols 4 from user_tab_columns 5 group by table_name; TABLE_NAME COLS STORE_SALES SALES_PK,DATE_AT_WHICH_CUSTOMER_CAME_INTO_THE_STOP,DATE_AT_W HICH_CUSTOMER_CAME_LEFT_THE_STOP,DURATION_CUSTOMER_SPENT_BRO WSING_SALES_CATALOG_BEFORE_ASKING_FOR_ASSISTANCE_IN_MINS,ITE,LENGTH_IN_MILLIMETERS_OF_THE_RECEIPT_WE_PRINTED_FOR_THE_CUS [snip] TIME_SPENT_WHILST_REFOLDING_ITE...(2378) plus you get control 82 41

42 SQL> select table_name, 2 listagg(column_name, ',' on overflow truncate '[more]') 3 within group (order by column_id) cols 4 from user_tab_columns 5 group by table_name; TABLE_NAME COLS STORE_SALES SALES_PK,DATE_AT_WHICH_CUSTOMER_CAME_INTO_THE_STOP,DATE_AT_W HICH_CUSTOMER_CAME_LEFT_THE_STOP,DURATION_CUSTOMER_SPENT_BRO WSING_SALES_CATALOG_BEFORE_ASKING_FOR_ASSISTANCE_IN_MINS,ITE,LENGTH_IN_MILLIMETERS_OF_THE_RECEIPT_WE_PRINTED_FOR_THE_CUS [snip] TIME_SPENT_WHILST_REFOLDING_ITE[more](2378) SQL> select table_name, 2 listagg(column_name,',' 3 on overflow truncate '[more]' without count) 4 within group (order by column_id) cols 5 from user_tab_columns 6 group by table_name; TABLE_NAME COLS STORE_SALES SALES_PK,DATE_AT_WHICH_CUSTOMER_CAME_INTO_THE_STOP,DATE_AT_W HICH_CUSTOMER_CAME_LEFT_THE_STOP,DURATION_CUSTOMER_SPENT_BRO WSING_SALES_CATALOG_BEFORE_ASKING_FOR_ASSISTANCE_IN_MINS,ITE,LENGTH_IN_MILLIMETERS_OF_THE_RECEIPT_WE_PRINTED_FOR_THE_CUS [snip] TIME_SPENT_WHILST_REFOLDING_ITE[more] 42

43 SQL> select table_name, 2 listagg(column_name,',' 3 on overflow truncate '' without count) 4 within group (order by column_id) cols 5 from user_tab_columns 6 group by table_name; TABLE_NAME COLS STORE_SALES SALES_PK,DATE_AT_WHICH_CUSTOMER_CAME_INTO_THE_STOP,DATE_AT_W HICH_CUSTOMER_CAME_LEFT_THE_STOP,DURATION_CUSTOMER_SPENT_BRO WSING_SALES_CATALOG_BEFORE_ASKING_FOR_ASSISTANCE_IN_MINS,ITE,LENGTH_IN_MILLIMETERS_OF_THE_RECEIPT_WE_PRINTED_FOR_THE_CUS [snip] TIME_SPENT_WHILST_REFOLDING_ITE

44 column level collation 87 every system... 44

45 ... I've worked on 89 struggles with case 45

46 no correlation but its my fault 91 SQL> select surname 2 from names; SURNAME jones brown SMITH sigh... 46

47 SQL> select initcap(surname) 2 from names; SURNAME Jones Brown Smith Mcdonald and it just gets worse

48 SQL> select * 2 from customers 3 where cust_name = 'ADAMS'; COUNTRY CREATED CUST_NAME AUS 07-NOV-16 ADAMS SQL> select * 2 from customers 3 where upper(cust_name) = 'ADAMS'; COUNTRY CREATED CUST_NAME AUS 07-NOV-16 Adams AUS 07-NOV-16 ADAMS AUS 07-NOV-16 adams 48

49 97 SQL> select * from customers 2 where upper(cust_name) = 'ADAMS'; 98 49

50 99 SQL> select column_name 2 from user_ind_columns 3 where index_name = 'CUST_IX'; COLUMN_NAME CUST_NAME SQL> select * from customers 2 where upper(cust_name) = 'ADAMS'; Id Operation Name Rows Bytes SELECT STATEMENT * 1 TABLE ACCESS FULL CUSTOMERS

51 SQL> create index cust_ix 2 on customers ( cust_name ); Index created. SQL> create index cust_ix2 2 on customers ( upper(cust_name) ); Index created. DML slower more contention more redo/undo

52 "not my problem"

53 SQL> alter table customers shrink space; * ERROR at line 1: ORA-10631: SHRINK clause should not be specified a better way

54 column level collation ? 54

55 SQL> CREATE TABLE CUSTOMERS 2 ( 3 COUNTRY VARCHAR2(128), 4 CREATED DATE, 5 CUST_NAME VARCHAR2(150) COLLATE BINARY_CI 6 ); Table created. "case insenstive" SQL> create index cust_ix 2 on customers ( cust_name); Index created. SQL> set autotrace traceonly explain SQL> select * from customers 2 where cust_name = 'ADAMS'; Id Operation Name Rows SELECT STATEMENT 1 1 TABLE ACCESS BY INDEX ROWID BATCHED CUSTOMERS 1 * 2 INDEX RANGE SCAN CUST_IX

56 "big deal" 111 SQL> select * from customers 2 where cust_name = 'ADAMS'; COUNTRY CREATED CUST_NAME AUS 07-NOV-16 Adams AUS 08-NOV-16 ADAMS AUS 09-NOV-16 adams 56

57 binary_ci SQL> select * from customers 2 where cust_name = 'ADAMS'; COUNTRY CREATED CUST_NAME AUS 07-NOV-16 Adams AUS 08-NOV-16 ADAMS AUS 09-NOV-16 adams 113 binary_ai SQL> select * from customers 2 where cust_name = 'ADAMS'; COUNTRY CREATED CUST_NAME AUS 07-NOV-16 Adams AUS 08-NOV-16 ADAMS AUS 09-NOV-16 adams AUS 10-NOV-16 adáms adáms

58 column table user 115 SQL> alter table people default collation binary_ai; new columns only 58

59 key point 117 SQL> alter table people default collation binary_ai; * ERROR at line 1: ORA-43929: Collation cannot be specified if parameter MAX_STRING_SIZE=STANDARD 59

60 5 119 deprecating code

61 121 SQL> create or replace 2 package customer_pkg as 3 4 cursor get_customers(p_name varchar2) is 5 select * from customers 6 where upper(customer_name) = upper(p_name);

62 SQL> create or replace 2 package customer_pkg as do not use cursor get_customers(p_name varchar2) is 8 select * from customers 9 where upper(customer_name) = upper(p_name); fixed with CI collation cursor get_cust_ci(p_name varchar2) is 15 select * from customers 16 where customer_name = p_name;

63 use a pragma 125 SQL> create or replace 2 package customer_pkg as 3 cursor get_customers(p_name varchar2) is 4 select * from customers 5 where upper(customer_name) = upper(p_name); 6 7 pragma deprecate(get_customers,'use get_cust_ci'); 8 9 cursor get_cust_ci(p_name varchar2) is 10 select * from customers 11 where customer_name = p_name; 63

64 SQL> alter system set 2 plsql_warnings = enable:(6019,6020,6021,6022)'; SQL> alter procedure PROCESS_CUSTOMERS compile; SP2-0804: Procedure created with compilation warnings LINE/COL ERROR /1 PLW-05018: unit PROCESS_CUSTOMERS omitted optional AUTHID clause; default value DEFINER used 7/9 PLW-06020: reference to a deprecated entity: GET_CUSTOMERS declared in unit CUSTOMER_PKG[2,10]. Use get_cust_ci instead 8/9 PLW-06020: reference to a deprecated entity: 64

65 one month later

66 SQL> alter system set 2 plsql_warnings = error:(6019,6020,6021,6022)'; SQL> alter procedure PROCESS_CUSTOMERS compile; SP2-0804: Procedure created with compilation errors LINE/COL ERROR /1 PLW-05018: unit PROCESS_CUSTOMERS omitted optional AUTHID clause; default value DEFINER used 7/9 PLW-06020: reference to a deprecated entity: GET_CUSTOMERS declared in unit CUSTOMER_PKG[2,10]. Use get_cust_ci instead 8/9 PLW-06020: reference to a deprecated entity: 66

67

68 135 R E S T J S O N

69 {"stuff": { "id": "123", "description": "File", "checkout": { "metadata": [ {"created": " "}, ] } "checkin": { "metadata": [ {"updated": " :02:12"}, {"review": "TODAY+7"} ] } }} 137 {"stuff": { "id": "123", "description": "File", "checkout": { "metadata": [ {"created": " "}, ] } "checkin": { "metadata": [ {"updated": " :02:12"}, {"review": "TODAY+7"} ] } }}

70 {"stuff": { "id": "123", "description": "File", "checkout": { "metadata": [ {"created": " "}, ] } "checkin": { "metadata": [ {"updated": " :02:12"}, {"review": "TODAY+7"} ] } }}

71 pessimistic with data 141 SQL> select TO_DATE(CREATED_DATE) 2 from MY_JSON_AS_TABLE; ERROR at line 1: ORA-01858: a non-numeric character was found... SQL> select TO_DATE(CREATED_DATE) 2 from MY_JSON_AS_TABLE; 3 where???? MY_PLSQL_CHECKER(CREATED_DATE) = 'OK'

72 DBA 143 DBA

73 "don't call PLSQL from SQL!!!!" 145 validate_conversion

74 SQL> select CREATED_DATE 2 from MY_JSON_AS_TABLE; CREATED_DATE FEB MAR AUG SEP OCT SQL> select to_date(created_date, 'dd-mon-yyyy') 2 from MY_JSON_AS_TABLE 3 where validate_conversion( 4 created_date as date, 'dd-mon-yyyy' 5 ) = 1; TO_DATE(C FEB MAR SEP OCT

75 CAST extended 149 SQL> select SALARY, 2 cast(salary as number 3 DEFAULT -1 ON CONVERSION ERROR) conv_sal 4 from MY_JSON_AS_TABLE; SALARY CONV_SAL , TO_DATE TO_NUMBER TO_TIMESTAMP etc

76 select raw_data, TO_UTC_TIMESTAMP_TZ(raw_data) as utc from t; RAW_DATA UTC T07:14:47 22-NOV AM +00:00 18c improvements

77 partitioned outer join 153 SQL> select * 2 from timeslots; HR SQL> select * 2 from bookings; HR ROOM WHO Room2 PETE 9 Room1 JOHN 11 Room1 MIKE 14 Room2 JILL 15 Room2 JANE 16 Room1 SAM

78 bookings by hour conventional outer join 155 SQL> SELECT hrs.hr, t1.room, t1.who 2 from timeslots hrs 3 left outer join bookings t1 4 on hrs.hr = t1.hr HR ROOM WHO Room2 PETE 9 Room1 JOHN Room1 MIKE Room2 JILL 15 Room2 JANE 16 Room1 SAM

79 bookings by hour per room 157 HR ROOM WHO Room1 JOHN Room1 MIKE Room1 SAM HR ROOM WHO Room2 PETE Room2 JILL 15 Room2 JANE

80 SQL> select * 2 from timeslots; HR x "Room 1" x "Room 2"... x "Room n" 159 partitioned outer join

81 SQL> SELECT hrs.hr, t1.room, t1.who 2 FROM bookings t1 3 PARTITION BY (t1.room) 4 RIGHT OUTER JOIN hrs ON (hrs.hr = t1.hr); HR ROOM WHO Room1 9 Room1 JOHN 10 Room1 11 Room1 MIKE 12 Room1 13 Room1 14 Room1 15 Room1 16 Room1 SAM 8 Room2 PETE 9 Room2 10 Room2 11 Room2 12 Room2 13 Room2 14 Room2 JILL 15 Room2 JANE 16 Room

82 pagination 163 "employees by hiredate, recent first"

83 SQL> select empno, ename, hiredate 2 from emp 3 where rownum <= 5 4 order by hiredate desc; EMPNO ENAME HIREDATE MARTIN 28/09/ :00: JONES 02/04/ :00: WARD 22/02/ :00: ALLEN 20/02/ :00: SMITH 17/12/ :00: inline view

84 SQL> select * 2 from ( 3 select empno, ename, hiredate 4 from emp 5 order by hiredate desc 6 ) 7 where rownum <= 5; EMPNO ENAME HIREDATE ADAMS 12-JAN SCOTT 09-DEC MILLER 23-JAN JAMES 03-DEC FORD 03-DEC SQL> select * 2 from ( 3 select 4 empno, ename, hiredate, 5 row_number() over ( order by hiredate desc) rn 6 from emp 7 ) 8 where rn <= 5;

85 SQL> select empno, ename, hiredate 2 from emp 3 order by hiredate desc 4 fetch first 5 rows only; EMPNO ENAME HIREDATE ADAMS 12-JAN SCOTT 09-DEC MILLER 23-JAN JAMES 03-DEC FORD 03-DEC "TL;DR... my app can do it"

86 public static void Paging(Connection conn ) throws Exception { PreparedStatement sql_stmt = conn.preparestatement( "select empno, ename, hiredate from emp order by hiredate desc"); } ResultSet rset = sql_stmt.executequery(); int i = 0; while( rset.next() ) {... i = i + 1; if (i > 5) { break; } } rset.close(); 171 "TL;DR... Apex can do it"

87 173 87

88 demo oc01.sql 175 let the database know

89 SQL> select * 2 from ( 3 select empno, ename, hiredate 4 from emp 5 order by hiredate desc ) Id Operation Name Rows 7 where rownum <= 5; SELECT STATEMENT 5 * 1 COUNT STOPKEY 2 VIEW 14 * 3 SORT ORDER BY STOPKEY 14 4 TABLE ACCESS FULL EMP SQL> select empno, ename, hiredate 2 from emp 3 order by hiredate desc 4 fetch first 5 rows only; Id Operation Name Rows SELECT STATEMENT 14 * 1 VIEW 14 * 2 WINDOW SORT PUSHED RANK 14 3 TABLE ACCESS FULL EMP

90 you get other benefits oc02.sql 179 "but what about the next page?"

91 there is no next page 181 new query

92 SQL> select empno, ename, hiredate 2 from emp 3 order by hiredate desc 4 offset 5 rows fetch first 5 rows only; EMPNO ENAME HIREDATE KING 17-NOV MARTIN 28-SEP TURNER 08-SEP CLARK 09-JUN BLAKE 01-MAY forget the OFFSET clause

93 SQL> select empno, ename, hiredate 2 from emp 3 order by hiredate desc; HIREDATE EMPNO ENAME FEB BROWN 12-JAN ADAMS 09-DEC SCOTT 23-JAN MILLER 03-DEC FORD 03-DEC JAMES 17-NOV KING 28-SEP MARTIN 08-SEP TURNER 09-JUN CLARK 01-MAY BLAKE 02-APR JONES 22-FEB WARD 20-FEB ALLEN 17-DEC SMITH fetch first 5 rows offset 5 fetch next... Apex 185 SQL> select empno, ename, hiredate 2 from emp 3 order by hiredate desc; HIREDATE EMPNO ENAME FEB BROWN 12-JAN ADAMS 09-DEC SCOTT 23-JAN MILLER 03-DEC FORD 03-DEC JAMES 17-NOV KING 28-SEP MARTIN 08-SEP TURNER 09-JUN CLARK 01-MAY BLAKE 02-APR JONES 22-FEB WARD 20-FEB ALLEN 17-DEC SMITH SQL> select empno, ename, hiredate 2 from emp 3 where hiredate < :last_shown 3 order by hiredate desc;

94 "an expensive query per page?!?! 187 consider result caching

95 SQL> with first_200 as 2 ( select f.*, /*+ result_cache rownum r */ rownum r, f.* 3 from 4 ( select * 5 from t 6 order by owner, object_name desc 7 ) f 8 where rownum <= ) 10 select * 11 from first_ where r between <= and 20 oc03.sql 189 Classic IR IG Apex <=

96 Classic IR IG Apex nearly

97 totals / subtotals 193 "Employee salary list, plus department total, plus grand total"

98

99 select deptno, ename, sal from emp order by 1,2 call count cpu elapsed disk query current rows Parse Execute Fetch total fixed requirement

100 SQL> select empno, ename, sal, deptno from emp 2 order by deptno; EMPNO SQL> ENAME select deptno, SAL DEPTNO sum(sal) CLARK 3 from emp KING 4 group by deptno MILLER 5 order by deptno; JAMES DEPTNO SUM(SAL) BLAKE MARTIN SQL> 10 select 8750 sum(sal) 1250 from 30 emp; SUM(SAL) from 3 to 2 rollup

101 SQL> select empno, ename, sal, deptno from emp 2 order by deptno; EMPNO ENAME SAL DEPTNO SQL> select deptno, CLARK 2 sum(sal) KING 3 from emp MILLER 4 group by rollup(deptno) order by deptno; 7900 JAMES BLAKE DEPTNO SUM(SAL) MARTIN still messy

102 EMPNO SAL DEPTNO DEPTNO SUM(SAL) from 2 to

103 SQL> select deptno, 2 nvl2(rownum,max(empno),null) empno, 3 nvl2(rownum,max(ename),null) ename, 4 sum(sal) 5 from emp 6 group by rollup(deptno,rownum) 7 order by deptno,empno; 205 DEPTNO EMPNO ENAME SUM(SAL) CLARK KING MILLER SMITH JONES JAMES the whole lot!

104 SQL> select deptno,job,sum(sal) from scott.emp 2 group by CUBE(deptno,job) 3 order by deptno,job; 207 DEPTNO JOB SUM(SAL) CLERK MANAGER PRESIDENT ANALYST CLERK MANAGER CLERK MANAGER SALESMAN ANALYST 6000 CLERK 4150 MANAGER 8275 PRESIDENT 5000 SALESMAN totally customisable

105 SQL> select deptno, job, mgr, sum(sal) from emp 2 group by grouping sets ( 3 (deptno), 4 (job,mgr), () ) ; DEPTNO JOB MGR SUM(SAL) CLERK PRESIDENT 5000 CLERK CLERK CLERK SALESMAN MANAGER ANALYST last

106 211 "talking" to your database... makes it faster

107 example 213 STORES CUSTOMERS SALES

108 hash outer join? nested loop? select prod_id, max(amount) from stores st, customers c, sales s where s.cust_id = c.cust_id(+) and c.store_id = st.store_id and s.amount > 10 group by prod_id STORES first? sort merge? Id Operation Name Rows SELECT STATEMENT HASH GROUP BY 100 * 2 HASH JOIN 990K 3 NESTED LOOPS SEMI TABLE ACCESS FULL CUSTOMERS 5000 * 5 INDEX UNIQUE SCAN STORE_IX 50 * 6 TABLE ACCESS FULL SALES 990K

109 add indexes? rewrite query? can we do better? result cache? materialized view? 217 share your knowledge with the db oc04.sql

110 wrap up 219 SQL and PL/SQL

111 very cool 221 very powerful

112 less code 223 never too early to start

113 Enjoy the conference!!! blog connor-mcdonald.com youtube tinyurl.com/connor-tube 113