PL/SQL Concepts
Ref
Definition
- Procedural Language for SQL is a procedural extesion for SQL.
- Most commonly used features include:
- Program units
- Block
- Function
- Procedure
- Package
- Trigger
- Data types
- Numeric
- Character
- Date
- Exceptions
- Specifi columns
- Conditional statements
- Array handling
- Associative arrays(index-by tables)
- Nested tables
- Varrays(variable-size arrays)
- Cursors
- Looping
- Dynamic SQL
- Program units
Trigger
Stored Procedure and Function
Refs
Stored Procedure vs Function
Functions follow the computer-science definition in that they MUST return a value and cannot alter the data they receive as parameters (the arguments). Functions are not allowed to change anything, must have at least one parameter, and they must return a value. Stored procs do not have to have a parameter, can change database objects, and do not have to return a value.
Stored Procedure
Syntax
1 | -- create a procedure: |
- Parameter types:
- IN: Passed into the procedure, must assign a value, immutable.
- OUT: Not required to assign a value, mutable.
- IN OUT: Passed into the procedure, must assign a value, mutable.
Test Data
- Initalize test data for the examples:
1 | create table customers ( |
Cursor
A cursor is a pointer that points to the result of a query.
There are two types of cursors:
- Implicit cursor
- Automatically created by Oracle whenever an SQL statement is executed.
- Whenever a DML(INSERT, UPDATE and DELETE) statement is executed, an implicit cursor is associated with this statement.
- For INSERT statement, the cursor holds the data to be inserted; For UPDATE and DELETE statement, the cursor identifies the rows that would be affected.
- Explicit cursor
- Created on a SELECT statement which returns more than one row.
- Implicit cursor
Cursor attributes
Attribute Description %FOUND Returns TRUE if an INSERT, UPDATE, or DELETE statement affected one or more rows or a SELECT INTO statement returned one or more rows. Otherwise, it returns FALSE. %NOTFOUND The logical opposite of %FOUND. It returns TRUE if an INSERT, UPDATE, or DELETE statement affected no rows, or a SELECT INTO statement returned no rows. Otherwise, it returns FALSE. %ISOPEN Always returns FALSE for implicit cursors, because Oracle closes the SQL cursor automatically after executing its associated SQL statement. %ROWCOUNT Returns the number of rows affected by an INSERT, UPDATE, or DELETE statement, or returned by a SELECT INTO statement.
Examples
If you run the examples in PL/SQL Developer, remember to run the code of the procedure creation in a program windows instead of a sql window. Sql window does not throw errors!
- Implicit cursor:
1 | DECLARE |
- Explicit cursor:
1 | DECLARE |
- Simplest procedure:
1 | CREATE OR REPLACE PROCEDURE greetings |
- Procedure with parameters:
1 | DECLARE |
1 | DECLARE |
- Exception handling:
1 | DECLARE |
CTE
Ref
Definition
- Common Table Expression, a query defined within another query.
- It’s like a subquery, but can be assigned a name and reused many times.
- It’s also like a ‘one-shot’ view.
- Also called a SQL WITH clause as it uses the WITH keyword.
Example
Initialization data
- Initialize data:
1 | CREATE TABLE employee ( |
This creates the following data:
EMP_ID | FIRST_NAME | LAST_NAME | DEPT_ID | MANAGER_ID | OFFICE_ID |
---|---|---|---|---|---|
1 | Sally | Jones | 3 | 2 | 5 |
2 | Mark | Smith | 2 | 4 | 3 |
3 | John | Andrews | 1 | 4 | 3 |
4 | Michelle | Johnson | 2 | 5 | |
5 | Brian | Grand | 2 | 2 | 3 |
Simple Example: Get employee name with department employe count
1 | WITH d_count AS |
Recursive CTE Example
1 | WITH cteEmp(emp_id, |
- This produces the following result:
EMP_ID | FIRST_NAME | MANAGER_ID | EMPLEVEL |
---|---|---|---|
4 | Michelle | 1 | |
2 | Mark | 4 | 2 |
3 | John | 4 | 2 |
1 | Sally | 2 | 3 |
5 | Brian | 2 | 3 |
The above result is generated in the following process:
- Get data from the initial query
where manager_id IS NULL
, which returns one row;
Notice that a recursive CTE must have beUNION
query connecting a initial qery and a recursive query. - The recursive query
FROM employee e, cteEmp r WHERE e.manager_id = r.emp_id
associates the original table with data from the initial query, returning more data; - Repeats step 2, until no more data is yielded.
Materialized View
Ref
Concept
- A materialized view, or snapshot as they were previously known, is a table segment whose contents are periodically refreshed based on a query, either against a local or remote table.
Syntax
1 | -- Normal |
Build options:
- IMMEDIATE: The materialized view is populated immediately.
- DEFERRED: The materialized view is populated on the first request refresh.
Refresh types:
- FAST: A fast refresh is attempted. If materialized view logs are not present against the source tables in advance, the creation fails.
- COMPLETE: The table segment supporting the materialized view is truncated and repopulated completely using the associated query.
- FORCE: A fast refresh is attempted. If one is not possible a complete refresh is performed.
- FAST VS COMPLETE: FAST refresh only updates rows while COMPLETE refresh completely removes all data and inserts all data from the query.
Trigger types:
- ON COMMIT: The refresh is triggered by a comitted data change in one of the dependent tables.
- ON DEMAND: The refresh is initiated by a manual request or a scheduled task.
- Refreshing on commi is very intensive on a volative base table.
Prebuilt:
- ON PREBUILT TABLE: use existing table which must have same name as materialized view and same column structure as the query.
- QUERY REWRITE: tells optimizer if materilized view should be considered for qery rewrite operations.
Schedule:
- The
START WITH ... NEXT ...
specifies a schedule.
- The
Refresh on demand
A materialized view can be refreshed either manually or as part of a refresh group or via a schedule.
Refresh manually:
1
2
3
4
5EXEC DMBS_MVIEW.refresh('mvt1');
-- For PL/SQL, use this:
begin
DBMS_MVIEW.REFRESH('mvt1');
end;Create a refresh group:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25BEGIN
DBMS_REFRESH.make(
name => 'SCOTT.MINUTE_REFRESH',
list => '',
next_date => SYSDATE,
interval => '/*1:Mins*/ SYSDATE + 1/(60*24)',
implicit_destroy => FALSE,
lax => FALSE,
job => 0,
rollback_seg => NULL,
push_deferred_rpc => TRUE,
refresh_after_errors => TRUE,
purge_option => NULL,
parallelism => NULL,
heap_size => NULL);
END;
/
BEGIN
DBMS_REFRESH.add(
name => 'SCOTT.MINUTE_REFRESH',
list => 'SCOTT.EMP_MV',
lax => TRUE);
END;
/Create a schedule(must be specified at the creation of the materialized view):
1
2
3
4
5
6create materialized view mvt1
build immediate
refresh force on demand
start with sysdate next sysdate + 1/24/60 -- Refresh every minute
as
select * from mvtt;The materialized view
mvt1
will be refreshed every minute. An Oracle job is also created at the same time.
To find out the job id, use this query:
1 | select m.owner, m.mview_name, r.job |
Examples
- Create a test table
mvtt
:
ind | name |
---|---|
1 | a |
- Create a materialized view:
1 | create materialized view mvt1 |
Now mvt1
has the same data as mvtt
. Insert a new row will not trigger an update in mvtt
because its trigger type is on demand
.
Analytic Function/Window Function
Key points
- Analytic functions calculate an aggregate value based on a group of rows and return multiple rows for each group.
- Analytic functions are just like GROUP BY aggregate functions, but do not reduce rows retured.
- Syntax:
analytic_function([ arguments ]) OVER (analytic_clause)
- Anytic clause can be broken down as:
[ query_partition_clause ] [ order_by_clause [ windowing_clause ] ]
- Anytic clause can be broken down as:
Example
1 | CREATE TABLE emp ( |
- Get average department salary for each row
1 | SELECT empno, deptno, sal, |
- Get first value order by salary, put NULL values last in he sorted query results
- Note:
- In terms of sorting, SQL sorts
NULL
values to last inASC
order and first inDESC
MAX
andMIN
ignoresNULL
values
- In terms of sorting, SQL sorts
- Note:
1 | SELECT empno, |
- Windowing clause: an extension of the
order_by_clause
, can only be used whenorder_by_clause
is present. - When there’s
order_by_clause
, a default windowing clause is attached:RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
- The fact it is RANGE, not ROWS, means it includes all rows with the same value as the value in the current row, even if they are further down the result set. As a result, the window may extend beyond the current row, even though you may not think this is the case.
1 | RANGE BETWEEN start_point AND end_point |
1 | SELECT empno, deptno, sal, |
1 | SELECT empno, deptno, sal, |
LAG
: Access the row at a given offset prior of the current row without using a self-join.- Ref
- Syntax:
1 | LAG(expression [, offset ] [, default ]) |
1 | SELECT e.empno, |
SUM
also supports windowing:
1 | SELECT e.empno, |
Others
Database link
1 | create public database link |
1 | -- user和password都不需要引号,如果passwrd有特殊字符,那就用双引号""包起来 |
Find all database links:
- DBA_DB_LINKS - All DB links defined in the database
- ALL_DB_LINKS - All DB links the current user has access to
- USER_DB_LINKS - All DB links owned by current user
INSERT MULTIPLE ROWS
- Use
INSERT ALL
to insert multiple rows:
1 | CREATE TABLE employee ( |
MD5
1 | CREATE OR REPLACE FUNCTION MD5( |