Professional Documents
Culture Documents
• Multi-Table Insert
• Data Aggregation
• Merge Statement
• Analytical Functions
• BulkCollect and ForAll
May 2007
Multi-Table Insert
• INSERT … SELECT
In a multi table insert, you insert computed rows derived from the rows
returned from the evaluation of a sub query into one or more tables.
Types:
• Unconditional Insert
• Conditional Insert
• Conditional First Insert
• Pivoting Insert
Current Scenario :
INSERT ALL
INTO hbg2 VALUES (emp_no,name )
INTO hbg1 VALUES (emp_no,name)
SELECT emp_no, name
FROM hbg
WHERE emp_no > 2;
Conditional INSERT ALL
INSERT ALL
WHEN emp_no > 4 THEN
INTO hbg2 VALUES (emp_no,name )
WHEN emp_no <= 4 THEN
INTO hbg1 VALUES (emp_no,name)
SELECT emp_no,name
FROM hbg
WHERE emp_no > 2;
Conditional INSERT FIRST
INSERT FIRST
WHEN name ='Harsh' THEN
INTO hbg1 VALUES (emp_no,name)
WHEN emp_no = 2 THEN
INTO hbg2 VALUES (emp_no,name)
WHEN emp_no >2 and emp_no < 4 THEN
INTO hbg3 VALUES (emp_no,name)
ELSE
INTO hbg4 VALUES (emp_no,name)
SELECT emp_no, name FROM hbg;
Pivoting INSERT
INSERT ALL
INTO sales VALUES (emp_id,name,region1)
INTO sales VALUES (emp_id,name,region2)
INTO sales VALUES (emp_id,name,region3)
SELECT emp_id, name, region1,region2, region3
FROM sales_main;
Tips and Fine Points
• We can also use an ELSE clause to tell oracle what to do if none of the
WHEN clauses evaluates to true
• Instead of using Sqlldr to load data into multiple table , multi table inserts
coupled with an external table can be used.
MERGE Statement
We can conditionally insert rows into table B from table A with help of
single SQL statement.
• ROLLUP
Used to calculate sub-totals
• CUBE
Used to get cross-tabulation results
• Grouping Sets
For Multiple Groupings
• With Clause
Materialize the Repeated Inline Views
With Clause
With data as
(Select rownum r from all_objects
Where rownum< 50)
Select sysdate + r from data
Tips and Fine Points
Select deptno,ename,sal
Row_number() over (partition by deptno
Order by sal desc )
from emp
Deptno Ename Sal SCOTT
King 3000 11
5000
10 FORD
Clark 3000 22
2450
JONES
Miller 2975 33
1300
20 ADAMS 1100 4
30 SMITH 800 5
Analytics
• And the list is infinitely long
– "Analytics are the coolest thing to happen to SQL since the keyword
Select"
– Lets look at a complex example
• RANK
• DENSE_RANK
• ROW_NUMBER
• FIRST_VALUE / LAST_VALUE
• LEAD
• LAG
Classic Problem
I have records like this:
Time Amount
11/22/2003 12:22:01 100
11/22/2003 12:22:03 200
11/22/2003 12:22:04 300
11/22/2003 12:22:45 100
11/22/2003 12:22:46 200
11/22/2003 12:23:12 100
11/22/2003 12:23:12 200
What I need to do is sum the amounts where the time of the records is within 3
seconds of each other. In the case where the data is like this:
11/22/2003 12:22:03 200
11/22/2003 12:22:04 200
11/22/2003 12:22:05 200
11/22/2003 12:22:06 200
11/22/2003 12:22:07 200
11/22/2003 12:22:08 200
11/22/2003 12:22:09 200
There would only be one row with the total for all the rows. (Basically, we are looking
for "instances" where we define an instance such that all the records within the
instance are no more than three seconds apart. So there can be 1 or many records all
of the same instance and the resulting summation would have one summary record
per instance.) Would you please point me in the right direction?
Analytics on Analytics
“Conventional
binds”
Conventional Bind
Oracle server
Performance penalty
for many “context
switches”
Enter the “Bulk Bind”
Oracle server0
PL/SQL block
Procedural
statement SQL
FORALL indx IN executor statement
deptlist.FIRST.. executor
deptlist.LAST
UPDATE employee
SET salary = ...
WHERE employee_id =
deptlist(indx);
Much less overhead for
context switching
Use the FORALL Bulk Bind Statement
• Instead of executing repetitive, individual DML statements,
you can write your code like this:
PROCEDURE remove_emps_by_dept (deptlist dlist_t)
IS
BEGIN
FORALL aDept IN deptlist.FIRST..deptlist.LAST
DELETE FROM emp WHERE deptno = deptlist(aDept);
END;
DECLARE
TYPE employees_aat IS TABLE OF employees%ROWTYPE
Declare a collection of INDEX BY BINARY_INTEGER;
records to hold the
queried data. l_employees employees_aat;
BEGIN
SELECT *
BULK COLLECT INTO l_employees
Use BULK COLLECT FROM employees;
to retrieve all rows.
FOR indx IN 1 .. l_employees.COUNT
LOOP
process_employee (l_employees(indx));
END LOOP;
Iterate through the END;
collection contents with
a loop.
Limit the number of rows returned by BULK COLLECT
PROCEDURE update_emps (
col_in IN VARCHAR2, empnos_in IN numList) IS
enames NameList;
BEGIN
FORALL indx IN empnos_in.FIRST .. empnos_in.LAST
EXECUTE IMMEDIATE
'UPDATE emp SET ' || col_in || ' = ' || col_in
|| ' * 1.1 WHERE empno = :1
RETURNING ename INTO :2'
USING empnos_in (indx ) Notice that empnos_in is
RETURNING BULK COLLECT INTO enames; indexed, but enames is
... not.
END;
Excellent Exception Handling for Bulk Operations
• Allows you to continue past errors and obtain error information for
each individual operation (for dynamic and static SQL).
• Bulk collects:
– Can be used with implicit and explicit cursors
– Collection is always filled sequentially, starting at row 1