SlideShare a Scribd company logo
1
Connor McDonald
bit.ly/techguysong
2 2
3 3
4 4
5
Stuff
youtube bit.ly/youtube-connor
blog connor-mcdonald.com
twitter @connor_mc_d
400+ posts mainly on database & development
300+ technical videos, new uploads every week
rants and raves on tech and the world :-)
6
etc...
facebook bit.ly/facebook-connor
linkedin bit.ly/linkedin-connor
instagram bit.ly/instagram-connor
slideshare bit.ly/slideshare-connor
7 7https://asktom.oracle.com
10
SO
THE
BIG
QUESTION
IS
16
17
why talk about SQL ?
18
it is old !
19
20
why talk about SQL # 1
21
NoSQL
non relational
22
23
why talk about SQL # 2
24
developers love cool stuff
25
MICROSERVICES
26
SQL is microservices !
27
"fine-grained to perform a single function"
"Each service is ... minimal, and complete"
https://en.wikipedia.org/wiki/Microservices
select COUNT(*)
from PEOPLE
where GENDER = 'MALE'
28
even cooler stuff
29
API
30
SQL is entirely APIs !
31
"By abstracting the underlying implementation"
"describes the expected behaviour ...
but can have multiple implementations"
https://en.wikipedia.org/wiki/Application_programming_interface
select NAME, STREET_NO, ZIP_CODE
from PEOPLE p,
ADDRESS a
where p.AGE > 50
and p.ADDRESS_ID = a.ADDRESS_ID;
40
key point
41
this session is not about ...
42
being a smart-ass
43
we can do anything ...
44
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)
45
18 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,
https://technology.amis.nl
46
SQL> variable board varchar2(1000)
SQL> begin :board :=
2 '53.|.7.|...
3 6..|195|...
4 .98|...|.6.
5 -----------
6 8..|.61|..3
7 4..|8.3|..1
8 7..|.2.|..6
9 -----------
10 .6.|...|28.
11 ...|419|..5
12 ...|.8.|.79
13 ';
14 end;
5 3 7
6 1 9 5
9 8 6
8 6 1 3
4 8 3 1
7 2 6
6 2 8
4 1 9 5
8 7 9
47
SOLUTION
-----------
534|678|912
672|195|348
198|342|567
-----------
859|761|423
426|853|791
713|924|856
-----------
961|537|284
287|419|635
345|286|179
-----------
sud.sql
48
100%
% of developers that
will need to solve Sudoku
as part of their job
49
100%
% of developers that need
to get real s*#t done
50
real stuff
51
52
some controversy...
DBA
54
55
Public
56
Public
57
DBA friendship is important
oc00.sql
58
59
query block naming
60
C#, C++ ESB Tuxedo
Weblogic
Stored
Procedure
61
for (int i = 0; i < WinningCombinations.Count; ++i)
{
if (WinningCombinations[i].Investment > 0 &&
WinningCombinations[i].PrimaryDividend > MinDividendDeadHeat)
{
maxDivisor =
Math.Max(maxDivisor, WinningCombinations[i].Divisor);
}
}
for (int i = 0; i < WinningCombinations.Count; ++i)
{
if (WinningCombinations[i].Investment > 0 &&
WinningCombinations[i].PrimaryDividend > MinDividendDeadHeat)
{
WinningCombinations[i].Divisor =
maxDivisor / WinningCombinations[i].Divisor;
sumNewDivisors += WinningCombinations[i].Divisor;
}
}
62
no comments
UKOUG 2019 - SQL features
64
"C# is self-documenting"
65
SQL can be complex
66
SQL should "self
document"
67
query blocks = self-documenting SQL
68
select emp.*
from emp,
( select trunc(hiredate,'YYYY'), max(empno) empno
from emp
where empno > 0
group by trunc(hiredate,'YYYY') ) x,
( select deptno, avg(sal)
from emp
group by deptno ) y
where x.empno = emp.empno
and y.deptno = emp.deptno
69
Id | Operation | Name |
----------------------------------------------|
0 | SELECT STATEMENT | |
1 | HASH JOIN | |
2 | TABLE ACCESS BY INDEX ROWID | EMP |
3 | NESTED LOOPS | |
4 | VIEW | |
5 | SORT GROUP BY | |
6 | TABLE ACCESS BY INDEX ROWID| EMP |
7 | INDEX FULL SCAN | E2 |
8 | INDEX RANGE SCAN | E1 |
9 | VIEW | |
10 | SORT GROUP BY | |
11 | TABLE ACCESS BY INDEX ROWID | EMP |
12 | INDEX RANGE SCAN | E2 |
70
select emp.*
from emp,
( select trunc(hiredate,'YYYY'), max(empno) empno
from emp
where empno > 0
group by trunc(hiredate,'YYYY') ) x,
( select deptno, avg(sal)
from emp
group by deptno ) y
where x.empno = emp.empno
and y.deptno = emp.deptno
Id | Operation | Name |
----------------------------------------------|
0 | SELECT STATEMENT | |
1 | HASH JOIN | |
2 | TABLE ACCESS BY INDEX ROWID | EMP |
3 | NESTED LOOPS | |
4 | VIEW | |
5 | SORT GROUP BY | |
6 | TABLE ACCESS BY INDEX ROWID| EMP |
7 | INDEX FULL SCAN | E2 |
8 | INDEX RANGE SCAN | E1 |
9 | VIEW | |
10 | SORT GROUP BY | |
11 | TABLE ACCESS BY INDEX ROWID | EMP |
12 | INDEX RANGE SCAN | E2 |
71
select emp.*
from emp,
( select /*+ QB_NAME(YR_HIRE) */
trunc(hiredate,'YYYY'), max(empno) empno
from emp
where empno > 0
group by trunc(hiredate,'YYYY') ) x,
( select /*+ QB_NAME(AV_SAL) */
deptno, avg(sal)
from emp
group by deptno ) y
where x.empno = emp.empno
and y.deptno = emp.deptno
72
Id | Operation | Name | Query Block
----------------------------------------------|--------------
0 | SELECT STATEMENT | |
1 | HASH JOIN | |
2 | TABLE ACCESS BY INDEX ROWID | EMP |
3 | NESTED LOOPS | |
4 | VIEW | |
5 | SORT GROUP BY | |
6 | TABLE ACCESS BY INDEX ROWID| EMP |
7 | INDEX FULL SCAN | E2 |
8 | INDEX RANGE SCAN | E1 |
9 | VIEW | |
10 | SORT GROUP BY | |
11 | TABLE ACCESS BY INDEX ROWID | EMP |
12 | INDEX RANGE SCAN | E2 |
SEL$1
SEL$1
AV_SAL
AV_SAL
AV_SAL
AV_SAL
SEL$1
YR_HIRE
YR_HIRE
YR_HIRE
YR_HIRE
73
74
error logging
75
SQL> insert into MY_TABLE
2 select *
3 from MY_HUGE_GREAT_FAT_TABLE;MY_HUGE_GREAT_FAT_TABLE;
76
77
78
79
80
81
SQL> insert into MY_TABLE
2 select *
3 from MY_HUGE_GREAT_FAT_TABLE;
Elapsed: 06:12:34.00
82
SQL> insert into MY_TABLE
2 select *
3 from MY_HUGE_GREAT_FAT_TABLE;
Elapsed: 06:12:34.00
ERROR at line 1:
ORA-01847: day of month must be between 1 and last day of month
83
83
oooooooo !
84
84
85
and then we do this :-)
86
SQL> select count(*) from MY_TABLE;
COUNT(*)
----------
0
87
what we would like
88
keep successful rows
89
skip / bypass bad rows
90
hard
91
SQL> insert into MY_TABLE
2 select *
3 from MY_HUGE_GREAT_FAT_TABLE
4 where "not a duplicate"
5 and "datatypes are ok"
6 and "foreign keys are ok"
7 and "check constraints are ok"
92
SQL> exec DBMS_ERRLOG.CREATE_ERROR_LOG('EMP')
93
ERR$_EMP
94
DBMS_ERRLOG.CREATE_ERROR_LOG (
dml_table_name IN VARCHAR2,
err_log_table_name IN VARCHAR2 := NULL,
err_log_table_owner IN VARCHAR2 := NULL,
...
95
SQL> desc ERR$_EMP
Name Null? Type
----------------------------- -------- ----------------
ORA_ERR_NUMBER$ NUMBER
ORA_ERR_MESG$ VARCHAR2(2000)
ORA_ERR_ROWID$ ROWID
ORA_ERR_OPTYP$ VARCHAR2(2)
ORA_ERR_TAG$ VARCHAR2(2000)
EMPNO VARCHAR2(4000)
ENAME VARCHAR2(4000)
JOB VARCHAR2(4000)
MGR VARCHAR2(4000)
HIREDATE VARCHAR2(4000)
SAL VARCHAR2(4000)
COMM VARCHAR2(4000)
DEPTNO VARCHAR2(4000)
96
96
97
example
98
add to EMP from NEW_DATA
99
SQL> select * from NEW_DATA;
EMPNO SAL DEPTNO
---------- ---------- ----------
1000 5000 20
100X 3550 10
2000 2500 50
7934 4000 20
non-numeric
no dept 50
duplicate
100
SQL> exec dbms_errlog.create_error_log('EMP');
PL/SQL procedure successfully completed.
SQL> insert into EMP (empno,sal,deptno)
2 select empno,sal,deptno
3 from NEW_DATA
4 LOG ERRORS REJECT LIMIT UNLIMITED;
1 row created.
50
101
SQL> select ORA_ERR_OPTYP$ op, ORA_ERR_MESG$, EMPNO
2 from ERR$_EMP
OP ORA_ERR_MESG$ EMPNO
-- ------------------------------------------------------------ -----
I ORA-01722: invalid number 100X
I ORA-02291: integrity constraint (SCOTT.FK_DEPTNO) violated 2000
I ORA-00001: unique constraint (SCOTT.PK_EMP) violated 7934
102
103
partitioned outer join
104
104
SQL> select *
2 from timeslots;
HR
--
8
9
10
11
12
13
14
15
16
SQL> select *
2 from bookings;
HR ROOM WHO
------- ---------- -------
8 Room2 PETE
9 Room1 JOHN
11 Room1 MIKE
14 Room2 JILL
15 Room2 JANE
16 Room1 SAM
105
bookings by hour
conventional outer join
106
SQL> SELECT hrs.hr, t1.room, t1.who
2 from timeslots hrs
3 left outer join bookings t1
4 on hrs.hr = t1.hr
5 order by 1
HR ROOM WHO
------- ---------- ----------
8 Room2 PETE
9 Room1 JOHN
10
11 Room1 MIKE
12
13
14 Room2 JILL
15 Room2 JANE
16 Room1 SAM
107
bookings by hour per room
108
HR ROOM WHO
------- ---------- ----------
8 Room2 PETE
9
10
11
12
13
14 Room2 JILL
15 Room2 JANE
16
HR ROOM WHO
------- ---------- ----------
8
9 Room1 JOHN
10
11 Room1 MIKE
12
13
14
15
16 Room1 SAM
109
SQL> select *
2 from timeslots;
HR
--
8
9
10
11
12
13
14
15
16
x "Room 1"
x "Room 2"
...
x "Room n"
110
partitioned outer join
111
SQL> SELECT hrs.hr, t1.room, t1.who
2 FROM bookings t1
3 PARTITION BY (t1.room)
4 RIGHT OUTER JOIN timeslots ON (hrs.hr = t1.hr)
5 order by 1,2
HR ROOM WHO
--------- ---------- ----------
8 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 Room2
112
113
subquery factoring
114
common table expressions
115
WITH clause
116
WITH last_hire AS
(
select deptno, max(hiredate)
from emp
group by deptno
)
select * from last_hire;
117
"who cares?....... more code, same result"
118
why is it cool ?
119
good solution metaphor
120
relational is a rigorous model ...
121
relational is the dominant model ...
122
relational ... can sortta suck :-)
123
not our fault
124
Codd & Date
125
"data is represented as mathematical n-ary
relations, an n-ary relation being a subset of
the Cartesian product of n domains."
126
127
procedural world
128
step by step
129
"First, get the total salary paid by each department,
then get the average of these totals,
then list those departments above that average"
SQL ?
130
"First, get the total salary paid by department...
SQL> WITH dept_salaries AS (
2 SELECT dname, SUM(sal) dept_sal
3 FROM emp e, dept d
4 WHERE e.deptno = d.deptno
5 GROUP BY dname),
131
"...then get the average of these totals...
6 avg_sal AS ( SELECT AVG(dept_sal) avsal
7 FROM dept_salaries)
132
"...then list those departments above average."
8 SELECT * FROM dept_salaries d, avg_sal a
9 WHERE d.dept_sal > a.avsal
10 ORDER BY d.dname;
133
SQL> WITH dept_salaries AS (
2 SELECT dname, SUM(sal) dept_sal
3 FROM emp e, dept d
4 WHERE e.deptno = d.deptno
5 GROUP BY dname),
6 avg_sal AS ( SELECT AVG(dept_sal) avsal
7 FROM dept_salaries)
8 SELECT * FROM dept_salaries d, avg_sal a
9 WHERE d.dept_sal > a.avsal
10 ORDER BY d.dname;
134
programmer's approach....
135
... relational solution
136
the "finishing touches"
137
everyone loves JSON
138
recall: partitioned outer join
139
SQL> with raw_data as (
2 select
3 hrs.hr,
4 t1.room,
5 t1.who
6 from bookings t1
7 partition by (t1.room)
8 right outer join hrs
9 on (hrs.hr = t1.hr)
10 order by
11 hr, room
12 )
13 select
14 json_arrayagg(
15 json_object(key room||to_char(hr) value who )
16 order by hr ) as meetings
17 from raw_data ;
[{"Room1-08":null},
{"Room1-09":"JOHN"},
{"Room1-10":null},
{"Room1-11":"MIKE"},
{"Room1-12":null},
...
...
{"Room2-14":"JILL"},
{"Room2-15":null},
{"Room2-16":"JANE"}]
140
141
speaking of procedural to relational
142
scalar queries
143
SQL> select
2 ( select dname
3 from dept
4 where deptno = e.deptno ) dname,
5 decode(empno, 7499,
6 ( select max(sal) from emp ),
7 -1)
8 from
9 ( select * from emp
10 where sal > 0 ) e
11 where
12 ( select max(hiredate) from emp ) < sysdate
13 /
scalar
anywhere an
expression could be
148
turn procedural into "relational"
149
List all persons in the STAFF table plus their
salary calculated based on CLASS_TYPE
column value:
= ‘T’ (temp worker) salary is FIXED_PRICE from
PART_TIME_PACKAGE table
= ‘C’ (contractor) salary is the HRS * HRLY_RATE
from CONTRACT_PACKAGE table
= ‘P’ (permanent) salary is the ANNUAL_SAL +
BONUS from PERM_PACKAGE table
150
different table per row
151
4 begin
5 for i in ( select * from staff ) loop
6 if i.class_type = 'T' then -- part time
7 select fixed_price
8 into v_sal
9 from part_time_package
10 where id = i.class_id;
11 elsif i.class_type = 'C' then -- contractors
12 select hrs * hrly_rate
13 into v_sal
14 from contract_package
15 where id = i.class_id;
16 elsif i.class_type = 'P' then -- permanent
17 select annual_sal + bonus
18 into v_sal
19 from perm_package
20 where id = i.class_id;
21 end if;
22 dbms_output.put_line(rpad(i.name,20)||lpad(v_sal,10));
23 end loop;
152
SQL can still do it
153
SQL> select s.name,
2 case class_type
3 when 'T' then (
4 select fixed_price
5 from part_time_package
6 where id = s.class_id )
7 when 'C' then (
8 select hrs * hrly_rate
9 from contract_package
10 where id = s.class_id )
11 when 'P' then (
12 select annual_sal + bonus
13 from perm_package
14 where id = s.class_id )
15 end sal
16 from staff s;
Scalar subquery
NAME SAL
------------------------------ -------
JOHN SMITH 123.45
JOE BLOGGS 2435.54
154
"big deal..."
155
subquery caching
156
157
STOPKEY optimization
158
aka, pagination
159
"employees by hiredate, recent first"
160
SQL> select empno, ename, hiredate
2 from emp
3 where rownum <= 5
4 order by hiredate desc;
EMPNO ENAME HIREDATE
---------- ---------- -------------------
7654 MARTIN 28/09/1981 00:00:00
7566 JONES 02/04/1981 00:00:00
7521 WARD 22/02/1981 00:00:00
7499 ALLEN 20/02/1981 00:00:00
7369 SMITH 17/12/1980 00:00:00
161
inline view
162
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
---------- ---------- ---------
7876 ADAMS 12-JAN-83
7788 SCOTT 09-DEC-82
7934 MILLER 23-JAN-82
7900 JAMES 03-DEC-81
7902 FORD 03-DEC-81
162
163
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;
164
SQL> select empno, ename, hiredate
2 from emp
3 order by hiredate desc
4 fetch first 5 rows only;
EMPNO ENAME HIREDATE
---------- ---------- ---------
7876 ADAMS 12-JAN-83
7788 SCOTT 09-DEC-82
7934 MILLER 23-JAN-82
7900 JAMES 03-DEC-81
7902 FORD 03-DEC-81
165
"TL;DR ... my app can do it"
166
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();
}
167
168
demo
oc01.sql
169
let the database know
170
SQL> select *
2 from (
3 select empno, ename, hiredate
4 from emp
5 order by hiredate desc
6 )
7 where rownum <= 5;
------------------------------------------------
| Id | Operation | Name | Rows |
------------------------------------------------
| 0 | SELECT STATEMENT | | 5 |
|* 1 | COUNT STOPKEY | | |
| 2 | VIEW | | 14 |
|* 3 | SORT ORDER BY STOPKEY| | 14 |
| 4 | TABLE ACCESS FULL | EMP | 14 |
------------------------------------------------
171
SQL> select empno, ename, hiredate
2 from emp
3 order by hiredate desc
4 fetch first 5 rows only;
-------------------------------------------------
| Id | Operation | Name | Rows |
-------------------------------------------------
| 0 | SELECT STATEMENT | | 14 |
|* 1 | VIEW | | 14 |
|* 2 | WINDOW SORT PUSHED RANK| | 14 |
| 3 | TABLE ACCESS FULL | EMP | 14 |
-------------------------------------------------
172
173
most of us know about analytics
174
SQL> select row_number() OVER ( order by sal )
2 from emp
3 ...
https://bit.ly/analytic_sql
175
"Show me lowest salary for each department..."
SQL> select deptno, min(sal)
2 from emp
3 group by deptno;
"...and I need to know who has that lowest salary"
SQL> select deptno, empno, min(sal)
2 from emp
3 group by deptno;
ORA-00979: not a GROUP BY expression
176
KEEP extension
177
SQL> select deptno, min(sal),
2 min(empno)
3 KEEP ( dense_rank FIRST order by sal) empno
4 from emp
5 group by deptno;
DEPTNO MIN(SAL) EMPNO
---------- ---------- ----------
10 1300 7934
20 800 7369
30 950 7900
Emp 7934 has
the lowest salary
of 1300 in dept 10
178
179
every system ...
180
... I've worked on
181
struggles with cAsE
182
no correlation ☺
but its my fault
183
SQL> select surname
2 from names;
SURNAME
------------------------------
jones
brown
SMITH
sigh...
184
SQL> select initcap(surname)
2 from names;
SURNAME
------------------------------
Jones
Brown
Smith
Mcdonald
185
and it just gets worse...
186
SQL> select *
2 from customers
3 where cust_name = 'ADAMS';
COUNTRY CREATED CUST_NAME
------------ --------- ------------
AUS 07-NOV-16 ADAMS
187
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
188
189
SQL> select * from customers
2 where upper(cust_name) = 'ADAMS';
UKOUG 2019 - SQL features
191
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 |
-------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 152 |
|* 1 | TABLE ACCESS FULL| CUSTOMERS | 1 | 152 |
-------------------------------------------------------
192
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.
193
DML slower
more contention
more redo/undo
194
"not my problem"
195
196
SQL> alter table customers shrink space;
*
ERROR at line 1:
ORA-10631: SHRINK clause should not be specified
197
a better way
198
column level collation
199
200
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"
201
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 |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| CUSTOMERS | 1 |
|* 2 | INDEX RANGE SCAN | CUST_IX | 1 |
-----------------------------------------------------------------
202
"what is so special about that?"
203
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
204
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
205
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
206
column | table | user
207
SQL> alter table people default collation binary_ai;
new columns only
208
UKOUG 2019 - SQL features
210
210
211
"talking" to your database
... makes it faster
212
example
213
STORES
CUSTOMERS
SALES
214
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
hash outer join ?
nested loop ?
STORES first ?
sort merge ?
215
---------------------------------------------------
| Id | Operation | Name | Rows |
---------------------------------------------------
| 0 | SELECT STATEMENT | | 100 |
| 1 | HASH GROUP BY | | 100 |
|* 2 | HASH JOIN | | 990K |
| 3 | NESTED LOOPS SEMI | | 5000 |
| 4 | TABLE ACCESS FULL| CUSTOMERS | 5000 |
|* 5 | INDEX UNIQUE SCAN| STORE_IX | 50 |
|* 6 | TABLE ACCESS FULL | SALES | 990K |
---------------------------------------------------
216
can we do better ?
add indexes ?
rewrite query ?
result cache ?
materialized view ?
217
share your knowledge with the db
oc04.sql
218
wrap up
219
SQL
220
very cool
221
very powerful
222
less code
223
never too early to start
UKOUG 2019 - SQL features
UKOUG 2019 - SQL features
226
25 years of tips and techniques
Tuesday, 9am, Empress
227
Have a great conference !
youtube youtube.com/c/ConnorMcDonaldOracle
blog connor-mcdonald.com
twitter @connor_mc_d

More Related Content

PDF
UKOUG - 25 years of hints and tips
PDF
Flashback ITOUG
PDF
ANSI vs Oracle language
PPTX
SQL techniques for faster applications
PDF
Sangam 19 - PLSQL still the coolest
PDF
Sangam 19 - Analytic SQL
PDF
Sangam 2019 - The Latest Features
PDF
Latin America Tour 2019 - 10 great sql features
UKOUG - 25 years of hints and tips
Flashback ITOUG
ANSI vs Oracle language
SQL techniques for faster applications
Sangam 19 - PLSQL still the coolest
Sangam 19 - Analytic SQL
Sangam 2019 - The Latest Features
Latin America Tour 2019 - 10 great sql features

What's hot (20)

PDF
APEX Connect 2019 - array/bulk processing in PLSQL
PDF
KScope19 - SQL Features
PDF
Sangam 19 - Successful Applications on Autonomous
PPTX
Sangam 18 - Great Applications with Great SQL
PDF
Latin America Tour 2019 - pattern matching
PDF
Latin America tour 2019 - Flashback
PPTX
Analytic SQL Sep 2013
PPTX
SQL Tuning 101 - Sep 2013
PDF
OOW19 - Ten Amazing SQL features
PDF
OOW19 - Flashback, not just for DBAs
PDF
Oracle Database 12c Application Development
PDF
Pattern Matching with SQL - APEX World Rotterdam 2019
PPTX
Get your moneys worth out of your database
PDF
OOW19 - Killing database sessions
KEY
実践 memcached
PPT
SQL WORKSHOP::Lecture 4
PPTX
The Five Best Things To Happen To SQL
PPTX
Perth APAC Groundbreakers tour - SQL Techniques
PPTX
SQL techniques for faster applications
PPTX
Les04 Displaying Data From Multiple Table
APEX Connect 2019 - array/bulk processing in PLSQL
KScope19 - SQL Features
Sangam 19 - Successful Applications on Autonomous
Sangam 18 - Great Applications with Great SQL
Latin America Tour 2019 - pattern matching
Latin America tour 2019 - Flashback
Analytic SQL Sep 2013
SQL Tuning 101 - Sep 2013
OOW19 - Ten Amazing SQL features
OOW19 - Flashback, not just for DBAs
Oracle Database 12c Application Development
Pattern Matching with SQL - APEX World Rotterdam 2019
Get your moneys worth out of your database
OOW19 - Killing database sessions
実践 memcached
SQL WORKSHOP::Lecture 4
The Five Best Things To Happen To SQL
Perth APAC Groundbreakers tour - SQL Techniques
SQL techniques for faster applications
Les04 Displaying Data From Multiple Table
Ad

Similar to UKOUG 2019 - SQL features (20)

PDF
Connor McDonald Partitioning
PPTX
SQL and PLSQL features for APEX Developers
PDF
ILOUG 2019 - SQL features for Developers
PDF
On Seeing Double in V$SQL_Thomas_Kytepdf
PDF
Connor McDonald 11g for developers
PPT
Dbms plan - A swiss army knife for performance engineers
PDF
12c for Developers - Feb 2014
PPTX
OpenWorld Sep14 12c for_developers
PPTX
OpenWorld 2018 - Common Application Developer Disasters
PPTX
Wellington APAC Groundbreakers tour - SQL Pattern Matching
PPTX
5 Cool Things About SQL
PDF
Chasing the optimizer
DOCX
Subquery factoring for FTS
PDF
All on Adaptive and Extended Cursor Sharing
PPT
PDF
SQLチューニング総合診療Oracle CloudWorld出張所
PDF
MERGE SQL Statement: Lesser Known Facets
DOCX
metadatacoreProperties.xmlModel2015-07-13T030104Zthua3267th.docx
PPTX
A few things about the Oracle optimizer - 2013
PDF
Hailey_Database_Performance_Made_Easy_through_Graphics.pdf
Connor McDonald Partitioning
SQL and PLSQL features for APEX Developers
ILOUG 2019 - SQL features for Developers
On Seeing Double in V$SQL_Thomas_Kytepdf
Connor McDonald 11g for developers
Dbms plan - A swiss army knife for performance engineers
12c for Developers - Feb 2014
OpenWorld Sep14 12c for_developers
OpenWorld 2018 - Common Application Developer Disasters
Wellington APAC Groundbreakers tour - SQL Pattern Matching
5 Cool Things About SQL
Chasing the optimizer
Subquery factoring for FTS
All on Adaptive and Extended Cursor Sharing
SQLチューニング総合診療Oracle CloudWorld出張所
MERGE SQL Statement: Lesser Known Facets
metadatacoreProperties.xmlModel2015-07-13T030104Zthua3267th.docx
A few things about the Oracle optimizer - 2013
Hailey_Database_Performance_Made_Easy_through_Graphics.pdf
Ad

More from Connor McDonald (14)

PDF
APEX tour 2019 - successful development with autonomous
PDF
APAC Groundbreakers 2019 - Perth/Melbourne
PDF
OOW19 - Read consistency
PDF
OOW19 - Slower and less secure applications
PDF
Latin America Tour 2019 - 18c and 19c featues
PDF
Latin America Tour 2019 - slow data and sql processing
PDF
OG Yatra - upgrading to the new 12c+ optimizer
PDF
OG Yatra - 25 years of hints and tips
PDF
OG Yatra - Flashback, not just for developers
PDF
Kscope19 - Flashback: Good for Developers as well as DBAs
PDF
Kscope19 - Understanding the basics of SQL processing
PDF
18c and 19c features for DBAs
PDF
APEX Connect 2019 - SQL Tuning 101
PDF
APEX Connect 2019 - successful application development
APEX tour 2019 - successful development with autonomous
APAC Groundbreakers 2019 - Perth/Melbourne
OOW19 - Read consistency
OOW19 - Slower and less secure applications
Latin America Tour 2019 - 18c and 19c featues
Latin America Tour 2019 - slow data and sql processing
OG Yatra - upgrading to the new 12c+ optimizer
OG Yatra - 25 years of hints and tips
OG Yatra - Flashback, not just for developers
Kscope19 - Flashback: Good for Developers as well as DBAs
Kscope19 - Understanding the basics of SQL processing
18c and 19c features for DBAs
APEX Connect 2019 - SQL Tuning 101
APEX Connect 2019 - successful application development

Recently uploaded (20)

PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPT
Teaching material agriculture food technology
PDF
Electronic commerce courselecture one. Pdf
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
cuic standard and advanced reporting.pdf
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Approach and Philosophy of On baking technology
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Empathic Computing: Creating Shared Understanding
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Machine learning based COVID-19 study performance prediction
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PPTX
Cloud computing and distributed systems.
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Teaching material agriculture food technology
Electronic commerce courselecture one. Pdf
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Agricultural_Statistics_at_a_Glance_2022_0.pdf
cuic standard and advanced reporting.pdf
Per capita expenditure prediction using model stacking based on satellite ima...
Review of recent advances in non-invasive hemoglobin estimation
Approach and Philosophy of On baking technology
sap open course for s4hana steps from ECC to s4
Empathic Computing: Creating Shared Understanding
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Unlocking AI with Model Context Protocol (MCP)
Encapsulation_ Review paper, used for researhc scholars
MIND Revenue Release Quarter 2 2025 Press Release
Machine learning based COVID-19 study performance prediction
20250228 LYD VKU AI Blended-Learning.pptx
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Building Integrated photovoltaic BIPV_UPV.pdf
Cloud computing and distributed systems.

UKOUG 2019 - SQL features

  • 2. 2 2
  • 3. 3 3
  • 4. 4 4
  • 5. 5 Stuff youtube bit.ly/youtube-connor blog connor-mcdonald.com twitter @connor_mc_d 400+ posts mainly on database & development 300+ technical videos, new uploads every week rants and raves on tech and the world :-)
  • 6. 6 etc... facebook bit.ly/facebook-connor linkedin bit.ly/linkedin-connor instagram bit.ly/instagram-connor slideshare bit.ly/slideshare-connor
  • 8. 10
  • 9. SO
  • 10. THE
  • 11. BIG
  • 13. IS
  • 14. 16
  • 17. 19
  • 18. 20 why talk about SQL # 1
  • 20. 22
  • 21. 23 why talk about SQL # 2
  • 25. 27 "fine-grained to perform a single function" "Each service is ... minimal, and complete" https://en.wikipedia.org/wiki/Microservices select COUNT(*) from PEOPLE where GENDER = 'MALE'
  • 29. 31 "By abstracting the underlying implementation" "describes the expected behaviour ... but can have multiple implementations" https://en.wikipedia.org/wiki/Application_programming_interface select NAME, STREET_NO, ZIP_CODE from PEOPLE p, ADDRESS a where p.AGE > 50 and p.ADDRESS_ID = a.ADDRESS_ID;
  • 31. 41 this session is not about ...
  • 33. 43 we can do anything ...
  • 34. 44 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)
  • 35. 45 18 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, https://technology.amis.nl
  • 36. 46 SQL> variable board varchar2(1000) SQL> begin :board := 2 '53.|.7.|... 3 6..|195|... 4 .98|...|.6. 5 ----------- 6 8..|.61|..3 7 4..|8.3|..1 8 7..|.2.|..6 9 ----------- 10 .6.|...|28. 11 ...|419|..5 12 ...|.8.|.79 13 '; 14 end; 5 3 7 6 1 9 5 9 8 6 8 6 1 3 4 8 3 1 7 2 6 6 2 8 4 1 9 5 8 7 9
  • 38. 48 100% % of developers that will need to solve Sudoku as part of their job
  • 39. 49 100% % of developers that need to get real s*#t done
  • 41. 51
  • 43. DBA
  • 44. 54
  • 47. 57 DBA friendship is important oc00.sql
  • 48. 58
  • 50. 60 C#, C++ ESB Tuxedo Weblogic Stored Procedure
  • 51. 61 for (int i = 0; i < WinningCombinations.Count; ++i) { if (WinningCombinations[i].Investment > 0 && WinningCombinations[i].PrimaryDividend > MinDividendDeadHeat) { maxDivisor = Math.Max(maxDivisor, WinningCombinations[i].Divisor); } } for (int i = 0; i < WinningCombinations.Count; ++i) { if (WinningCombinations[i].Investment > 0 && WinningCombinations[i].PrimaryDividend > MinDividendDeadHeat) { WinningCombinations[i].Divisor = maxDivisor / WinningCombinations[i].Divisor; sumNewDivisors += WinningCombinations[i].Divisor; } }
  • 55. 65 SQL can be complex
  • 57. 67 query blocks = self-documenting SQL
  • 58. 68 select emp.* from emp, ( select trunc(hiredate,'YYYY'), max(empno) empno from emp where empno > 0 group by trunc(hiredate,'YYYY') ) x, ( select deptno, avg(sal) from emp group by deptno ) y where x.empno = emp.empno and y.deptno = emp.deptno
  • 59. 69 Id | Operation | Name | ----------------------------------------------| 0 | SELECT STATEMENT | | 1 | HASH JOIN | | 2 | TABLE ACCESS BY INDEX ROWID | EMP | 3 | NESTED LOOPS | | 4 | VIEW | | 5 | SORT GROUP BY | | 6 | TABLE ACCESS BY INDEX ROWID| EMP | 7 | INDEX FULL SCAN | E2 | 8 | INDEX RANGE SCAN | E1 | 9 | VIEW | | 10 | SORT GROUP BY | | 11 | TABLE ACCESS BY INDEX ROWID | EMP | 12 | INDEX RANGE SCAN | E2 |
  • 60. 70 select emp.* from emp, ( select trunc(hiredate,'YYYY'), max(empno) empno from emp where empno > 0 group by trunc(hiredate,'YYYY') ) x, ( select deptno, avg(sal) from emp group by deptno ) y where x.empno = emp.empno and y.deptno = emp.deptno Id | Operation | Name | ----------------------------------------------| 0 | SELECT STATEMENT | | 1 | HASH JOIN | | 2 | TABLE ACCESS BY INDEX ROWID | EMP | 3 | NESTED LOOPS | | 4 | VIEW | | 5 | SORT GROUP BY | | 6 | TABLE ACCESS BY INDEX ROWID| EMP | 7 | INDEX FULL SCAN | E2 | 8 | INDEX RANGE SCAN | E1 | 9 | VIEW | | 10 | SORT GROUP BY | | 11 | TABLE ACCESS BY INDEX ROWID | EMP | 12 | INDEX RANGE SCAN | E2 |
  • 61. 71 select emp.* from emp, ( select /*+ QB_NAME(YR_HIRE) */ trunc(hiredate,'YYYY'), max(empno) empno from emp where empno > 0 group by trunc(hiredate,'YYYY') ) x, ( select /*+ QB_NAME(AV_SAL) */ deptno, avg(sal) from emp group by deptno ) y where x.empno = emp.empno and y.deptno = emp.deptno
  • 62. 72 Id | Operation | Name | Query Block ----------------------------------------------|-------------- 0 | SELECT STATEMENT | | 1 | HASH JOIN | | 2 | TABLE ACCESS BY INDEX ROWID | EMP | 3 | NESTED LOOPS | | 4 | VIEW | | 5 | SORT GROUP BY | | 6 | TABLE ACCESS BY INDEX ROWID| EMP | 7 | INDEX FULL SCAN | E2 | 8 | INDEX RANGE SCAN | E1 | 9 | VIEW | | 10 | SORT GROUP BY | | 11 | TABLE ACCESS BY INDEX ROWID | EMP | 12 | INDEX RANGE SCAN | E2 | SEL$1 SEL$1 AV_SAL AV_SAL AV_SAL AV_SAL SEL$1 YR_HIRE YR_HIRE YR_HIRE YR_HIRE
  • 63. 73
  • 65. 75 SQL> insert into MY_TABLE 2 select * 3 from MY_HUGE_GREAT_FAT_TABLE;MY_HUGE_GREAT_FAT_TABLE;
  • 66. 76
  • 67. 77
  • 68. 78
  • 69. 79
  • 70. 80
  • 71. 81 SQL> insert into MY_TABLE 2 select * 3 from MY_HUGE_GREAT_FAT_TABLE; Elapsed: 06:12:34.00
  • 72. 82 SQL> insert into MY_TABLE 2 select * 3 from MY_HUGE_GREAT_FAT_TABLE; Elapsed: 06:12:34.00 ERROR at line 1: ORA-01847: day of month must be between 1 and last day of month
  • 74. 84 84
  • 75. 85 and then we do this :-)
  • 76. 86 SQL> select count(*) from MY_TABLE; COUNT(*) ---------- 0
  • 79. 89 skip / bypass bad rows
  • 81. 91 SQL> insert into MY_TABLE 2 select * 3 from MY_HUGE_GREAT_FAT_TABLE 4 where "not a duplicate" 5 and "datatypes are ok" 6 and "foreign keys are ok" 7 and "check constraints are ok"
  • 84. 94 DBMS_ERRLOG.CREATE_ERROR_LOG ( dml_table_name IN VARCHAR2, err_log_table_name IN VARCHAR2 := NULL, err_log_table_owner IN VARCHAR2 := NULL, ...
  • 85. 95 SQL> desc ERR$_EMP Name Null? Type ----------------------------- -------- ---------------- ORA_ERR_NUMBER$ NUMBER ORA_ERR_MESG$ VARCHAR2(2000) ORA_ERR_ROWID$ ROWID ORA_ERR_OPTYP$ VARCHAR2(2) ORA_ERR_TAG$ VARCHAR2(2000) EMPNO VARCHAR2(4000) ENAME VARCHAR2(4000) JOB VARCHAR2(4000) MGR VARCHAR2(4000) HIREDATE VARCHAR2(4000) SAL VARCHAR2(4000) COMM VARCHAR2(4000) DEPTNO VARCHAR2(4000)
  • 86. 96 96
  • 88. 98 add to EMP from NEW_DATA
  • 89. 99 SQL> select * from NEW_DATA; EMPNO SAL DEPTNO ---------- ---------- ---------- 1000 5000 20 100X 3550 10 2000 2500 50 7934 4000 20 non-numeric no dept 50 duplicate
  • 90. 100 SQL> exec dbms_errlog.create_error_log('EMP'); PL/SQL procedure successfully completed. SQL> insert into EMP (empno,sal,deptno) 2 select empno,sal,deptno 3 from NEW_DATA 4 LOG ERRORS REJECT LIMIT UNLIMITED; 1 row created. 50
  • 91. 101 SQL> select ORA_ERR_OPTYP$ op, ORA_ERR_MESG$, EMPNO 2 from ERR$_EMP OP ORA_ERR_MESG$ EMPNO -- ------------------------------------------------------------ ----- I ORA-01722: invalid number 100X I ORA-02291: integrity constraint (SCOTT.FK_DEPTNO) violated 2000 I ORA-00001: unique constraint (SCOTT.PK_EMP) violated 7934
  • 92. 102
  • 94. 104 104 SQL> select * 2 from timeslots; HR -- 8 9 10 11 12 13 14 15 16 SQL> select * 2 from bookings; HR ROOM WHO ------- ---------- ------- 8 Room2 PETE 9 Room1 JOHN 11 Room1 MIKE 14 Room2 JILL 15 Room2 JANE 16 Room1 SAM
  • 96. 106 SQL> SELECT hrs.hr, t1.room, t1.who 2 from timeslots hrs 3 left outer join bookings t1 4 on hrs.hr = t1.hr 5 order by 1 HR ROOM WHO ------- ---------- ---------- 8 Room2 PETE 9 Room1 JOHN 10 11 Room1 MIKE 12 13 14 Room2 JILL 15 Room2 JANE 16 Room1 SAM
  • 98. 108 HR ROOM WHO ------- ---------- ---------- 8 Room2 PETE 9 10 11 12 13 14 Room2 JILL 15 Room2 JANE 16 HR ROOM WHO ------- ---------- ---------- 8 9 Room1 JOHN 10 11 Room1 MIKE 12 13 14 15 16 Room1 SAM
  • 99. 109 SQL> select * 2 from timeslots; HR -- 8 9 10 11 12 13 14 15 16 x "Room 1" x "Room 2" ... x "Room n"
  • 101. 111 SQL> SELECT hrs.hr, t1.room, t1.who 2 FROM bookings t1 3 PARTITION BY (t1.room) 4 RIGHT OUTER JOIN timeslots ON (hrs.hr = t1.hr) 5 order by 1,2 HR ROOM WHO --------- ---------- ---------- 8 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 Room2
  • 102. 112
  • 106. 116 WITH last_hire AS ( select deptno, max(hiredate) from emp group by deptno ) select * from last_hire;
  • 107. 117 "who cares?....... more code, same result"
  • 108. 118 why is it cool ?
  • 110. 120 relational is a rigorous model ...
  • 111. 121 relational is the dominant model ...
  • 112. 122 relational ... can sortta suck :-)
  • 115. 125 "data is represented as mathematical n-ary relations, an n-ary relation being a subset of the Cartesian product of n domains."
  • 116. 126
  • 119. 129 "First, get the total salary paid by each department, then get the average of these totals, then list those departments above that average" SQL ?
  • 120. 130 "First, get the total salary paid by department... SQL> WITH dept_salaries AS ( 2 SELECT dname, SUM(sal) dept_sal 3 FROM emp e, dept d 4 WHERE e.deptno = d.deptno 5 GROUP BY dname),
  • 121. 131 "...then get the average of these totals... 6 avg_sal AS ( SELECT AVG(dept_sal) avsal 7 FROM dept_salaries)
  • 122. 132 "...then list those departments above average." 8 SELECT * FROM dept_salaries d, avg_sal a 9 WHERE d.dept_sal > a.avsal 10 ORDER BY d.dname;
  • 123. 133 SQL> WITH dept_salaries AS ( 2 SELECT dname, SUM(sal) dept_sal 3 FROM emp e, dept d 4 WHERE e.deptno = d.deptno 5 GROUP BY dname), 6 avg_sal AS ( SELECT AVG(dept_sal) avsal 7 FROM dept_salaries) 8 SELECT * FROM dept_salaries d, avg_sal a 9 WHERE d.dept_sal > a.avsal 10 ORDER BY d.dname;
  • 129. 139 SQL> with raw_data as ( 2 select 3 hrs.hr, 4 t1.room, 5 t1.who 6 from bookings t1 7 partition by (t1.room) 8 right outer join hrs 9 on (hrs.hr = t1.hr) 10 order by 11 hr, room 12 ) 13 select 14 json_arrayagg( 15 json_object(key room||to_char(hr) value who ) 16 order by hr ) as meetings 17 from raw_data ; [{"Room1-08":null}, {"Room1-09":"JOHN"}, {"Room1-10":null}, {"Room1-11":"MIKE"}, {"Room1-12":null}, ... ... {"Room2-14":"JILL"}, {"Room2-15":null}, {"Room2-16":"JANE"}]
  • 130. 140
  • 131. 141 speaking of procedural to relational
  • 133. 143 SQL> select 2 ( select dname 3 from dept 4 where deptno = e.deptno ) dname, 5 decode(empno, 7499, 6 ( select max(sal) from emp ), 7 -1) 8 from 9 ( select * from emp 10 where sal > 0 ) e 11 where 12 ( select max(hiredate) from emp ) < sysdate 13 / scalar anywhere an expression could be
  • 134. 148 turn procedural into "relational"
  • 135. 149 List all persons in the STAFF table plus their salary calculated based on CLASS_TYPE column value: = ‘T’ (temp worker) salary is FIXED_PRICE from PART_TIME_PACKAGE table = ‘C’ (contractor) salary is the HRS * HRLY_RATE from CONTRACT_PACKAGE table = ‘P’ (permanent) salary is the ANNUAL_SAL + BONUS from PERM_PACKAGE table
  • 137. 151 4 begin 5 for i in ( select * from staff ) loop 6 if i.class_type = 'T' then -- part time 7 select fixed_price 8 into v_sal 9 from part_time_package 10 where id = i.class_id; 11 elsif i.class_type = 'C' then -- contractors 12 select hrs * hrly_rate 13 into v_sal 14 from contract_package 15 where id = i.class_id; 16 elsif i.class_type = 'P' then -- permanent 17 select annual_sal + bonus 18 into v_sal 19 from perm_package 20 where id = i.class_id; 21 end if; 22 dbms_output.put_line(rpad(i.name,20)||lpad(v_sal,10)); 23 end loop;
  • 139. 153 SQL> select s.name, 2 case class_type 3 when 'T' then ( 4 select fixed_price 5 from part_time_package 6 where id = s.class_id ) 7 when 'C' then ( 8 select hrs * hrly_rate 9 from contract_package 10 where id = s.class_id ) 11 when 'P' then ( 12 select annual_sal + bonus 13 from perm_package 14 where id = s.class_id ) 15 end sal 16 from staff s; Scalar subquery NAME SAL ------------------------------ ------- JOHN SMITH 123.45 JOE BLOGGS 2435.54
  • 142. 156
  • 145. 159 "employees by hiredate, recent first"
  • 146. 160 SQL> select empno, ename, hiredate 2 from emp 3 where rownum <= 5 4 order by hiredate desc; EMPNO ENAME HIREDATE ---------- ---------- ------------------- 7654 MARTIN 28/09/1981 00:00:00 7566 JONES 02/04/1981 00:00:00 7521 WARD 22/02/1981 00:00:00 7499 ALLEN 20/02/1981 00:00:00 7369 SMITH 17/12/1980 00:00:00
  • 148. 162 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 ---------- ---------- --------- 7876 ADAMS 12-JAN-83 7788 SCOTT 09-DEC-82 7934 MILLER 23-JAN-82 7900 JAMES 03-DEC-81 7902 FORD 03-DEC-81 162
  • 149. 163 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;
  • 150. 164 SQL> select empno, ename, hiredate 2 from emp 3 order by hiredate desc 4 fetch first 5 rows only; EMPNO ENAME HIREDATE ---------- ---------- --------- 7876 ADAMS 12-JAN-83 7788 SCOTT 09-DEC-82 7934 MILLER 23-JAN-82 7900 JAMES 03-DEC-81 7902 FORD 03-DEC-81
  • 151. 165 "TL;DR ... my app can do it"
  • 152. 166 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(); }
  • 153. 167
  • 156. 170 SQL> select * 2 from ( 3 select empno, ename, hiredate 4 from emp 5 order by hiredate desc 6 ) 7 where rownum <= 5; ------------------------------------------------ | Id | Operation | Name | Rows | ------------------------------------------------ | 0 | SELECT STATEMENT | | 5 | |* 1 | COUNT STOPKEY | | | | 2 | VIEW | | 14 | |* 3 | SORT ORDER BY STOPKEY| | 14 | | 4 | TABLE ACCESS FULL | EMP | 14 | ------------------------------------------------
  • 157. 171 SQL> select empno, ename, hiredate 2 from emp 3 order by hiredate desc 4 fetch first 5 rows only; ------------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------------- | 0 | SELECT STATEMENT | | 14 | |* 1 | VIEW | | 14 | |* 2 | WINDOW SORT PUSHED RANK| | 14 | | 3 | TABLE ACCESS FULL | EMP | 14 | -------------------------------------------------
  • 158. 172
  • 159. 173 most of us know about analytics
  • 160. 174 SQL> select row_number() OVER ( order by sal ) 2 from emp 3 ... https://bit.ly/analytic_sql
  • 161. 175 "Show me lowest salary for each department..." SQL> select deptno, min(sal) 2 from emp 3 group by deptno; "...and I need to know who has that lowest salary" SQL> select deptno, empno, min(sal) 2 from emp 3 group by deptno; ORA-00979: not a GROUP BY expression
  • 163. 177 SQL> select deptno, min(sal), 2 min(empno) 3 KEEP ( dense_rank FIRST order by sal) empno 4 from emp 5 group by deptno; DEPTNO MIN(SAL) EMPNO ---------- ---------- ---------- 10 1300 7934 20 800 7369 30 950 7900 Emp 7934 has the lowest salary of 1300 in dept 10
  • 164. 178
  • 168. 182 no correlation ☺ but its my fault
  • 169. 183 SQL> select surname 2 from names; SURNAME ------------------------------ jones brown SMITH sigh...
  • 170. 184 SQL> select initcap(surname) 2 from names; SURNAME ------------------------------ Jones Brown Smith Mcdonald
  • 171. 185 and it just gets worse...
  • 172. 186 SQL> select * 2 from customers 3 where cust_name = 'ADAMS'; COUNTRY CREATED CUST_NAME ------------ --------- ------------ AUS 07-NOV-16 ADAMS
  • 173. 187 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
  • 174. 188
  • 175. 189 SQL> select * from customers 2 where upper(cust_name) = 'ADAMS';
  • 177. 191 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 | ------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 152 | |* 1 | TABLE ACCESS FULL| CUSTOMERS | 1 | 152 | -------------------------------------------------------
  • 178. 192 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.
  • 181. 195
  • 182. 196 SQL> alter table customers shrink space; * ERROR at line 1: ORA-10631: SHRINK clause should not be specified
  • 185. 199
  • 186. 200 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"
  • 187. 201 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 | ----------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 | TABLE ACCESS BY INDEX ROWID BATCHED| CUSTOMERS | 1 | |* 2 | INDEX RANGE SCAN | CUST_IX | 1 | -----------------------------------------------------------------
  • 188. 202 "what is so special about that?"
  • 189. 203 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
  • 190. 204 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
  • 191. 205 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
  • 193. 207 SQL> alter table people default collation binary_ai; new columns only
  • 194. 208
  • 197. 211 "talking" to your database ... makes it faster
  • 200. 214 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 hash outer join ? nested loop ? STORES first ? sort merge ?
  • 201. 215 --------------------------------------------------- | Id | Operation | Name | Rows | --------------------------------------------------- | 0 | SELECT STATEMENT | | 100 | | 1 | HASH GROUP BY | | 100 | |* 2 | HASH JOIN | | 990K | | 3 | NESTED LOOPS SEMI | | 5000 | | 4 | TABLE ACCESS FULL| CUSTOMERS | 5000 | |* 5 | INDEX UNIQUE SCAN| STORE_IX | 50 | |* 6 | TABLE ACCESS FULL | SALES | 990K | ---------------------------------------------------
  • 202. 216 can we do better ? add indexes ? rewrite query ? result cache ? materialized view ?
  • 203. 217 share your knowledge with the db oc04.sql
  • 209. 223 never too early to start
  • 212. 226 25 years of tips and techniques Tuesday, 9am, Empress
  • 213. 227 Have a great conference ! youtube youtube.com/c/ConnorMcDonaldOracle blog connor-mcdonald.com twitter @connor_mc_d