ORACLE: PL/SQL

download report

Transcript ORACLE: PL/SQL

An Introduction to
Oracle DBMS Architecture
and
Server-Side Programming
Victor Matos
Department of Computer and Information Science
Cleveland State University
1
CONTENTS
Introduction
Oracle Architecture
PL/SQL Programming
Supplied Packages
Collections and Records
Objects
Cursors
Batch Processing
Exceptions
Packages
Triggers
Mutating Tables
Example Package (OLD)
3
18
127
213
222
272
309
333
344
357
367
397
423
CREDITS.
This document is a collage of notes taken from
2
1.
Oracle Documentation Files (www.oracle.com)
2.
Fundamentals of Database Systems by Elmasri & Navathe. Ed. Addison Wesley
3.
Oracle – The Complete Reference by Koch & Loney. Ed. Oracle Press
4.
Microsoft On-Line Help files (www.microsoft.com)
5.
V. Matos lecture notes
What is ORACLE ?
• Very robust implementation of a
Relational Database Management
System (RDBMS)
• The relational model of data is simple to
understand and has been extensively
scrutinized since 1970’s
3
What else is good about ORACLE ?
• The company is solid and successful,
since 1994 revenues in the order
of $2+ billion/year (~ $3BD in 2005)
• Very popular software,
worldwide distribution
(≈ 41% world market in 2007)
• Runs in different
type of computers.
4
Reasons for the Oracle Success
• Security Mechanisms users are given specific
rights to operate on the data.
• Backup and Recovery minimizes data loss and
idle time in the presence of failures
• Space Management flexible allocation
• Open Connectivity uninterrupted services
reachable from heterogeneous clients
• Development Tools
many to choose from
5
Software Support on the Oracle Server
• Procedural Option: built-in programming
capabilities based on the PL/SQL language
• Stored Procedures: programs stored in the
server-side could be invoked using an ADA-like
interface
• Triggers: dormant server-side routines which
are ‘fired’ when specific maintenance conditions
are met
6
Parts of the Oracle Server
cont
• Packages:
libraries of server-side routines including proc,
functions, triggers, user defined data types,
constants, variables, etc.
ORACLE
PACKAGES
Various
Clients
ORACLE
SERV ER
Same set of Proc,
functions, datatype, const, etc
7
Parts of the Oracle Server
cont
Distributed Option:
• Data could be stored in different machines and
placed in different cities.
• Oracle Distributed option provides location
transparency, the user does not need to be aware
of where the data is kept.
8
Oracle Distributed Option
Cleveland, Ohio
Ohio
Inventory
Workstation
SELECT PartNumber, Price
FROM Ohio_inventory, suppliers
WHERE inv_sup = Sup_Numb;
Indians95 Oraccle Server
NETWORK
New York, NY.
Suppliers
Yankees96 ORACLE Server
9
Oracle Distributed Option
Homogenous Distributed Database Systems
A homogenous distributed database system is a network of two or more
Oracle Databases that reside on one or more machines
Heterogeneous
Distributed Database
Systems
- In a heterogeneous distributed
database system, at least one of
the databases is a non-Oracle
Database system.
- To the application, the
heterogeneous distributed
database system appears as a
single, local, Oracle Database.
- The local Oracle Database
server hides the distribution and
heterogeneity of the data.
10
Oracle Distributed Option
Location Transparency
•
For a client application, the location and
platform of the databases are transparent.
•
You can also create synonyms for remote
objects in the distributed system so that
users can access them with the same
syntax as local objects.
•
For example, if you are connected to local
database MFG but want to access data on
remote database HQ, creating a synonym
on mfg for the remote emp table enables
you to issue this query:
SELECT * FROM emp;
same as
SELECT * FROM [email protected];
•
In this way, a distributed system gives the
appearance of native data access.
•
Users on mfg do not have to know that the
data they access resides on remote
databases.
11
Parts of the Oracle Server
cont
Parallel Server Option:
• Independent machines (nodes) which their own
memory and disk space could tap into a common
disk database.
• This loosely coupled architecture provides data
sharing and message exchange between processes
12
Parallel Server Option
NODE 1
Cleveland, Ohio
NODE 2
New York, NY.
NY data
Ohio data
Shared
Database
Indians95 Oraccle Server
Yankees96 ORACLE Server
13
Parts of the Oracle Server
cont
Parallel Query Option:
• Computers holding more than one CPU (such as
multiPentium Windows NT, XT, …) could use those
processors in solving independent portions of a
query.
• An Oracle control unit breaks the query into
pieces, and re-assembles the partial results.
14
Parallel Query Option
Cleveland, Ohio
Original SQL
statement
SELECT LastName, Dno
FROM Employee
WHERE (salary > 70000) or (sex = 'F')
Ohio data
Pentium 1
SELECT LastName, Dno
FROM
Employee
WHERE (salary > 70000)
Indians95 Oraccle Server
Dual Pentium
Window s NT4.0
Pentium 2
OR
SELECT LastName, Dno
FROM
Employee
WHERE (sex = 'F')
Results
15
Links to ORACLE Products & Services
www.oracle.com
TECHNOLOGY PRODUCTS
Database and Grids
Middleware | Data Hubs
Developer Tools
Security | Search
Enterprise Management
Business Intelligence
Collaboration | Content
Data Warehousing
Standards | Java | Linux
Downloads
APPLICATION PRODUCTS
Customer Relationship Management
Financial Accounting
Human Resources
Supply Chain
Public Sector Applications
Banking Applications
Retail Applications
Telecom Applications
Higher Education Applications
Other Industries
ORACLE SERVICES
Support | Education
On Demand
Financing
INSIGHT | Consulting
16
Links to ORACLE Products & Services
www.oracle.com
INDUSTRIES
Oracle has solutions for many industry segments such as.
Automotive
Banking
Engineering &
Construction
Download (PDF)
Download (PDF)
Download (PDF)
Government
Healthcare
Human Capital
Management
Download (PDF)
Download (PDF)
Download (PDF)
Government
Download (PDF)
Manufacturing
Download (PDF)
Government
Download (PDF)
Retail
Download (PDF)
Telecommunications
Download (PDF)
17
Components of Typical Oracle Server
Data Dictionary
Permanent Storage
Memory & Processes
18
Oracle Server – Database Dictionary
The Database dictionary is a read-only set of tables and
views that provides information about the database.
A data dictionary contains:
■ The definitions of all schema objects in the database (tables, views, indexes,
clusters, synonyms, sequences, procedures, functions, packages, triggers, and so on)
■ How much space has been allocated for, and is currently used by, the schema objects
■ Default values for columns
■ Integrity constraint information
■ The names of Oracle users
■ Privileges and roles each user has been granted
■ Auditing information, such as who has accessed or updated various schema objects
■ Other general database information
The data dictionary tables and views for a given database are stored in that database’s
SYSTEM tablespace.
19
Oracle Server – Database Dictionary
How the Data Dictionary Is Used
The data dictionary has three primary uses:
■ Oracle accesses the data dictionary to find information about
users, schema objects, and storage structures.
■ Oracle modifies the data dictionary every time that a data
definition language (DDL) statement is issued.
■ Any Oracle user can use the data dictionary as a read-only
reference for information about the database.
Data Dictionary View Prefixes
Prefix Scope
USER
User’s view (what is in the user’s schema)
ALL
Expanded user’s view (what the user can access)
DBA
Database administrator’s view (what is in all users’ schemas)
20
ORACLE Architecture
A. What is inside of the database dictionary?
SYSTEM SQL> column COMMENTS format a35 wrap
SYSTEM SQL> select * from DICTIONARY;
TABLE_NAME
-----------------------------DBA_ROLES
DBA_PROFILES
USER_RESOURCE_LIMITS
USER_PASSWORD_LIMITS
USER_CATALOG
ALL_CATALOG
DBA_CATALOG
USER_CLUSTERS
ALL_CLUSTERS
DBA_CLUSTERS
…
DBA_SQLSET_DEFINITIONS
USER_SQLSET_DEFINITIONS
1821 rows selected.
COMMENTS
--------------------------------------All Roles which exist in the database
Display all profiles and their limits
Display resource limit of the user
Display password limits of the user
Tables, Views, Synonyms and Sequences
owned by the user
All tables, views, synonyms, sequences
accessible to the user
All database Tables, Views, Synonyms,
Sequences
Descriptions of user's own clusters
Description of clusters accessible
to the user
Description of all clusters in the
database
Synonym for DBA_SQLSET
Synonym for USER_SQLSET
21
ORACLE Architecture
B. What is inside of a table?
SCOTT_SQL> describe
Name
------------------FNAME
MINIT
LNAME
SSN
BDATE
ADDRESS
SEX
SALARY
SUPERSSN
DNO
Employee
Null?
Type
-------- ------------------------VARCHAR2(10)
CHAR(1)
NOT NULL VARCHAR2(15)
NOT NULL CHAR(9)
DATE
VARCHAR2(28)
CHAR(1)
NUMBER(10,2)
CHAR(9)
NUMBER(38)
NOTE: You could use desc instead of describe
22
ORACLE Architecture
B. What tables do I have?
SCOTT_SQL> select table_name, blocks, num_rows
from user_tables;
TABLE_NAME
BLOCKS
NUM_ROWS
------------------------------ ---------- ---------DEPENDENT
5
7
DEPARTMENT
5
3
DEPT_LOCATIONS
5
5
PROJECT
5
6
JUNK
5
1
PAY_CHECK_TABLE
5
3
WORKS_ON
5
17
EMPLOYEE
5
8
7 rows selected.
23
Physical Database Structures
Datafiles
• Every Oracle database has one or more physical datafiles.
• The datafiles contain all the database data.
• The data of logical database structures, such as tables and indexes, is physically stored in the datafiles
allocated for a database.
The characteristics of datafiles are:
■ A datafile can be associated with only one database.
■ Datafiles can have certain characteristics set to let them automatically extend when the database
runs out of space.
■ One or more datafiles form a logical unit of database storage called a tablespace.
■ Data in a datafile is read, as needed, during normal database operation and stored in the memory
cache of Oracle.
Example.
Assume that a user wants to access some data in a table of a database. If the requested information is not
already in the memory cache for the database, then it is read from the appropriate datafiles and stored in
memory. Modified or new data is not necessarily written to a datafile immediately. To reduce the amount
of disk access and to increase performance, data is pooled in memory and written to the appropriate
datafiles all at once, as determined by the database writer process (DBWn) background process.
24
ORACLE Architecture
•A database consists of one or
more logical storage units called
tablespaces, which collectively
store all of the database’s data.
•Each tablespace consists of one
or more files called datafiles.
•Datafiles are physical structures
that conform to the operating
system in which Oracle is running.
25
ORACLE Architecture
Exploring TABLESPACE definitions
SYSTEM SQL> desc v$tablespace
Name
-----------------------------------TS#
NAME
INCLUDED_IN_DATABASE_BACKUP
BIGFILE
FLASHBACK_ON
ENCRYPT_IN_BACKUP
Type
------------NUMBER
VARCHAR2(30)
VARCHAR2(3)
VARCHAR2(3)
VARCHAR2(3)
VARCHAR2(3)
This DATABASE
instance is called
XE
SYSTEM SQL> select * from v$tablespace;
TS#
---------0
1
2
4
3
NAME
-----------------SYSTEM
UNDO
SYSAUX
USERS
TEMP
5 rows selected.
INC
--YES
YES
YES
YES
NO
BIG
--NO
NO
NO
NO
NO
FLA ENC
--- --YES
YES
YES
YES
YES
26
ORACLE Architecture
Enlarging a Database by Adding a Datafile to a Tablespace
Enlarging a Database by Adding a New Tablespace
27
ORACLE Architecture
Enlarging a Database by Dynamically Sizing
Datafiles
28
ORACLE Architecture
Physical Storage and its relationship to Oracle logical components
[Database, TableSpace, Schema Objects (Tables, Indices, Clusters,…)]
29
ORACLE Architecture
The logical organization and operation of Oracle DBMS is very similar to
the IBM370 Virtual Memory, Multitasking computers of the late 70’s.
30
ORACLE Architecture
LOGICAL DATA STRUCTURES
• Oracle stores data in data blocks. One data block
corresponds to a specific number of bytes of physical
database space on disk.
• The next level of logical database space is an extent.
An extent is a specific number of contiguous data
blocks allocated for storing a specific type of
information.
• The level of logical database storage greater than an
extent is called a segment. A segment is a set of
extents, each of which has been allocated for a specific
data structure and all of which are stored in the same
tablespace.
• For example, each table’s data is stored in its own
data segment, while each index’s data is stored in its
own index segment. If the table or index is
partitioned, each partition is stored in its own segment.
31
ORACLE Architecture
Data Block Format
The Oracle data block
format is similar regardless
of whether the data block
contains table, index, or
clustered data.
32
Physical Database Structures
Control Files
Every Oracle database has a control file. A control file contains entries that specify the
physical structure of the database. For example, it contains the following information:
■ Database name
■ Names and locations of datafiles and redo log files
■ Time stamp of database creation
Oracle can multiplex the control file, that is, simultaneously maintain a number of identical control file
copies, to protect against a failure involving the control file.
Every time an instance of an Oracle database is started, its control file identifies the database and redo log
files that must be opened for database operation to proceed.
If the physical makeup of the database is altered (for example, if a new datafile or redo log file is created),
then the control file is automatically modified by Oracle to reflect the change.
A control file is also used in database recovery.
33
Physical Database Structures
Control Files
Create controlfile reuse set database "XE"
MAXINSTANCES 8
MAXLOGHISTORY 1
MAXLOGFILES
16
MAXLOGMEMBERS 3
MAXDATAFILES 100
Datafile
'C:\oraclexe\oradata\XE\system.dbf',
'C:\oraclexe\oradata\XE\undo.dbf',
'C:\oraclexe\oradata\XE\sysaux.dbf',
'C:\oraclexe\oradata\XE\users.dbf'
LOGFILE
GROUP 1 SIZE 51200K,
GROUP 2 SIZE 51200K,
RESETLOGS;
34
Physical Database Structures
Redo Log Files
• Every Oracle database has a set of two or more redo log files.
• The primary function of the redo log is to record all changes made to data. If a failure prevents modified
data from being permanently written to the datafiles, then the changes can be obtained from the redo log, so
work is never lost.
• To protect against a failure involving the redo log itself, Oracle allows a multiplexed redo log so that two
or more copies of the redo log can be maintained on different disks.
• The information in a redo log file is used only to recover the database from a system or media failure that
prevents database data from being written to the datafiles.
Example.
If an unexpected power outage terminates database operation, then data in memory cannot be written to the
datafiles, and the data is lost. However, lost data can be recovered when the database is opened, after
power is restored. By applying the information in the most recent redo log files to the database datafiles,
Oracle restores the database to the time at which the power failure occurred. The process of applying the
redo log during a recovery operation is called rolling forward.
35
Physical Database Structures
Other Control Files
Archive Log Files
Permanent (disk) images of REDO logs.
Parameter Files
Parameter files contain a list of configuration parameters for that instance and database.
Alert and Trace Log Files
The alert file, or alert log, is a special trace file. The alert log of a database is a
chronological log of messages and errors. Each server and background process can write to
an associated trace file. When an internal error is detected by a process, it dumps
information about the error to its trace file.
Backup Files
To restore a file is to replace it with a backup file. Typically, you restore a file when a media
failure or user error has damaged or deleted the original file.
36
Oracle Memory & Transactions
Oracle uses memory to store information such as the following:
■ Program code
■ Information about a connected session, even if it is not currently
active
■ Information needed during program execution (for example, the
current state of a query from which rows are being fetched)
■ Information that is shared and communicated among Oracle
processes (for example, locking information)
■ Cached data that is also permanently stored on peripheral memory
(for example, data blocks and redo log entries)
37
Oracle Memory & Transactions
The basic memory structures associated with Oracle include:
■ System Global Area (SGA), which is shared by all server and
background processes.
■ Program Global Areas (PGA), which is private to each server and
background process; there is one PGA for each process.
38
Oracle Memory & Transactions
System Global Area
• The System Global Area (SGA) is a shared memory region that contains
data and control information for one Oracle instance.
• Oracle allocates the SGA when an instance starts and deallocates it when
the instance shuts down.
• Each instance has its own SGA.
• Users currently connected to an Oracle database share the data in the SGA.
• For optimal performance, the entire SGA should be as large as possible
(while still fitting in real memory) to store as much data in memory as
possible and to minimize disk I/O.
39
Oracle Memory & Transactions
System Global Area
The information stored in the SGA is divided into several types of memory structures
• Database Buffer Cache of the SGA Database buffers store the most recently used
blocks of data. The set of database buffers in an instance is the database buffer cache. The
buffer cache contains modified as well as unmodified blocks. Because the most recently
(and often, the most frequently) used data is kept in memory, less disk I/O is necessary,
and performance is improved.
• Redo Log Buffer of the SGA The redo log buffer stores redo entries—a log of changes
made to the database. The redo entries stored in the redo log buffers are written to an
online redo log table, which is used if database recovery is necessary.
• Shared Pool of the SGA The shared pool contains shared memory constructs, such as
shared SQL areas. A shared SQL area is required to process every unique SQL statement
submitted to a database. A shared SQL area contains information such as the parse tree and
execution plan for the corresponding statement. A single shared SQL area is used by
multiple applications that issue the same statement, leaving more shared memory for other
uses.
40
Oracle Memory & Transactions
Database Buffer Cache
The database buffer cache is the portion of the SGA that holds copies of data blocks
read from datafiles.
Organization of the Database Buffer Cache.
The buffers in the cache are organized in two lists:
• The WRITE list holds dirty buffers, which contain data that has been modified but
has not yet been written to disk.
• The LRU list holds free buffers, pinned buffers, and dirty buffers that have not yet
been moved to the write list.
Free buffers do not contain any useful data and are available for use.
Pinned buffers are currently being accessed.
When an Oracle process accesses a buffer, the process moves the buffer to the most recently used
(MRU or HOT SIDE) end of the LRU list.
As more buffers are continually moved to the MRU end of the LRU list, dirty buffers age toward the
41
LRU end (COLD SIDE) of the LRU list.
Oracle Memory & Transactions
Database Buffer Cache
The WRITE List holds dirty buffers, which contain data that has been
modified but has not yet been written to disk.
Dirty
Ready
for disk
Dirty
Ready
for disk
The LRU list holds free buffers, pinned buffers, and dirty buffers
that have not yet been moved to the write list.
Dirty
Moving
to WL
Dirty
Moving
to WL
Pinned
(in use)
Pinned
(in use)
Pinned
(in use)
Free
Free
COLD side
HOT side
(least rec. used)
(most rec. used)
Free
42
Oracle Memory & Transactions
Least Recently Used (LRU) Method - Memory Management
The first time an Oracle user process requires a particular piece of data, it searches for the data in
the database buffer cache.
1.
If the process finds the data already in the cache (a cache hit), it can read the data directly from
memory.
2.
If the process cannot find the data in the cache (a cache miss), it must copy the data block from a
datafile on disk into a buffer in the cache before accessing the data (accessing data through a cache hit is
faster than data access through a cache miss).
3.
Before writing a data block into the cache, the process must first find a free buffer.
1.
The process searches the LRU list, starting at the least recently used end of the list. The process
searches either until it finds a free buffer or until it has searched the threshold limit of buffers.
2.
If the user process finds a dirty buffer as it searches the LRU list, it moves that buffer to the write
list and continues to search.
3.
When the process finds a free buffer, it reads the data block from disk into the buffer and moves
the buffer to the MRU end (HOT SIDE) of the LRU list.
4.
If an Oracle user process searches the threshold limit of buffers without finding a free buffer, the
process stops searching the LRU list and signals the DBW0 background process to write some of
the dirty buffers to disk.
43
ORACLE Transactions
Example.
Transfer $500 from savings to checking account.
• A transaction is a logical unit of work that
contains one or more SQL statements.
• A transaction is an atomic unit. The effects
of all the SQL statements in a transaction can
be either all committed (applied to the
database) or all rolled back (undone from
the database).
• A transaction begins with the first
executable SQL statement.
• A transaction ends when it is committed or
rolled back, either explicitly with a COMMIT
or ROLLBACK statement or implicitly when a
DDL statement is issued.
•Commit Write Immediate NoWait
•Commit Work
•Rollback ToSavePointName
44
ORACLE Processes
Introduction to Processes
All connected Oracle users must run two modules of code to access an
Oracle database instance.
■ Application or Oracle tool: A database user runs a database
application (such as a precompiler program) or an Oracle tool (such as
SQL*Plus), which issues SQL statements to an Oracle database.
■ Oracle database server code: Each user has some Oracle database
code executing on his or her behalf, which interprets and processes the
application’s SQL statements.
45
ORACLE Processes
An instance is a portion of the computers
memory and a collection of processes
required by Oracle to operate
46
ORACLE Processes
Background
Process
Acronym
Definition
Archiver
ARCH
Copies online REDO LOG files to a designated storage device
once it has become full
Checkpoint
CKPT
Updates datafile headers and control files on behalf of the LGWR
when a checkpoint is completed
Database Writer
DBWR
Writes data from the database buffer cache to the datafiles
Lock Process
LCKn
Performs inter-instance locking in a parallel server system
Log Writer
LGWR
Writes data from the redo log buffer to the redo log files. Updates
datafile headers and control files if CKPT is not enabled
Process Monitor
PMON
Performs process recovery when a user process fails
Recoverer
RECO
Recovers failures involving distributed transactions
System Monitor
SMON
Performs instance recovery at instance startup, does cleanup, and
reclaims temporary segments
Parallel Query
Qnnn
Performs parallel queries
Snapshot
SNPn
Performs automatic refreshes of snapshots and handles the server
job queues
47
ORACLE Processes
An Example of How ORACLE DBMS works
The following example is a simple illustration of the dedicated server
architecture of Oracle. Assume a database server machine is currently
running Oracle using multiple background processes.
1.
A client workstation runs a database application (in a user process)
such as SQL*Plus. The client application attempts to establish a
connection to the server using a SQL*Net driver.
2. The database server is currently running the proper SQL*Net driver.
The Listener process on the database server detects the connection
request from the client database application and creates a dedicated
server process on the database server on behalf of the user process.
3. The user executes a single SQL statement. For example, the user
inserts a row into a table.
48
ORACLE Processes
An Example of How ORACLE DBMS works (continuation)
4. The dedicated server process receives the statement. At this point, two
paths can be followed to continue processing the SQL statement:
4.1 If the shared pool contains a shared SQL area for an
identical SQL statement, the server process can use the
existing shared SQL area to execute the client's SQL statement.
4.2 If the shared pool does not contain a shared SQL area for
an identical SQL statement, a new shared SQL area is
allocated for the statement in the shared pool.
5.
In either case, a private SQL area is created in the session's PGA
and the dedicated server process checks the user's access
privileges to the requested data.
6.
The server process retrieves data blocks from the actual datafile, if
necessary, or uses data blocks already stored in the buffer
cache in the SGA of the instance.
49
ORACLE Processes
An Example of How ORACLE DBMS works (continuation)
7. The server process executes the SQL statement stored in the shared
SQL area.
8.
Data is first changed in the SGA. It is permanently written to disk
when the DBWR process determines it is most efficient to do so.
9. The LGWR process records the transaction in the online redo log
file only on a subsequent commit request from the user. If the
request is successful, the server sends a message across the network to
the user. If it is not successful, an appropriate error message is
transmitted.
10. Throughout this entire procedure, the other background processes are
running and watching for any conditions that require intervention. In
addition, Oracle is managing other transactions and preventing contention
between different transactions that request the same data.
50
These steps show only the most basic level of operations that Oracle performs.
ORACLE Management Tool
Explore the Oracle
architecture using
the ENTERPRISE
MANAGER (EM) web
tool (10g v10.1)
51
ORACLE Management Tool
52
ORACLE Management Tool
Explore the Oracle
architecture using
the ENTERPRISE
MANAGER (EM)
web tool.
53
ORACLE Management Tool
54
ORACLE Management Tool
55
ORACLE Tools
Explore/manage database using Oracle 10g Express Edition (v 10.2)
http://127.0.0.1:8080/apex/
56
ORACLE Tools
Explore/manage database using Oracle 10g Express Edition (v 10.2)
57
ORACLE Tools
Explore/manage database using Oracle 10g Express Edition (v 10.2)
58
ORACLE Tools
Explore/manage database using Oracle 10g Express Edition (v 10.2)
59
ORACLE Tools
Explore/manage database using Oracle 10g Express Edition (v 10.2)
60
ORACLE Tools
SQL*Plus is a simple text editor (notepad-like) connected to the
Oracle Server. It is useful for simple development tasks.
61
ORACLE Tools
SQL*Plus Connection String for Reaching a Remote Server.
Assume remote Oracle server instance named ORCL is hosted at
sancho.csuohio.edu. The following is a valid (although terribly
inconvenient) connection string for the user identified as: csuperson /
euclid.
SQL> connect csuperson @ (DESCRIPTION= (ADDRESS=(PROTOCOL=tcp)
(HOST=sancho.csuohio.edu)(PORT=1521) )
(CONNECT_DATA=(SERVICE_NAME=ORCL) ) ) / euclid
NOTE.
In Oracle 11g credentials (UserName/Password) are case sensitive. It is recommended
to use UPPER CASE values.
62
ORACLE Tools
SQL*Plus Connection String for Reaching a Remote Server.
A better way to connect to the remote Oracle server instance named ORCL hosted
at sancho.csuohio.edu requires us to add the following entry to the tnsnames.ora
file located in the path c:\…\server\NETWORK\ADMIN
SANCHO = (DESCRIPTION=
(ADDRESS=(PROTOCOL=tcp)
(HOST=sancho.csuohio.edu)(PORT=1521) )
(CONNECT_DATA=(SERVICE_NAME=ORCL) )
)
To use this definition with SQL*Plus the csuperson user should enter
SQL>
connect CSUPERSON/[email protected]
 case sensitive
63
See note on: Database Links
ORACLE Tools
SQL Developer is a sophisticated IDE connected to the Oracle Server.
Useful for complex server-side tasks. Originally part of JDeveloper.
64
Making .sql scripts with SQL*Plus
How to know what Objects are already there?
--myObjects.sql
--useful script showing user’s objects
column object_name format a40 wrap
select
from
where
and
order
object_name, object_type
obj
object_name not like 'BIN$%'
object_name not like 'SYS_%'
by 2, 1
SCOTT SQL> desc obj
Name
Type
------------------- -------------OBJECT_NAME
VARCHAR2(128)
SUBOBJECT_NAME
VARCHAR2(30)
OBJECT_ID
NUMBER
DATA_OBJECT_ID
NUMBER
OBJECT_TYPE
VARCHAR2(19)
CREATED
DATE
LAST_DDL_TIME
DATE
TIMESTAMP
VARCHAR2(19)
STATUS
VARCHAR2(7)
TEMPORARY
VARCHAR2(1)
GENERATED
VARCHAR2(1)
SECONDARY
VARCHAR2(1)
65
SQL * Plus
Tools for creating Oracle Objects
SQL*Plus is a command-line tool that provides access to the Oracle RDBMS.
SQL*Plus enables you to:
■ Enter SQL*Plus commands to configure the SQL*Plus environment
■ Startup and shutdown an Oracle database
■ Connect to an Oracle database
■ Enter and execute SQL commands and PL/SQL blocks
■ Format and print query results
■ SQL*Plus is available on several platforms. In addition, it has a web-based user
interface, iSQL*Plus.
66
SQL * Plus
Basic SQL*Plus Commands
Log in to SQL*Plus
SQLPLUS [ { username[/passward][@connect_identifier] | / }
[ AS { SYSDBA | SYSOPER } ]
| /NOLOG
]
List help topics available in SQL*Plus
HELP [ INDEX | topic ]
Execute host commands
HOST [ command ]
Show SQL*Plus system variables or environment settings
SHOW { ALL | ERRORS | USER | system_variable [, system_
variable] ...}
Alter SQL*Plus system variables or environment settings
SET system_variable value
Start up a database
STARTUP [ PFILE = filename ]
[ MOUNT [ dbname ] | NOMOUNT ]
Connect to a database
CONNECT [{username[/password] [@connect_identifier] | /}
[AS {SYSOPER | SYSDBA}
|{proxy_user [ username ]
[/password] [@connect_identifier]}
]
List column definitions for a table, view, or synonym, or specifications for a
function or procedure
DESCRIBE [ schema. ] object
Edit contents of the SQL buffer or a file
EDIT [ filename [ .ext ] ]
Get a file and load its contents into the SQL buffer
GET filename [ .ext ] [ LIST | NOLLIST ]
Save contents of the SQL buffer to a file
SAVE filename [ .ext ] [ CREATE | REPLACE | APPEND ]
List contents of the SQL buffer
LIST [ n | n m | n LAST ]
Delete contents of the SQL buffer
DEL [ n | n m | n LAST ]
Add new lines following current line in the SQL buffer
INPUT [ text ]
Append text to end of current line in the SQL buffer
APPEND text
Find and replace first occurrence of a text string in current line of the SQL buffer
CHANGE sepchar old [ sepchar [ new [ sepchar ] ] ]
sepchar can be any nonalphanumeric ASCII character such as "/" or "!“
67
SQL * Plus
Basic SQL*Plus Commands
Capture query results in a file and, optionally, send contents of file to default printer
SPOOL [ filename [ .ext ]
[ CREATE | REPLACE | APPEND | OFF | OUT ]
Run SQL*Plus statements stored in a file
@ { url | filename [ .ext ] } [ arg ... ]
START { url | filename [ .ext ] } [ arg ... ]
ext can be omitted if the filename extension is .sql
Execute commands stored in the SQL buffer
/
List and execute commands stored in the SQL buffer
RUN
Execute a single PL/SQL statement or run a stored procedure
EXECUTE statement
Disconnect from a database
DISCONNECT
Shut down a database
SHUTDOWN [ ABORT | IMMEDIATE | NORMAL ]
Log out of SQL*Plus
{ EXIT | QUIT }
[ SUCCESS | FAILURE | WARNING ]
[ COMMIT | ROLLBACK ]
68
Basic SQL * Plus Commands
Remark
Set headsep
Ttitle
Btitle
Column
Break on
Compute sum
Set linesize
Set pagesize
Set newpage
Spool
/* */
-Set pause
Line comments
The heading separator is a single char
used to split a title into two or more lines
Sets the top page-title
Sets the bottom page-title
Formatting, heading of a column.
Put spaces between sections of a report
Calculates subtotal
Number of characters per line.
Nuber of lines per page.
Number of blank lines between pages.
Re-route report from screen to file.
Comment delimiters.
(Minus Minus) In-line comment.
Stop screen displaying.
69
Basic SQL * Plus Commands
Save
Host
Start @
Edit
Define_Editor
Saves current SQL query to disk.
Send any command to the host
operating system.
Execute the instructions saved on file
Call editor
Customize editor selection.
NOTE: The editor is not part of Oracle.
For instance, use NOTEPAD.EXE in
windows.
Example
Define_editor = “Notepad”
Define_editor = “c:\Program Files\Notepad++\notepad++.exe -/sql“
70
Basic SQL * Plus Commands
SET HEADSEP
set headsep !
The symbol ! indicates where you want to
break a page title or a column heading that
runs longer than a line.
71
Basic SQL * Plus Commands
COLUMN
column
column
column
Item
Item
Item
heading 'What Was!Sold'
format
a18
truncated
• Heading indicates the column’s title. Instead of Item,
the column’s name is a two-line header displaying
“What was” (line1), “Sold” (line2).
• Format indicates the layout of the output value.
A18 indicated alphanumeric, 18 characters wide.
A999.99 is an example of a numeric format.
• Truncated tells the report facility to cut strings longer
than 18. Other option is WRAP.
72
Basic SQL * Plus Commands
Numeric Format
column Rate format 90.99
• Format 90.99 reserves space for a numeric
field of at most four digits.
• For numbers less than 1 - such as 1/2 - , the
output should be printed using a zero rather
than a blank. In our example output should be
_0.50 instead of _.50
73
Basic SQL * Plus Commands
SET PAGESIZE, LINESIZE
set linesize 79
set pagesize 50
set newpage
0
• Linesize Total number of characters per line
is set to 79.
• Pagesize Total number of lines -icluding
top/bottom titles- is set to 50.
• NewPage Sets the number of blank lines
printed of top of the report.
74
Basic SQL * Plus Commands
SPOOLING
spool c:\activity.lst
spool off
• Spool <filename> All of the SQL output
that normally is delivered to the screen will
also be routed to a disk file -in the example
Activity.lst.
• Spool Off Stops the routing of data to the
file. Next output goes to the screen only.
• Use the disk file as a common ASCII text file.
75
Basic SQL * Plus Commands
HOST $
Pass any valid command to your
operating system (WIN, DOS, Unix…)
SQL> host copy a:\x.sql c:\y.sql
SQL> $ xcopy a:\*.* c:\Junk /s
SQL> host mv aaa bbb
76
Basic SQL * Plus Commands
Checking the SQL*PLUS Environment
Use the SHOW command to
see settings
SQL> show ttitle
SQL> show headsep
SQL> show pagesize
SQL> show all
Reset the different
environment variables
SQL>
SQL>
SQL>
SQL>
ttitle off
btitle off
clear columns
clear breaks
Note: Use the ‘column’
command to see column
formatting.
77
Basic SQL * Plus Commands
How to create SQL scripts
– Call your editor: SQL> EDIT myQuery1.sql
– Type in the SQL command(s)
– File | Close the editing session
– Execute the script with the SQL*PLUS command:
SQL>
@myQuery1
or RUN myQuery1
– Repeat the process if necessary
78
Basic SQL * Plus Commands
Example: Login.sql - A script to setup current session
set
set
set
set
feedback
echo
verify
pagesize
OFF
OFF
ON
50, linesize 120, ServerOutput ON
set SqlPrompt "&_user &_connect_identifier>"
SELECT * FROM V$VERSION;
prompt
prompt
prompt
==============================================
This is my ORACLE 10g (10.2) Xpress Edition
==============================================
column F1 format A39, F2 format A39
set feedback ON
79
Basic SQL * Plus Commands
Example: Whoami.sql - Exploring current session
------
----------------------------------------------------------------------Filename:
Whoami.sql
Purpose:
information about your current database session
Author:
Victor Matos Date: 8-Feb-2008
-----------------------------------------------------------------------
set feedback OFF
column global_name format a60 wrap
select USER, TO_CHAR(SYSDATE, 'DD MON YYYY HH24:MI:SS') Now,
USERENV('Terminal') as Terminal,
USERENV('SESSIONID') as "Session ID"
from Dual;
select * from global_name;
set feedback ON
80
Basic SQL * Plus Commands
Example: Options.sql - Showing Version and Installed Options
-------
----------------------------------------------------------------------Filename:
Options.sql
Purpose:
Show database version with options intalled/unistalled
Date:
8-Feb-2008
Author:
Victor Matos
-----------------------------------------------------------------------
clear screen
set head ON, feedback OFF, verify
ON
set linesize 100, pagesize 25
column banner format a70 wrap, parameter format a40 wrap, value
select banner as Version from
format a10
sys.v_$version;
select Decode(value,'TRUE','ON', 'OFF
from sys.v_$option order by 1, 2;
') Status, parameter
set feedback ON
81
Basic SQL * Plus Commands
Links to Useful Oracle On-Line Resources
http://www.oracle.com/pls/db102/homepage
http://www.orafaq.com/scripts/index.htm#GENSQL
http://www.dbasupport.com/oracle/
http://www.oracle-base.com/dba/DBACategories.php
http://www.oraclepower.com/WebPortal/webportal
http://www.oradev.com
82
Basic SQL * Plus Commands
Using other editors
• NOTEPAD is the Windows default editor.
• To change the editor -for instance- to
NotePad++ you enter the following command
Define_Editor = “c:\Program Files\Notepad++\Notepad++.exe -/sql “
Define_Editor = “vi”
__________
Notepad++ is a free GNU source code editor and Notepad replacement, which supports
several programming languages, running under the MS Windows environment.
83
Objects reachable from the
Oracle Enterprise Manager Tool
Oracle
Objects
Instance
Storage
Security
Memory Parameters
All Initialization Parameters
Controlfiles
Tablespaces
Datafiles
Rollback Segments
Redo Log Groups
Archive Logs
Temporary Tablespace Groups
Users
Roles
Profiles
Schema
Tables
Indexes
Views
Synonyms
Sequences
Database Links
Warehouse
Packages
Package Bodies
Procedures
Functions
Triggers
Java Sources
Java Classes
Array Types
Object Types
Table Types
Cubes
OLAP Dimensions
Measure Folders
Dimensions
Materialized Views
Materialized View Logs
Oracle
Objects
Objects seen
from the Oracle’s
JDeveloper and
SQLDeveloper
Tools
ORACLE Objects
How to create objects in ORACLE
Objects in an ORACLE database are typically created in the following order
1. create database
2. create tablespace(s)
3. create rollback segment (s)
4. create user(s)
5. create table(s)
6. create index
7. create other objects such as: sequence, cluster, procedure, function,
package, trigger, link, profile, synonym, schema, snapshot, view, etc.
86
ORACLE Objects
1. CREATE DATABASE Command
Creates, initialize, and mounts a database, making it available for
general use. The following actions are performed









Creates the datafiles for the database
Creates the control files
Creates the redo log files and establishes the ARCHIVELOG mode.
Creates the SYSTEM tablespace
Creates the SYSAUX tablespace
Creates the data dictionary
Sets the character set that stores data in the database
Sets the database time zone
Mounts and opens the database for use
Warning:
This command prepares a database for initial use and erases any data currently in
the specified files. Only use this command when you understand its ramifications.
87
ORACLE Objects
CREATE DATABASE Command (Example 2)
CREATE DATABASE myNewDB
USER SYS
IDENTIFIED BY mypassword1
USER SYSTEM IDENTIFIED BY mypassword2
LOGFILE GROUP 1 ('c:/oradata/mynewdb/redo01.log') SIZE 100M,
GROUP 2 ('c:/oradata/mynewdb/redo02.log') SIZE 100M,
GROUP 3 ('c:/oradata/mynewdb/redo03.log') SIZE 100M
MAXLOGFILES
5
MAXLOGMEMBERS 5
MAXLOGHISTORY 1
MAXDATAFILES 100
MAXINSTANCES 1
CHARACTER SET US7ASCII NATIONAL CHARACTER SET AL16UTF16
CREATE TABLESPACE SYSTEM
DATAFILE 'c:/oradata/mynewdb/system01.dbf'
CREATE TABLESPACE SYSAUX
DATAFILE 'c:/oradata/mynewdb/sysaux01.dbf'
CREATE TABLESPACE TEMP
DATAFILE 'c:/oradata/mynewdb/temp01.dbf'
CREATE TABLESPACE USERS
DATAFILE 'c:/oradata/mynewdb/users01.dbf'
SIZE 325M REUSE
SIZE 325M REUSE
SIZE 20M REUSE
SIZE 20M REUSE
DEFAULT TABLESPACE Users
DEFAULT TEMPORARY TABLESPACE Temp
88
ORACLE Objects
CREATE DATABASE Command (Example 2)
A database is created with the following characteristics:
1.
The database is named mynewdb. Its global database name is mynewdb.us.oracle.com.
2.
The password for user SYS is mypassword1 and the password for SYSTEM is mypassword2.
The two clauses that specify the passwords for SYS and SYSTEM are not mandatory in Express
Oracle. However, if you specify either clause, you must specify both clauses.
3.
The new database has three redo log files as specified in the LOGFILE clause. MAXLOGFILES,
MAXLOGMEMBERS, and MAXLOGHISTORY define limits for the redo log.
4.
MAXDATAFILES specifies the maximum number of datafiles that can be opened in the database.
This number affects the initial sizing of the control file.
5.
MAXINSTANCES specifies that only one instance can have this database mounted and opened.
89
ORACLE Objects
CREATE DATABASE Command (Example 2)
•
The US7ASCII character set is used to store data in this database.
•
The AL16UTF16 character set is specified as the NATIONAL CHARACTER SET, used to
store data in columns specifically defined as NCHAR, NCLOB, or NVARCHAR2.
•
The SYSTEM tablespace, consisting of the operating system file c:/oradata/mynewdb/
system01.dbf is created as specified by the DATAFILE clause. If a file with that name already
exists, it is overwritten.
•
A SYSAUX tablespace is created, consisting of the operating system file c:/oradata/
mynewdb/sysaux01.dbf as specified in the SYSAUX DATAFILE clause.
•
The DEFAULT TABLESPACE clause creates and names a default permanent tablespace for
this database.
•
The DEFAULT TEMPORARY TABLESPACE clause creates and names a default
temporary tablespace for this database.
90
ORACLE Objects
CREATE DATABASE Command (Example 2)
Redo log files will not initially be archived, because the ARCHIVELOG clause is not
specified in this CREATE DATABASE statement.
1.
This is customary during database creation.
2.
You can later use an ALTER DATABASE statement to switch to ARCHIVELOG
mode.
91
ORACLE Objects
CREATE DATABASE Command (Example 3)
create table MyTable
(col1 varchar2 primary key)
tablespace testdata
storage (initial 50M next 100M pctincrease 20
minextents 1 maxextents 200);
Tracing the growth of the database:
Base
Original size:
After Extend 1:
After Extend 2:
After Extend 3:
After Extend 4:
After Extend 5:
...
<Extend>
Fixed Add Pct% Add
[---50---] [---100---] [---10---]
[---160---] [---100---] [---32---]
[---292---] [---100---] [---58---]
[---450---] [---100---] [---90---]
[---640---] [---100---] [---128---]
[---868---] [---100---] [---173---]
Total
Size
160MB
292MB
450MB
640MB
868MB
1131MB
92
ORACLE Objects
2.1 How to create a TableSpace
CREATE TABLESPACE PayRoll
DATAFILE 'C:\ORADATA\PayRoll.dat' SIZE 10M
DEFAULT STORAGE (
INITIAL
10K
Associate applications (such as PayRoll,
NEXT
50K
HR, Inventory, CustomerAccounts, etc) to
MINEXTENTS 1
individual and separated tablespaces
MAXEXTENTS 999
PCTINCREASE 10)
ONLINE;
93
ORACLE Objects
2.2 Exploring a TableSpace
Asking for the datafiles, and tablespaces in the current database
SYSTEM SQL>
SELECT file_name,
tablespace_name,
bytes
FROM dba_data_files;
FILE_NAME
---------------------------------------C:\ORACLEXE\ORADATA\XE\USERS.DBF
C:\ORACLEXE\ORADATA\XE\SYSAUX.DBF
C:\ORACLEXE\ORADATA\XE\UNDO.DBF
C:\ORACLEXE\ORADATA\XE\SYSTEM.DBF
C:\ORADATA\PAYROLL.DAT
TABLESPACE_NAME
--------------USERS
SYSAUX
UNDO
SYSTEM
PAYROLL
BYTES
---------104857600
461373440
94371840
356515840
10485760
94
ORACLE Objects
2.3 How to eliminate a tablespace
DROP TABLESPACE PayRoll
INCLUDING CONTENTS
CASCADE
CONSTRAINTS;
HOST del C:\ORADATA\PayRoll.dat;
95
ORACLE Objects
CREATE USER
Purpose
• Use the CREATE USER statement to create and configure a database
user.
• A user is an access account through which you can log in to the
database.
Prerequisites
• You must have the CREATE USER system privilege.
• To log on to Oracle Database, a user must have the CREATE SESSION
system privilege.
Example
Create user Macarena identified by salsa;
Grant connect, resource to Macarena;
Note:
1. Macarena’s workarea is not explicitly indicated, therefore she is
implicitly associated to the default table space.
2. To eliminate permanently a user issue the command
96
drop user Macarena [Cascade]
ORACLE Objects
Create User
97
ORACLE Objects
Create User
SCOTT / TIGER
• During the Oracle setup process a demo user SCOTT/TIGER is
usually created
• The tables visible to scott/tiger are
TABLE_NAME
-----------------DEPT
EMP
BONUS
SALGRADE
DUMMY
CUSTOMER
ORD
ITEM
PRODUCT
PRICE
98
ORACLE Objects
Useful script to CREATE USER
--- MAKEUSER
Victor Matos 15-Oct-94. (SYSTEM/JEFE)
--- ------------------------------------------------------------------------ Supervisor must be connected to the server==> ORCL (or XE for XEdition)
--- Use this script to create a single user. The script should be executed
--- by the SYSTEM_DBA. It will prompt for LOGIN and PASSWORD values.
--- ---------------------------------------------------------------------set verify OFF
prompt Creating a single user at XE (<<--database name)
prompt
accept login_name char PROMPT '
LOGIN_NAME: '
accept password
char PROMPT '
PASSWORD:
'
drop user &&login_name CASCADE;
Change to PAYROLL (if needed)
create user &&login_name identified by &&password default tablespace USERS –
temporary tablespace SYSAUX quota unlimited on SYSTEM;
grant connect, resource, create session, create view
to &&login_name identified by &&password;
99
ORACLE Objects
Useful script to CREATE USER (cont.)
--- Sending a copy of the SCOTT.EMP and SCOTT.DEPT tables to the new user
drop
drop
table &&login_name..EMP;
table &&login_name..DEPT;
COPY
FROM scott/[email protected] TO
&&login_name/&&[email protected] CREATE emp USING select * from SCOTT.EMPLOYEE;
Change to ORCL (if needed)
COMMIT;
COPY
FROM scott/[email protected] TO
&&login_name/&&[email protected] CREATE dept USING select * from SCOTT.DEPARTMENT;
COMMIT;
--- Verify tables created for new user
select
table_name, owner
from
all_tables
where
owner = UPPER ('&&login_name');
100
ORACLE Objects
Useful script to DROP USER
--- DROPUSER
Victor Matos (30-JAN-2008). (SYSTEM/JEFE)
--- ----------------------------------------------------------------------------------- Must be issued by Supervisor or Creator
--- Use this script to eliminate a single user. The script should be executed
--- by the SYSTEM_DBA. It will prompt for LOGIN and PASSWORD values.
--- --------------------------------------------------------------------------------set verify OFF
prompt Dropping a single user at XE (<<--database name)
prompt
accept login_name char PROMPT ' LOGIN_NAME: '
accept password char PROMPT ' PASSWORD: '
drop user &&login_name CASCADE;
101
ORACLE Objects
3. VIEWS
• A view is a tailored presentation of the data contained in
one or more tables or other views.
• A view takes the output of a query and treats it as a table.
• A view can be thought of as a stored query or a virtual
table.
• You can use views in most places where a table can be
used.
For example
the employees table has several columns and numerous rows of
information. If you want users to see only some of these columns or only
specific rows, then you can create a view of that table for other users to
access.
102
ORACLE Objects
VIEWS
SCOTT SQL>create
view LADIES as
select Fname, Lname, Salary, Dno
from Employee
where sex = 'F';
SCOTT SQL> select * from LADIES;
FNAME
---------Alicia
Jennifer
Joyce
LNAME
SALARY
DNO
--------------- ---------- ---------Zelaya
25000
4
Wallace
43000
4
English
25000
5
SCOTT SQL>
103
ORACLE Objects
VIEWS are often used to:
Provide an additional level of table security by restricting access to a predetermined set of rows
or columns of a table.
Hide data complexity
For example, a single view can be defined with a join, which is a collection of related columns or rows
in multiple tables. However, the view hides the fact that this information actually originates from several
tables.
Simplify statements for the user
For example, views allow users to select information from multiple tables without actually knowing how
to perform a join.
Present the data in a different perspective from that of the base table
For example, the columns of a view can be renamed without affecting the tables on which the view is
based.
Isolate applications from changes in definitions of base tables
For example, if a view’s defining query references three columns of a four
column table, and a fifth column is added to the table, then the view’s definition
is not affected, and all applications using the view are not affected.
Express a query that cannot be expressed without using a view
For example, a view can be defined that joins a GROUP BY view with a table, or a
view can be defined that joins a UNION view with a table.
Save complex queries
For example, a query can perform extensive calculations with table information. By saving this query as
a view, you can perform the calculations each time the view is queried.
104
ORACLE Objects
4. Sequence Generator (Autonumbers)
The sequence generator provides a sequential series of numbers.
CREATE SEQUENCE customers_ID
START WITH 1000
INCREMENT BY 1;
• The sequence generator is especially useful in multiuser
environments for generating unique sequential numbers without
the overhead of disk I/O or transaction locking.
•The first reference to customers_ID.nextval returns 1000.
• The second returns 1001.
• Each subsequent reference will return a value 1 greater than the
previous reference.
•Any reference to .currval always returns the current value of the
sequence
105
ORACLE Objects
EXAMPLE. Creating/Using a Sequence
CREATE SEQUENCE customers_ID
START WITH 1000
INCREMENT BY 1;
drop table junk;
create table junk (col1 integer, col2 varchar2(20));
insert into junk values (customers_id.nextval, 'AAA');
insert into junk values (customers_id.nextval, 'BBB');
insert into junk values (customers_id.nextval, 'CCC');
select * from junk;
select customers_id.CURRVAL from DUAL;
CURRVAL
-------1002
COL1 COL2
------ ----1000 AAA
1001 BBB
1002 CCC
106
ORACLE Objects
5. Indexes
Indexes are optional structures associated with tables and clusters.
You can create indexes on one or more columns of a table to speed SQL statement
execution on that table.
CREATE INDEX employees_idx1 ON employee (Fname, Lname);
CREATE INDEX employees_idx2 ON employee (SSN);
Oracle provides several indexing schemes, which provide complementary
performance functionality:
• B-tree indexes
• B-tree cluster indexes
• Hash cluster indexes
• Bitmap indexes
• Bitmap join indexes
107
ORACLE Objects
Internal Structure of a B-Tree Index
108
ORACLE Objects
CLUSTERS
A cluster is a schema object
that contains data from one
or more tables, all of which
have one or more columns in
common.
For better performance Oracle
stores together all the rows
from all the tables that share
the same cluster key.
In the example Dept# is used
to create an articulation point
between EMPLOYEE and
DEPARTMENT tables.
109
ORACLE Objects
--Create Cluster area based on common Dept# key
CREATE CLUSTER EmpDeptCluster (Department INTEGER)
SIZE 512 STORAGE (initial 100K next 50K);
--Create an Index for the Cluster
CREATE INDEX idx_EmpDeptCluster ON CLUSTER EmpDeptCluster ;
--Adding Tables to the Cluster
CREATE TABLE departmentC
CLUSTER EmpDeptCluster (Dnumber) AS
SELECT * FROM department;
Joining field(s)
Dnumber = Dno
CREATE TABLE employeeC
CLUSTER EmpDeptCluster (Dno) AS
SELECT * FROM employee;
110
ORACLE Objects
CLUSTERS make efficient computation of JOIN operations relating tables
tied by a common index.
SELECT fname, dno, dnumber, dname
FROM employeeC e JOIN departmentC d
ON e.dno = d.dnumber;
FNAME
DNO
DNUMBER DNAME
---------- ---------- ---------- --------------James
1
1 Headquarters
Alicia
4
4 Administration
Jennifer
4
4 Administration
Ahmad
4
4 Administration
John
5
5 Research
Franklin
5
5 Research
Ramesh
5
5 Research
Joyce
5
5 Research
drop
drop
drop
drop
INDEX idx_EmpDeptCluster;
TABLE deptartmentC;
TABLE employeeC;
CLUSTER EmpDeptCluster ;
111
ORACLE Objects
Hash Clusters
 Hashing is a technique for storing table data to improve the
performance of data retrieval.
 To use hashing, create a hash cluster and load tables into the cluster.
 Oracle physically stores the rows of a table in a hash cluster and
retrieves them according to the results of a hash function.
 Hash clusters are a better choice than using an indexed table or index
cluster when a table is queried frequently with equality queries (for
example, return all rows for department 10).
112
ORACLE Objects
Hash Clusters (cont.)
 Oracle uses a hash function to generate a distribution of numeric
values, called hash values, which are based on specific cluster key values.
The key of a hash cluster, like the key of an index cluster, can be a single
column or composite key (multiple column key).
To find or store a row in a hash cluster, Oracle applies the hash function
to the row's cluster key value. The resulting hash value corresponds to a
data block in the cluster, which Oracle then reads or writes on behalf of
the issued statement.
113
ORACLE Objects
Hash Clusters (cont.)
drop table demoemp;
Creating a cluster
drop cluster demo_cluster;
CREATE CLUSTER demo_cluster (DNO NUMBER(3))
TABLESPACE users
STORAGE (INITIAL 250K
MINEXTENTS 1
NEXT 50K
MAXEXTENTS 3
PCTINCREASE 0)
HASH IS Mod(DNO,10) HASHKEYS 10;
CREATE TABLE DemoEmp(
SSN
NUMBER(10) PRIMARY KEY,
Fname
varchar2(20),
Lname
varchar2(20),
Dno
NUMBER(3)
)
CLUSTER demo_cluster (DNO);
114
ORACLE Objects
Hash Clusters (cont.) Using a Cluster
insert into demoEmp (ssn, fname, lname, DNO) select ssn, fname, lname, DNO from employee;
select * from demoEmp where dno = 5;
Demo_Cluster
0:
1: PointerTo (1)
2:
Key =
Employee.dno
3:
Loc = MOD(dno,10)
4: PointerTo (2,3,4)
5: PointerTo (5,6,7,8)
6:
7:
8:
9:
115
ORACLE Objects
Bitmap Indexes
 In a bitmap index, a binary string (or bitmap) is made to
represent the actual key value held by each record.
 Each bit in the bitmap corresponds to a possible rowid. If the
bit is set, then it means that the row with the corresponding rowid
contains the key value.
 Bitmap indexing efficiently merges indexes that correspond to
several conditions in a WHERE clause. Rows that satisfy some, but
not all, conditions are filtered out before the table itself is
accessed. This improves response time, often dramatically.
116
ORACLE Objects
Bitmap Indexes
Evaluate
SELECT COUNT(*)
FROM CUSTOMER
WHERE MARITAL_STATUS = 'married'
AND REGION IN ('central','west');
117
ORACLE Objects
Bitmap Index Example
Create a bitmap on Department values for the Employee table.
CREATE BITMAP INDEX idx_Bmp_Employee
ON Employee(dno)
TABLESPACE Users;
118
Using SQL * Plus to create Objects
Create User Command
Creates a database user, or an account through which you can log in to the
database. You can optionally assign the following properties to the user:
• default tablespace
• temporary tablespace
• quotas for allocating space in tablespaces
• profile containing resource limits
Example: You can create the user MARIA by issuing the following statement:
CREATE USER Maria
IDENTIFIED BY Macarena
DEFAULT TABLESPACE payroll_ts
QUOTA 10M ON payroll_ts
QUOTA 5M ON temp_ts
QUOTA 5M ON system
PROFILE accountant;
Grant Connect, Resource to Maria;
119
Using SQL * Plus to create Objects
CREATE USER Command
120
ORACLE Objects
PROFILE
A profile is used to set user limits on database resources. If you assign the
profile to a user, then that user cannot exceed these limits.
CREATE PROFILE CONSULTANT
LIMIT SESSIONS_PER_USER
CPU_PER_SESSION
CPU_PER_CALL
CONNECT_TIME
LOGICAL_READS_PER_SESSION
LOGICAL_READS_PER_CALL
PRIVATE_SGA
COMPOSITE_LIMIT
UNLIMITED
UNLIMITED
3000
45
DEFAULT
1000
15K
5000000;
CREATE USER Maria
IDENTIFIED BY Macarena
DEFAULT TABLESPACE example
QUOTA 10M ON example
QUOTA 5M ON system
TEMPORARY TABLESPACE temp
PROFILE
consultant
PASSWORD EXPIRE;
121
Using SQL * Plus to create Objects
6. TABLES
•
•
•
Tables are the basic unit of data storage in an Oracle database.
Data is stored in rows and columns.
Typical datatypes are: CHAR, VARCHAR2, NUMBER, DATE
•
Each row has a unique (invisible) database-wide identifier called RowID
•
Each row has a unique serial (invisible) autonumber called RowNum.

A row is a collection of column information corresponding to a single record.

You can optionally specify rules for each column of a table. These rules are called
integrity constraints. Example: NOT NULL, PRIMARY KEY, CHECK…

Once you create a table, you insert rows of data using SQL statements.

Table data can then be queried, deleted, or updated using SQL.
122
Using SQL * Plus to create Objects
6. Record Identifiers
CSUPERSON SQL> SELECT rownum, rowid, p.* FROM Project p;
NOTE
• The fields RowNum and RowID must be explicitly requested in a query.
• RowNum changes when rows are inserted/deleted.
• However RowID is permanently attached to each row until the record is deleted.
123
Using SQL * Plus to create Objects
CREATE TABLE Command
To define the EMP2 table you could issue the following statement.
CREATE TABLE emp2 (
empno
NUMBER
CONSTRAINT pk_emp PRIMARY KEY,
ename
VARCHAR2(10)
CONSTRAINT nn_ename
NOT NULL
CONSTRAINT upper_ename CHECK (ename = UPPER(ename)),
CONSTRAINT unique_ename UNIQUE(ename),
job
VARCHAR2(9),
mgr
NUMBER
CONSTRAINT fk_mgr REFERENCES emp2(empno),
hiredate DATE DEFAULT SYSDATE,
sal
NUMBER(10,2) CONSTRAINT ck_sal CHECK (sal > 500),
comm
NUMBER(9,0) DEFAULT NULL,
deptno
NUMBER(2)
DEFAULT 20
CONSTRAINT nn_deptno NOT NULL
CONSTRAINT fk_deptno REFERENCES dept(deptno) )
PCTFREE 5
124
PCTUSED 75 ;
Using SQL * Plus to create Objects
Create Table Command
Notes
1- This table contains 8 columns. Ex: EMPNO column is of datatype NUMBER and has an
associated integrity constraint named PK_EMP.
2- HIREDDATE column is of datatype DATE and has a default value of SYSDATE.
3- PCTFREE of 5 indicates that a minimum 5% of space is reserved for future updates
4- PCTUSED says that a maximum of 75% of the table should be used on each data block
5- The constraint on the mgr field indicates that such a value (mgr’s id) must also be found in
the emp2 table (a recursive reference)
125
Using SQL * Plus to create Objects
Create Table Command
Notes
1.
The PCTFREE parameter sets the
minimum percentage of a data
block to be reserved as free space
for possible updates to rows that
already exist in that block.
2.
The PCTUSED parameter sets the
maximum percentage of a block
that can be used for row data plus
overhead.
After a data block is filled to the
limit determined by PCTFREE,
Oracle considers the block
unavailable for the insertion of
new rows until the percentage of
that block falls beneath the
parameter PCTUSED. Until this
value is achieved, Oracle uses the
free space of the data block only
for updates to rows already
contained in the data block. .
126
Using SQL * Plus to create Objects
Create Table Command. Typical data types
Data Type
Use
CHAR
Alpha-numeric,
Fixed data length
Alphanumeric,
variable-length
Numeric data:
Integers an float
Date data such as:
‘01-APR-97’
VARCHAR2
NUMBER
DATE
127
Using SQL * Plus to create Objects
DEFINING A COMPOUND KEY
CREATE TABLE works_on (
essn
char(9),
pno
number,
hours
number(5,1),
PRIMARY KEY (essn, pno),
FOREIGN KEY (Essn) REFERENCES Employee(Ssn),
FOREIGN KEY (Pno) REFERENCES Project(Pnumber))
NOTE. You may also use the ALTER TABLE command.
ALTER TABLE Works_On ADD PRIMARY KEY (essn, pno);
ALTER TABLE Works_On ADD CONSTRAINT pk_works_on
PRIMARY KEY (essn, pno);
128
Using SQL * Plus to create Objects
Create Table Command.
Example II. Assuming you have the parallel query option, then the fastest method to create a
table that has the same columns as the EMP table, but only for those employees in department 10,
is to issue a command similar to the following:
CREATE TABLE emp_tmp
UNRECOVERABLE
PARALLEL (DEGREE 3)
AS
SELECT *
FROM
employee
WHERE dno = 5;
Notes
1- The UNRECOVERABLE keyword speeds up table creation because there is no overhead in
generating and logging redo information.
2- Parallelism speeds up the creation of the table.
3- After the table is created, querying the table is also faster because the same degree of
parallelism is used to access the table.
129
Using SQL * Plus to create Objects
Database Links
A database link is a schema object in one database that enables you to access objects on another database.
Named Link: You specify the username and password used to connect to the remote database.
drop database link SanchoLink;
create database link SANCHOLINK
connect to csuperson
identified by euclid
using '(DESCRIPTION= (ADDRESS=(PROTOCOL=tcp)
(HOST=sancho.csuohio.edu)(PORT=1521) )
(CONNECT_DATA=(SERVICE_NAME=ORCL) ) )' ;
Anonymous Link: The current session’s username/password is used to enter in the remote database.
drop database link SanchoLink;
create database link SANCHOLINK using 'sancho‘;
Note: In this example ‘SANCHO’ is an entry already defined in the control file tnsnames.ora.
Example: select * from [email protected];
CAUTION: Credentials for Oracle11g are case sensitive! If your account in the remote computer is
130
CSUPERSON/EUCLID you must log in the current with exactly the same userName/password.
Using SQL * Plus to create Objects
Summary – What objects do I have?
-----
AUTHOR
V. Matos 8-Feb-2008
FILE
obj.sql
PURPOSE
List all objects accessible to the user.
-----------------------------------------------------------------------
set verify OFF, feedback OFF
column owner format a12, object_name format a35 wrap, object_type format a12
clear screen
select
o.owner
,o.object_name
,o.object_type
from
all_objects o
where
o.owner
like upper (nvl('&v_Owner',user))
and
o.object_name like upper ('%&v_Object_Name%')
and
o.object_name not like 'BIN$%'
and
o.object_name not like 'SYS_%'
and
o.object_type like upper ('%&v_Object_Type%')
order by o.owner
,o.object_type
,o.object_name;
set feedback on
131
PL/SQL
PROGRAMMING
132
ORACLE: PL/SQL
What is PL/SQL ?
• PL/SQL is a portable, high-performance transaction
processing language.PL/SQL stands for Procedural extensions
to SQL.
• It adds programming capabilities to Oracle-SQL. It is a
block-structured language with a syntax similar to classical
programming languages such as C, ADA, O-Pascal.
• It is not a stand-alone language (requires Oracle DBMS
server)
133
PL/SQL Programming
PL/SQL = Oracle SQL1 + Standard programming features
Support for typical programming features including
•
•
•
•
•
•
•
•
•
•
•
procedures, functions,
flow-control/iterative statements,
declared variables, constants,
primitive and user-defined types,
exception handling,
triggers,
packages,
objects, collections,
integration of SQL statements
interaction with the local OS,
anonymous blocks, etc.
Notes
1.
Oracle SQL is a superset of the American National Standards Institute (ANSI) and the International Standards
Organization (ISO) standard.
2.
Anonymous blocks are nameless fragments of code executed from script files
134
PL/SQL Architecture
CLIENT SIDE CODE
•
.NET languages
Java
C, C++
COBOL
MS-Access
Delphi
PowerBuilder
People’s Soft
SAP
HTML + scripts
(JavaScript, Perl, VBS)
Oracle Forms/Reports
ORACLE SERVER
CODE
ODBC
.NET
JDBC
Native Comm
PL-SQL (Oracle 7, 8, 9i, 10g…)
Java (Oracle8i, …)
...
135
PL/SQL Programming
Advantages of PL/SQL
■ Tight Integration with SQL
■ Thin client programming model with business logic on the server
■ Better enforcement of business rules, and standards
■ Better Performance (however creates bottleneck syndrome)
■ Higher Productivity
■ Full Portability
■ Tight Security
■ Access to Pre-defined Packages
■ Support for Object-Oriented Programming
■ Support for Developing Web Applications and Pages
136
PL/SQL Programming
Block-Structure
Declaration Section
Execution Section
Exception Section
137
PL/SQL Programming
Block-Structure
Procedure / Function / Trigger ObjectName (Arguments) ….
IS
Variable declaration;
...
BEGIN
Code to execute;
...
EXCEPTION
Error handling code;
...
END;
138
PL/SQL Programming
Structure of an ANONYMOUS block
DECLARE
Variable declaration;
...
BEGIN
Code to execute;
...
EXCEPTION
Error handling code;
...
END;
-- Smallest Anonymous block.
DECLARE
BEGIN
Null;
END;
139
PL/SQL Programming
PL/SQL Syntax
Assignment
Null statement
Blocks
x := x + 1;
Null;
Begin ... End;
Condition
Testing
if (condition) then
[ elsif (condition) then ]
[ else ]
end if;
Loops
For v in -1..10 Loop ... End Loop;
While (condition) Loop ... End Loop;
Loop ... End Loop
Conditional op. < ,<>, >, <= , >= , =
and, or, not
Logical op.
140
PL/SQL: Example-1
1. Use SQL*Plus. At the Oracle prompt enter the following line:
csuperson> Edit c:\sql\hello
create or replace
Procedure HELLO
Is
Begin
-- my first PL/SQL program
Dbms_Output.Put_Line ('Hello wonderful world');
End;
Note
Make sure your DBMS_OUTPUT environment variable has been set. Invoke SQL*Plus and enter:
SET SERVEROUTPUT ON
141
PL/SQL: Example-1
TESTING THE PROGRAM
…
CSUPERSON SQL> set serverOutput on
CSUPERSON SQL> exec hello
Hello world
PL/SQL procedure successfully completed.
CSUPERSON SQL>
HINT
You may add the statement set serverOutput on to your BIN\login.sql script
142
PL/SQL: Example-2
A function to retrieve the employee’s full name
create or replace
FUNCTION getName ( theSSN
IS
theTotal NUMBER;
theName VARCHAR2(40);
IN
NUMBER ) RETURN VARCHAR2
BEGIN
select count(*) into theTotal from employee
where SSN = theSSN;
if (theTotal = 0) then
RETURN('');
else
select (FName || ' ' || Lname) into theName
from employee
where SSN = theSSN;
RETURN (theName);
end if;
EXCEPTION
when others then
return ('***ERROR***');
END;
143
PL/SQL: Example-2
1- Testing the function
CSUPERSON SQL> variable xxx varchar2(40);
CSUPERSON SQL> exec :xxx := getName(123456789);
PL/SQL procedure successfully completed.
CSUPERSON SQL> print xxx
XXX
-------------------------------------------John Smith
CSUPERSON SQL>
144
PL/SQL: Example-2
2- Testing the function
SELECT getName(123456789) FROM DUAL;
GETNAME(123456789)
------------------------------------John Smith
145
PL/SQL: Example-2
2- Creating a Procedure
create or replace
PROCEDURE pGetName ( theSSN IN NUMBER, theName OUT VARCHAR2 )
IS
theTotal NUMBER;
BEGIN
select count(*) into theTotal from employee where SSN = theSSN;
if (theTotal = 0) then
theName := 'Nada---';
else
select (FName || ' ' || Lname) into theName
from employee
where SSN = theSSN;
end if;
EXCEPTION
when others then
theName := '***ERROR***';
END;
146
PL/SQL: Example-2
2- Testing a Procedure
CSUPERSON SQL> variable xxx varchar2(40);
CSUPERSON SQL> exec pGetName(123456789, :xxx);
PL/SQL procedure successfully completed.
CSUPERSON SQL> print xxx
XXX
----------------------------------------------John Smith
147
PL/SQL: Example-2
2- Testing a Procedure (again)
-- Anonymous block: Testing pGetName(…)
DECLARE
THESSN NUMBER;
THENAME VARCHAR2(200);
BEGIN
THESSN := 123456789;
PGETNAME ( THESSN, THENAME );
DBMS_OUTPUT.PUT_LINE('THENAME = ' || THENAME);
END;
148
PL/SQL: Example-3
3- Example of Procedure
-- Goal:
-- Author:
-- Date:
Find an employee’s salary as well as his/her direct supervisor’s SSN and salary
V. Matos
20-Feb-2008
create or replace
PROCEDURE PGETEMPSUPERSALARIES
( eSSN IN VARCHAR2
, eSalary OUT NUMBER
, sSSN OUT VARCHAR2
, sSalary OUT NUMBER
)
AS
vCounter Number;
BEGIN
--set default values for output variables
eSalary := 0;
sSSN := '***';
sSalary := 0;
--is there such an employee?
select count(*) into vCounter from employee where ssn = eSSN;
--if not just exit now
if (vCounter = 0) then return; end if;
149
PL/SQL: Example-3
3- Example of Procedure cont…
--get the employee's salary and supervisor's ssn
select salary, superSsn into eSalary, sSSN from employee where ssn = eSSN;
--if the employee has no supervisor the routine is terminated
if (sSSN is NULL) then return; end if;
--is there such an employee acting as a supervisor?
select count(*) into vCounter from employee where ssn = sSSN;
--if not just exit now
if (vCounter = 0) then return; end if;
--get the supervisor's salary
select salary into sSalary from employee where ssn = sSSN;
--in case of troubles do nothing
EXCEPTION
when others then return;
END PGETEMPSUPERSALARIES;
150
PL/SQL: Example-3
3- Testing the Procedure
cont…
--get the employee's salary and supervisor's ssn and salary
DECLARE
ESSN VARCHAR2(200); --employee’s SSN and salary
ESALARY NUMBER;
SSSN VARCHAR2(200); -- supervisor’s SSB and salary
SSALARY NUMBER;
BEGIN
ESSN := 123456789;
PGetEmpSuperSalaries(ESSN, ESALARY, SSSN, SSALARY );
DBMS_OUTPUT.PUT_LINE('ESALARY = ' || ESALARY);
DBMS_OUTPUT.PUT_LINE('SSSN = ' || SSSN);
DBMS_OUTPUT.PUT_LINE('SSALARY = ' || SSALARY);
END;
151
PL/SQL Programming
Creating/Debugging a Stored PL/SQL Function
This example shows how to create an debug a PL/SQL stored function using SQL*Plus
SQL> EDIT c:\sql\IsFile.sql
CREATE or REPLACE
FUNCTION IsFile ( MyTable IN VARCHAR2 ) RETURN ( boolean )
IS
result user_tables.table_name%TYPE;
BEGIN
SELECT table_name INTO result
Intentional
FROM
user_tables
error
WHERE table_name = UPPER(MyTable);
RETURN true;
EXCEPTION
WHEN No_Data_Found THEN RETURN false;
END;
/
152
PL/SQL Programming
Creating/Debugging a Stored PL/SQL Function
SQL> @c:\sql\isfile
Warning: Function created with compilation errors.
SQL> show errors
Errors for FUNCTION ISFILE:
Line and column where error was found
LINE/COL ERROR
-------- -------------------------------------------------1/47
PLS-00103: Encountered the symbol "(" when expecting
one of the following:<an identifier>
<a double-quoted delimited-identifier> LONG_ double
SQL> EDIT c:\sql\IsFile.sql
Use the editor to correct each
error in the script file
153
PL/SQL Programming
Testing /Debugging a Stored PL/SQL Function
Using an Anonymous Block
--Assume all errors of IsFile(…) are corrected
DECLARE
myResult boolean;
BEGIN
myResult := IsFile('Employee');
if (myResult) then
dbms_output.put_line('YES!');
else
dbms_output.put_line('NO');
end if;
END;
/
154
PL/SQL Programming
Anonymous Procedures
The following ANONYMOUS performs the following tasks:
• executes stored proc. GetEmpNameSal to obtain the name and salary of employee
whose SSN is 123456789. Results are saved into the table MYLOG (predefined)
• invokes the function RaiseSalary to increase the employee’s salary by 10%.
Again a new line is added to MYLOG reporting the new salary value.
-----
Name: Test.Sql
Anonymous Procedure to Test STORED routines
Uses: proc. GetEmpName, func. RaiseSalary
table Mylog (already created with two columns)
DECLARE
EmpName
varchar(20);
mSalary
number;
BEGIN
DELETE FROM Mylog;
Local memory variables defined to
store the employee’s name and salary
retrieved using the stored procedure
GetEmpNameSal (123456789, EmpName, mSalary);
INSERT INTO MyLog VALUES (mSalary, EmpName);
mSalary:= RaiseSalary(123456789, 0.10);
INSERT INTO MyLog VALUES (mSalary, EmpName);
END;
155
PL/SQL Programming
Testing the Anonymous Procedure
Running the anonymous script
SQL> @c:\sql\TEST
procedure successfully executed
SQL> select * from MYLOG;
COL1
--------30000
33000
COL2
----------------Smith, John
Smith, John
Results are placed into table MYLOG
156
PL/SQL Programming
PROCEDURE returning several results
-- GETEMPNAMESAL
CREATE or REPLACE
PROCEDURE GetEmpNameSal (
EmpSSN
IN number,
EmpName
OUT varchar,
EmpSalary OUT number )
IS
BEGIN
SELECT Lname ||', '|| Fname, Salary
INTO
EmpName, EmpSalary
FROM
Employee
OUT variables carry results
WHERE SSN = EmpSSN;
outside of the procedure
EXCEPTION
WHEN No_Data_Found THEN
INSERT INTO MyLog
VALUES (EmpSSN, 'ERROR. Emp not found');
EmpName:= '***';
EmpSalary:= -1;
END;
157
PL/SQL Programming
-- RaiseSalary: Function increases salary of certain employee by PctRaise
CREATE or REPLACE
FUNCTION RaiseSalary ( EmpSsn
number,
PctRaise number )
RETURN
number
IS
Default type is IN (put)
NewSalary
number;
OldSalary
number;
BEGIN
SELECT Salary INTO OldSalary FROM Employee
WHERE SSN = EmpSSN;
NewSalary:= OldSalary * (1 + PctRaise);
UPDATE Employee SET Salary = NewSalary
WHERE SSN = EmpSsn;
RETURN NewSalary;
Returned value
EXCEPTION
WHEN No_Data_Found THEN
INSERT INTO MyLog VALUES (EmpSSN, 'Not found');
RETURN -1;
158
END;
PL/SQL Programming
NOTE
l
We assume the general purpose table MYLOG (Col1, col2) has already
been defined.
Drop table MyLog;
Create Table MyLog ( Col1 varchar2(30),
Col2 varchar2(30) );
159
PL/SQL Programming
Anonymous Procedures
The following ANONYMOUS performs the following tasks:
• executes stored proc. GetEmpNameSal to obtain the name and salary of employee
whose SSN is 123456789. Results are saved into the table MYLOG (predefined)
• invokes the function RaiseSalary to increase the employee’s salary by 10%.
Again a new line is added to MYLOG reporting the new salary value.
-----
Name: Test.Sql
Anonymous Procedure to Test STORED routines
Uses: proc. GetEmpName, func. RaiseSalary
table Mylog (already created with two columns)
DECLARE
EmpName
varchar(20);
mSalary
number;
BEGIN
DELETE FROM Mylog;
Local memory variables defined to
store the employee’s name and salary
retrieved using the stored procedure
GetEmpNameSal (123456789, EmpName, mSalary);
INSERT INTO MyLog VALUES (mSalary, EmpName);
mSalary:= RaiseSalary(123456789, 0.10);
INSERT INTO MyLog VALUES (mSalary, EmpName);
END;
160
160
PL/SQL Programming
-- Version2: Testing Function using anonymous procedure
-- multiple parameters are referenced using named vars.
=> Notation (name, value)-pairs
DECLARE
allows passing of parameters in
EMPSSN
NUMBER;
any order
PCTRAISE NUMBER;
v_Return NUMBER;
BEGIN
EMPSSN := 123456789;
PCTRAISE := 10;
v_Return := RAISESALARY(EMPSSN => EMPSSN,
PCTRAISE => PCTRAISE );
DBMS_OUTPUT.PUT_LINE('v_Return = ' || v_Return);
END;
161
PL/SQL Programming
A Guide for Learning PL/SQL
•
•
•
•
•
•
•
•
•
•
•
•
•
Delimiters
Identifiers
Reserved words
Quoted Identifiers
Literals
Booleans
DateTime
Variable Declaration
Built-In DataTypes
Scope and Visibility
Assignments
Precedence of Operators
Logical Operators
•
•
•
•
•
Comparison Operators
NULLs
Built-In Functions
DateTime
Flow Control Structures
162
PL/SQL Programming
Identifiers
An identifier consists of a letter optionally followed by more letters, numerals, dollar
signs, underscores, and number signs. Other characters such as hyphens, slashes, and
spaces are not allowed (max. 30 chars).
Example: The following are VALID identifiers
custName,
Cust_name,
Cust_Number, CUST001,
CUST#,
CUST-NUMBER,
CustBalance$
Quoted Identifiers
PL/SQL lets you enclose identifiers within double quotes (not a very good idea!).
Quoted identifiers are seldom needed. They can contain any sequence of printable
characters including spaces but excluding double quotes.
Example: The following identifiers are valid:
"X+Y"
“Last Name” (similar to [Last Name] notation used in MS-Access, SQL-Server)
163
PL/SQL Programming
Reserved Words
Some identifiers, called reserved words, have a special syntactic meaning to
PL/SQL.
The following are reserved words
BEGIN, END,
LOOP,
IF,
PROCEDURE,
THEN, ELSE,
ELSIF,
FUNCTION,
DECLARE, TRIGGER, …
Often, reserved words are written in upper case for readability.
164
PL/SQL Programming
Literals
A literal is an explicit numeric, character, string, or Boolean value not represented
by an identifier.
Example: 123, 3.141592, 5E3 (same as 5000), ‘ABC’, ‘XYZ Corp.’, ‘Smith’,
‘SMITH’, ‘smith’, ‘’.
BOOLEAN Literals
BOOLEAN literals are the predefined values TRUE, FALSE, and NULL (NULL
stands for a missing, unknown, or inapplicable value).
Datetime Literals
Datetime literals have various formats depending on the datatype.
Example: '1998-12-25'; '1997-10-22 13:01:01'; ’19-Sep-2006’
Comments
Single-line comments begin with a double hyphen (--) anywhere on a line and
extend to the end of the line.Multi-line comments begin with a slash-asterisk (/*),
end with an asterisk-slash (*/), and can span multiple lines.
165
PL/SQL Programming
Defining/Initializing Variables
Salary
DeptNumber
LastName
Sex
JobType
BirthDate
Age
PI
NUMBER(10,2);
NUMBER (3) := 17;
VARCHAR2(20);
CHAR(1) := ‘F’;
CHAR(15);
DATE := ‘15-APR-96’;
SMALLINT;
REAL := 3.141592
Honorary
EmpRec
Employee.Salary%TYPE;
Employee%ROWTYPE;
Note. Most common data types are: NUMBER, VARCHAR2,
DATE, CHAR.
166
PL/SQL Programming
Built-in Datatypes
167
PL/SQL Programming
DECLARE
a CHAR;
b REAL;
BEGIN
-- identifiers available here: a (CHAR), b
DECLARE
a INTEGER;
c REAL;
BEGIN
-- identifiers available here: a (INTEGER), b, c
NULL;
END;
DECLARE
d REAL;
BEGIN
-- identifiers available here: a (CHAR), b, d
NULL;
END;
-- identifiers available here: a (CHAR), b
END;
/
168
PL/SQL Programming
Assigning Values to Variables
You can use assignment statements to assign values to variables using the := operator.
bonus := salary * 0.15;
• Variables and constants are initialized every time a block or subprogram is entered.
• By default, variables are initialized to NULL.
• Unless you expressly initialize a variable, its value is undefined (NULL)
Example
DECLARE
counter INTEGER;
BEGIN
-- COUNTER is initially NULL, so 'COUNTER + 1' is also null.
counter := counter + 1;
IF counter IS NULL THEN
DBMS_OUTPUT.PUT_LINE('COUNTER is NULL not 1.');
END IF;
END;
/
Note.
To avoid unexpected results, never reference a variable before you assign it a value.
169
PL/SQL Programming
Operator Precedence
170
PL/SQL Programming
Logical Operators
The logical operators are: AND, OR, and NOT.
Comparison Operators
IF (variable IS NULL) THEN ...
IF (last_name LIKE 'J%S_N‘) THEN ... --( % wild char any symbol(s), _
one char. This example finds values like Johnson, Jensen, …)
IF appointment BETWEEN 900 AND 1700 THEN ...
IF letter IN (‘A’, ‘b’, ‘m’) THEN ...
171
PL/SQL Programming
NULLs as Arguments to Built-In Functions
If a null argument is passed to a built-in function, a null is returned except in the case
of the NVL and DECODE functions.
The function DECODE compares its first argument to one or more search
expressions, which are paired with result expressions. Any search or result expression
can be null.
DECODE(superSsn, NULL, 'nobody', 'somebody')
DECODE(commission,NULL,0,Commission)
The function NVL returns the value of its second argument if its first argument is
null.
NVL(superSsn, 'Nobody')
NVL(commission, 0)
172
PL/SQL Programming
NULLs as Arguments to Built-In Functions
Using Decode
select ssn, decode(superSsn, null, ‘N.A.’, superSsn)
from employee;
SSN
--------123456789
333445555
999887777
987654321
666884444
453453453
987987987
888665555
DECODE(SU
--------333445555
888665555
987654321
888665555
333445555
333445555
987654321
N.A.
173
PL/SQL Programming
NULLs as Arguments to Built-In Functions
Using Decode
select e.ssn,
decode(superssn,null,
'NA',
(select lname from employee where ssn=e.superssn))
from employee e;
SSN
--------123456789
333445555
999887777
987654321
666884444
453453453
987987987
888665555
DECODE(SUPERSSN
--------------Wong
Borg
Wallace
Borg
Wong
Wong
Wallace
NA
174
PL/SQL
Built-in
Functions
175
PL/SQL Programming
Character functions
Character functions that return character
values are:
CHR
CONCAT
INITCAP
LOWER
LPAD
LTRIM
NLS_INITCAP
NLS_LOWER
NLSSORT
NLS_UPPER
REGEXP_REPLACE
REGEXP_SUBSTR
REPLACE
RPAD
RTRIM
SOUNDEX
SUBSTR
TRANSLATE
TREAT
TRIM
UPPER
Character functions that return number
values are:
ASCII
INSTR
LENGTH
REGEXP_INSTR
176
PL/SQL Programming
Character functions
-- testing primitive string functions
DECLARE
v1 varchar(100) := 'Hola mundo';
BEGIN
dbms_output.put_line (LENGTH(v1));
dbms_output.put_line (SUBSTR(v1,2,3));
dbms_output.put_line (INSTR(v1, 'ola'));
dbms_output.put_line (REPLACE(v1, 'mundo', 'world'));
dbms_output.put_line (UPPER(v1));
END;
/
10
ola
2
Hola world
HOLA MUNDO
177
PL/SQL Programming
The datetime functions are:
ADD_MONTHS
CURRENT_DATE
CURRENT_TIMESTAMP
DBTIMEZONE
EXTRACT (datetime)
FROM_TZ
LAST_DAY
LOCALTIMESTAMP
MONTHS_BETWEEN
NEW_TIME
NEXT_DAY
NUMTODSINTERVAL
NUMTOYMINTERVAL
ROUND (date)
SESSIONTIMEZONE
SYS_EXTRACT_UTC
SYSDATE
SYSTIMESTAMP
TO_CHAR (datetime)
TO_TIMESTAMP
TO_TIMESTAMP_TZ
TO_DSINTERVAL
TO_YMINTERVAL
TRUNC (date)
TZ_OFFSET
178
PL/SQL Programming
Example of datetime functions
-- testing primitive date functions
DECLARE
v0 date := sysdate;
v1 timeStamp:= sysdate;
BEGIN
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
END;
/
(v0);
(v1);
(TRUNC(v1));
(NEXT_DAY(v1, 'Friday'));
(LAST_DAY(v1));
(ADD_MONTHS(v1, 3));
(MONTHS_BETWEEN(v1, TO_DATE('01-01-2000','MM-DD-YYYY')));
(TO_CHAR(v1,'J'));
( TO_DATE(2454145,'J')); 25-FEB-08
(SESSIONTIMEZONE);
25-FEB-08 12.08.46.000000 AM
25-FEB-08
29-FEB-08
29-FEB-08
25-MAY-08
97.77438993428912783751493428912783751493
2454522
13-FEB-07
-05:00
Consult: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements004.htm#sthref408
179
PL/SQL Programming
Example of date formatting
-- testing primitive date formatting(cont.)
DECLARE
v0 date := sysdate;
v1 timeStamp:= sysdate;
BEGIN
dbms_output.put_line ('Timestamp ' || v1 );
dbms_output.put_line ('Date
' || v0 );
dbms_output.put_line ('DL
' || to_char(v0,
dbms_output.put_line ('DS
' || to_char(v0,
dbms_output.put_line ('D
' || to_char(v0,
dbms_output.put_line ('DD
' || to_char(v0,
dbms_output.put_line ('DDD
' || to_char(v0,
dbms_output.put_line ('DAY
' || to_char(v0,
dbms_output.put_line ('DY
' || to_char(v0,
dbms_output.put_line ('day
' || to_char(v0,
dbms_output.put_line ('MM
' || to_char(v0,
dbms_output.put_line ('MONTH ' || to_char(v0,
dbms_output.put_line ('YY
' || to_char(v0,
dbms_output.put_line ('YYYY
' || to_char(v0,
dbms_output.put_line ('Y,YYY ' || to_char(v0,
dbms_output.put_line ('YEAR
' || to_char(v0,
dbms_output.put_line ('HH
' || to_char(v0,
dbms_output.put_line ('HH AM ' || to_char(v0,
dbms_output.put_line ('HH24
' || to_char(v0,
dbms_output.put_line ('MI
' || to_char(v0,
dbms_output.put_line ('SS
' || to_char(v0,
dbms_output.put_line ('SSSSS ' || to_char(v0,
dbms_output.put_line ('W
' || to_char(v0,
dbms_output.put_line ('WW
' || to_char(v0,
dbms_output.put_line ('Q
' || to_char(v0,
END;
Timestamp 25-FEB-08 12.07.17.000000 AM
Date
25-FEB-08
DL
Monday, February 25, 2008
DS
2/25/2008
D
2
DD
25
DDD
056
DAY
MONDAY
DY
MON
day
monday
MM
02
MONTH February
YY
08
YYYY
2008
Y,YYY 2,008
YEAR
TWO THOUSAND EIGHT
HH
12
HH AM 12 AM
HH24
00
MI
07
SS
17
SSSSS 00437 sec midnight
W
4 week of month
WW
08 week of year
Q
1 quarter
'DL'));
'DS'));
'D'));
'DD'));
'DDD'));
'DAY'));
'DY'));
'day'));
'MM'));
'Month'));
'YY'));
'YYYY'));
'Y,YYY'));
'YEAR'));
'HH'));
'HH AM'));
'HH24'));
'MI'));
'SS'));
'SSSSS') || ' sec midnight');
'W') || ' week of month');
'WW') || ' week of year');
'Q') || ' quarter');
180
PL/SQL Programming
Date Format Element Suffixes
Suffix
TH
SP
SPTH or THSP
Meaning
Ordinal Number
Spelled Number
Spelled, ordinal number
Example Element
Example Value
DDTH
4TH
DDSP
FOUR
DDSPTH
FOURTH
Example of date formatting (cont.)
-- testing primitive date formatting (cont.)
DECLARE
V0 date := sysdate;
BEGIN
dbms_output.put_line (v0);
dbms_output.put_line ('DD
' || to_char(v0,
dbms_output.put_line ('DDTH
' || to_char(v0,
dbms_output.put_line ('DDSP
' || to_char(v0,
dbms_output.put_line ('DDTHSP ' || to_char(v0,
END;
/
'DD'));
'DDTH'));
'DDSP'));
'DDTHSP'));
25-FEB-08
DD
25
DDTH
25TH
DDSP
TWENTY-FIVE
DDTHSP TWENTY-FIFTH
181
PL/SQL Programming
Conversion Functions
Conversion functions convert a value from one datatype to
another. Generally, the form of the function names follows
the convention datatype TO datatype. The first datatype is the
input datatype. The second datatype is the output datatype.
The SQL conversion functions are:
ASCIISTR
BIN_TO_NUM
CAST
CHARTOROWID
COMPOSE
CONVERT
DECOMPOSE
HEXTORAW
NUMTODSINTERVAL
NUMTOYMINTERVAL
RAWTOHEX
RAWTONHEX
ROWIDTOCHAR
ROWIDTONCHAR
SCN_TO_TIMESTAMP
TIMESTAMP_TO_SCN
TO_BINARY_DOUBLE
TO_BINARY_FLOAT
TO_CHAR (character)
TO_CHAR (datetime)
TO_CHAR (number)
TO_CLOB
TO_DATE
TO_DSINTERVAL
TO_LOB
TO_MULTI_BYTE
TO_NCHAR (character)
TO_NCHAR (datetime)
TO_NCHAR (number)
TO_NCLOB
TO_NUMBER
TO_DSINTERVAL
TO_SINGLE_BYTE
TO_TIMESTAMP
TO_TIMESTAMP_TZ
TO_YMINTERVAL
TO_YMINTERVAL
TRANSLATE ... USING
UNISTR
182
PL/SQL Programming
Numeric Functions
Numeric functions accept numeric input and return numeric values. Most numeric functions that return
NUMBER values that are accurate to 38 decimal digits. The transcendental functions COS, COSH, EXP,
LN, LOG, SIN, SINH, SQRT, TAN, and TANH are accurate to 36 decimal digits. The transcendental
functions ACOS, ASIN, ATAN, and ATAN2 are accurate to 30 decimal digits. The numeric functions are:
ABS
ACOS
ASIN
ATAN
ATAN2
BITAND
CEIL
COS
COSH
EXP
FLOOR
LN
LOG
MOD
NANVL
POWER
REMAINDER
ROUND (number)
SIGN
SIN
SINH
SQRT
TAN
TANH
TRUNC (number)
WIDTH_BUCKET
183
PL/SQL Programming
Environment and Identifier Functions
The environment and identifier functions
provide information about the instance and
session. These functions are:
SYS_CONTEXT
SYS_GUID
SYS_TYPEID
UID
USER
USERENV
184
PL/SQL Programming
The aggregate functions are:
AVG
COLLECT
CORR
CORR_*
COUNT
COVAR_POP
COVAR_SAMP
CUME_DIST
DENSE_RANK
FIRST
GROUP_ID
GROUPING
GROUPING_ID
LAST
MAX
MEDIAN
MIN
PERCENTILE_CONT
PERCENTILE_DISC
PERCENT_RANK
RANK
VARIANCE
REGR_ (Linear Regression) Functions
STATS_BINOMIAL_TEST
STATS_CROSSTAB
STATS_F_TEST
STATS_KS_TEST
STATS_MODE
STATS_MW_TEST
STATS_ONE_WAY_ANOVA
STATS_T_TEST_*
STATS_WSR_TEST
STDDEV
STDDEV_POP
STDDEV_SAMP
SUM
VAR_POP
VAR_SAMP
185
PL/SQL Programming
PL/SQL Date Datatype
You use the DATE datatype to store fixed-length datetimes, which include the time
of day in seconds since midnight (eg. '22-JUN-2004 07:48:53.275'; ).
■ The date portion (22-JUN-2004) defaults to the first day of the current month; the time
portion (07:48:53.275'; ) defaults to midnight.
■ The date function SYSDATE returns the current date and time.
■ To compare dates for equality, regardless of the time portion of each date, use the
function result TRUNC(date_variable) in comparisons, GROUP BY operations, and so
on.
■ To find just the time portion of a DATE variable, subtract the date portion:
dateVariable - TRUNC(dateVariable).
■ Valid dates range from January 1, 4712 BC to December 31, 9999 AD.
■ A Julian date is the number of days since January 1, 4712 BC. Julian dates allow
continuous dating from a common reference.
■ You can use the date format model 'J' with the date functions TO_DATE and
TO_CHAR to convert between DATE values and their Julian equivalents.
■ In date expressions, PL/SQL automatically converts character values in the default
date format to DATE values.
186
Julian Day System
•
The Julian Day number system was invented by Joseph Justus Scaliger (born in France
in 1540). The system was named after the inventor's father, Julius Caesar Scaliger
(1484-1558).
•
A Julian date is the number of days since January 1, 4712 BC.
•
A Scalinger cycle lasts 7980 years (= 28 * 19 * 15).
•
The first Scaliger cycle began with Year 1 on -4712-01-01 (Julian) and will end after
7980 years on 3267-12-31 (Julian), which is 3268-01-22 (Gregorian).
•
The Julian day (jd) is computed from Gregorian day, month and year (d, m, y) as
follows:
jd = ( 1461 * ( y + 4800 + ( m - 14 ) / 12 ) ) / 4 +
( 367 * ( m - 2 - 12 * ( ( m - 14 ) / 12 ) ) ) / 12 ( 3 * ( ( y + 4900 + ( m - 14 ) / 12 ) / 100 ) ) / 4 +
d - 32075
187
PL/SQL Programming
Date/Time Examples
The following example returns the system timestamp:
SELECT SYSTIMESTAMP FROM DUAL;
SYSTIMESTAMP
-----------------------------------------------------------------28-MAR-00 12.38.55.538741 PM -04:00
The following example shows how to explicitly specify fractional seconds:
SELECT TO_CHAR(SYSTIMESTAMP, 'SSSSS.FF') FROM DUAL;
TO_CHAR(SYSTIME
--------------55615.449255
Expressing today’s date (18-Sep-2006) in JULIAN format
SELECT TO_CHAR(SYSTIMESTAMP, 'J') FROM DUAL;
TO_CHAR
------2453997
Number of days since 1-JAN-4712 BC
188
PL/SQL Programming
Date/Time Examples
How many days since 01-Jan-2000 (assume today is 18-Sep-2006)?
SELECT (TO_CHAR(SYSTIMESTAMP, 'J') –
TO_CHAR(TO_TIMESTAMP('01-JAN-2000'),'J')) as MillenniaDays
FROM DUAL
MILLENNIADAYS
------------2452
189
PL/SQL Programming
Character Functions - Examples
The following example returns several specified substrings of "ABCDEFG":
SELECT SUBSTR('ABCDEFG',3,4) FROM DUAL;
Substring
--------CDEF
SELECT SUBSTR('ABCDEFG',-5,4)
FROM DUAL;
Substring
--------CDEF
SELECT REPLACE('JACK and JUE','J','BL')FROM DUAL;
Changes
-------------BLACK and BLUE
190
PL/SQL Programming
Overview of PL/SQL Control Structures
IF (condition) THEN
statements;
ELSE
statements;
END IF;
DECLARE
sales NUMBER(8,2) := 12100;
bonus NUMBER(8,2);
empSSN NUMBER := 123456789;
BEGIN
IF (sales > 12000) THEN
bonus := 0.10 * sales + 500 ;
ELSE
bonus := 1;
END IF;
UPDATE employee SET salary = salary + bonus WHERE SSN = empSSN;
END;
/
191
PL/SQL Programming
IF (condition) THEN
statements;
ELSIF (condition) THEN
statements;
ELSE
statements;
END IF;
DECLARE
grade NUMBER(3) := 87;
letter CHAR(1);
BEGIN
IF (grade > 90) THEN
letter := 'A';
ELSIF (grade >80) THEN
letter := 'B';
ELSIF (grade >70) THEN
letter := 'C';
ELSE
letter := 'F';
END IF;
dbms_output.put_line('Grade: ' || to_char(Grade) || ' ' || letter
END;
);
192
PL/SQL Programming
DECLARE
gpa
NUMBER(1);
letter CHAR(1) := 'B';
BEGIN
CASE letter
WHEN 'A'
WHEN 'B'
WHEN 'C'
ELSE gpa
END CASE;
CASE varSelector
WHEN val1 THEN stmt1;
WHEN val2 THEN stmt2;
WHEN val3 THEN stmt3;
…
ELSE stmt-n;
END CASE;
THEN gpa := 4;
THEN gpa := 3;
THEN gpa := 2;
:= 0;
dbms_output.put_line('GPA: ' || to_char(gpa) || ' ' || letter
END;
/
);
193
PL/SQL Programming
Using the EXIT and LOOP Statements
The EXIT statement forces a loop to complete unconditionally. When an EXIT statement is
encountered, the loop completes immediately and control passes to the next statement as
shown in Example below.
DECLARE
credit_rating NUMBER := 0;
BEGIN
LOOP
credit_rating := credit_rating + 1;
IF credit_rating > 3 THEN
EXIT; -- exit loop immediately
END IF;
END LOOP;
-- control resumes here
DBMS_OUTPUT.PUT_LINE ('Credit rating: ' || TO_CHAR(credit_rating));
IF credit_rating > 3 THEN
DBMS_OUTPUT.PUT_LINE ('Credit rating is more than 3');
END IF;
DBMS_OUTPUT.PUT_LINE ('Adios ');
END;
/
194
PL/SQL Programming
Using the EXIT-WHEN Statement
The EXIT-WHEN statement lets a loop complete conditionally. When the EXIT
statement is encountered, the condition in the WHEN clause is evaluated. If the
condition is true, the loop completes and control passes to the next statement after the
loop.
LOOP
IF count > 100 THEN EXIT; ENDIF;
...
EXIT WHEN count > 100;
...
END LOOP;
These statements are logically equivalent, but the EXIT-WHEN statement is
(perhaps) easier to read and understand.
195
PL/SQL Programming
Using the RETURN Statement
•
The RETURN statement immediately completes the execution of a
subprogram (Function or Procedure) and returns control to the
caller.
•
Execution resumes with the statement following the subprogram
call.
•
In a function, the RETURN statement also sets the function identifier
to the return value.
196
PL/SQL Programming
Labeling a PL/SQL Loop
Like PL/SQL blocks, loops can be labeled. The optional label, an undeclared identifier enclosed
by double angle brackets, must appear at the beginning of the LOOP statement.
i 1 j 1 s 20
DECLARE
i 1 j 2 s 30
i 1 j 3 s 40
s INTEGER := 0;
i 1 j 4 s 50
i INTEGER := 0;
Outer --------------i 2 j 1 s 30
j INTEGER;
i 2 j 2 s 40
BEGIN
i 2 j 3 s 50
<<outer_loop>>
i 2 j 4 s 60
Outer --------------LOOP
i 3 j 1 s 40
i := i + 1;
i 3 j 2 s 50
i 3 j 3 s 60
j := 0;
i 3 j 4 s 70
<<inner_loop>>
Outer --------------LOOP
Adios
j := j + 1;
s := 10*(i + j); -- do some work here
DBMS_OUTPUT.PUT_LINE(' i ' || to_char(i) || ' j ' || to_char(j) ||
' s ' || to_char(s) );
EXIT inner_loop WHEN (j > 3);
END LOOP inner_loop;
DBMS_OUTPUT.PUT_LINE('Outer ---------------' );
EXIT outer_loop WHEN (i > 2);
END LOOP outer_loop;
DBMS_OUTPUT.PUT_LINE('Adios' );
END;
197
PL/SQL Programming
Using the WHILE-LOOP Statement
The WHILE-LOOP statement executes the statements in the loop body as long as a condition is true:
WHILE condition LOOP
sequence_of_statements
END LOOP;
Before each iteration of the loop, the condition is evaluated. If it is TRUE, the sequence of statements is
executed, then control resumes at the top of the loop. If it is FALSE or NULL, the loop is skipped and control
passes to the next statement.
Example
done := FALSE;
WHILE NOT done LOOP
sequence_of_statements
done := boolean_expression;
END LOOP;
198
PL/SQL Programming
Using the FOR-LOOP Statement
Simple FOR loops iterate over a specified range of integers. The number of iterations
is known before the loop is entered. A double dot (..) serves as the range operator. The
range is evaluated when the FOR loop is first entered and is never re-evaluated. If the
lower bound equals the higher bound, the loop body is executed once.
Example
--Using a Simple FOR..LOOP Statement
DECLARE
p NUMBER := 0;
BEGIN
FOR k IN 15..87 LOOP -- add numbers in the range
p := p + k;
END LOOP;
DBMS_OUTPUT.Put_Line ( to_char(p) );
END;
199
PL/SQL Programming
Using a Reverse FOR..LOOP Statement
DECLARE
n NUMBER(1) := 3;
BEGIN
FOR i IN REVERSE 1..n LOOP -- assign the values 3,2,1 to i
DBMS_OUTPUT.PUT_LINE (TO_CHAR(i));
END LOOP;
END;
/
Note. Inside a FOR loop, the counter can be read but cannot be changed.
Change STEP of a FOR..LOOP Statement
Some languages provide a STEP clause, which allows you to specify a different increment.
Unfortunately PL/SQL has no such structure.
200
PL/SQL Programming
Scope of the Loop Counter Variable
The loop counter is defined only within the loop. You cannot reference that variable
name outside the loop. After the loop exits, the loop counter is undefined:
Example
DECLARE
-- Scope of the LOOP Counter Variable
BEGIN
FOR i IN 1..3 LOOP -- assign the values 1,2,3 to i
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
DBMS_OUTPUT.PUT_LINE (i); -- raises an error
END;
/
Note
You do not need to declare the loop counter (i) because it is implicitly defined as a
local variable of type INTEGER.
201
PL/SQL Programming
Using the EXIT Statement in a FOR Loop
The EXIT statement lets a FOR loop complete early.
Example
--Using EXIT in a LOOP
DECLARE
x NUMBER;
BEGIN
FOR i IN 1..10 LOOP
DBMS_OUTPUT.Put_Line (i);
EXIT WHEN i > 7;
-- do some work here
DBMS_OUTPUT.Put_Line ('Busy Working …');
END LOOP;
END;
/
202
PL/SQL Programming
Using a Simple GOTO Statement
( what ? A GO TO ? You must be kidding!!! )
DECLARE
p VARCHAR2(30);
n INTEGER := 37; -- test any integer > 2 for prime
BEGIN
FOR j in 2..ROUND(SQRT(n)) LOOP
IF n MOD j = 0 THEN -- test for prime
p := ' is not a prime number'; -- not a prime number
GOTO print_now;
END IF;
END LOOP;
p := ' is a prime number';
<<print_now>>
DBMS_OUTPUT.PUT_LINE(TO_CHAR(n) || p);
END;
/
203
PL/SQL: Example-3
-- ToCELCIUS (Lowest temp, Highest Temp) Converts temperatures from Fahrenheit to Celcius.
-- Results are saved into TEMP, a predefined table to hold (text, text, text)
CREATE OR REPLACE
PROCEDURE ToCelcius (Low
IN
NUMBER,
High
IN
HUMBER)
IS
Celcius
Fahren
Msg
BEGIN
number(12);
number(12);
varchar2(40);
Intentional error
DELETE FROM
temp;
FOR Fahren IN Low..High LOOP
Celcius:= ROUND ( (Fahren -32)*5/9 );
IF (Fahren < 30 ) THEN
Msg := 'Too cold';
ELSIF (Fahren < 70 ) THEN
Msg := 'Cold';
ELSIF (Fahren <80) THEN
Msg := 'Very nice';
ELSE
Msg := 'Hot';
END IF;
INSERT INTO Temp VALUES (Fahren, Celcius, Msg);
Dbms_Output.Put_Line (to_char(Fahren) || ' ' ||
to_char(Celcius) || ' ' || Msg);
END LOOP;
END;
/
show errors
/
204
PL/SQL: Example-3
Testing the procedure
CSUPERSON SQL> exec toCelcius(60,77);
60 16 Cold
…
76 24 Very nice
77 25 Very nice
Values generated with
DBMS_OUTPUT.PUT_LINE…
CSUPERSON SQL> select * from temp;
F1
----60
61
…
77
F2
----16
16
F3
----------Cold
Cold
25
Very nice
205
PL/SQL: Example-4
-- ASSIGN or REMOVE employees from/to projects
-- shows: input/optional parameters
create or replace
PROCEDURE AdjustWorkLoad (
p_action
p_ssn
p_pno
p_hours
VARCHAR2,
VARCHAR2,
NUMBER,
NUMBER:= 40 )
IS
BEGIN
Optional argument &
Default value
IF (p_action = 'ASSIGN' ) THEN
INSERT INTO works_on VALUES (p_ssn, p_pno, p_hours);
ELSIF (p_action = 'REMOVE') THEN
DELETE FROM works_on
WHERE (essn = p_ssn) AND (pno = p_pno);
ELSE
dbms_output.put_line ('Invalid Action ' || p_action);
END IF;
EXCEPTION
when others then
dbms_output.put_line
END;
/
('Problems: ');
206
PL/SQL: Example-4
-- ASSIGN or REMOVE employees from/to projects
create or replace
PROCEDURE AdjustWorkLoad (
p_action
p_ssn
p_pno
p_hours
VARCHAR2,
VARCHAR2,
NUMBER := 7,
NUMBER:= 40 )
IS
BEGIN
-- ASSIGN / REMOVE employee to project for some hours
IF (p_action = 'ASSIGN' ) THEN
INSERT INTO works_on VALUES (p_ssn, p_pno, p_hours);
TWO
Optional arguments &
Default values
ELSIF (p_action = 'REMOVE') THEN
DELETE FROM works_on
WHERE (essn = p_ssn) AND (pno = p_pno);
ELSE
dbms_output.put_line ('Invalid Action ' || p_action);
END IF;
EXCEPTION
when others then
dbms_output.put_line
END;
/
('Problems: ');
207
PL/SQL: Example-4
Testing the procedure
CSUPERSON SQL> exec AdjustWorkLoad('ASSIGN',1,1,22);
CSUPERSON SQL> exec AdjustWorkLoad('ASSIGN',1,2);
CSUPERSON SQL> exec AdjustWorkLoad('ASSIGN',1);
CSUPERSON SQL> select * from works_on;
ESSN
PNO
HOURS
--------- ---------- ---------123456789
1
32.5
…
1
1
22
1
2
40
…
1
7
40
CSUPERSON SQL> exec AdjustWorkLoad('REMOVE',1,2);
208
PL/SQL Programming
Defining Variables
%TYPE
Declares a variable with
respect to a Table.Column
Bonus
EMP.Sal%TYPE;
EMP
EMPNO
----7369
7499
7521
ENAME
---------SMITH
ALLEN
WARD
JOB
MGR HIREDATE
SAL
COMM
DEPTNO
--------- --------- --------- --------- --------- --------CLERK
7902 17-DEC-80
800
20
SALESMAN
7698 20-FEB-81
1600
300
30
SALESMAN
7698 22-FEB-81
1250
500
30
Number(7,2)
209
PL/SQL Programming
Defining Variables
%RowType
Defines a record with respect
to an existing table definition
TempEmp
EMP%RowType
Refer to fields using: TempEmp.Salary
EMP
EMPNO
----7369
7499
7521
ENAME
---------SMITH
ALLEN
WARD
JOB
MGR HIREDATE
SAL
COMM
DEPTNO
--------- --------- --------- --------- --------- --------CLERK
7902 17-DEC-80
800
20
SALESMAN
7698 20-FEB-81
1600
300
30
SALESMAN
7698 22-FEB-81
1250
500
30
210
PL/SQL Example 5
Using %Type and %RowType (and Cursor construction)
create or replace
PROCEDURE Example5
IS
vEmpRecTemp
Employee%RowType;
vSSN
Employee.SSN%Type;
The scope of the variable extends to
the entire procedure
The scope of the (undeclared) variable
is limited to the for-loop
BEGIN
for vEmpRec in (select * from employee) loop
vSSN := vEmpRec.SSN;
dbms_output.put_line (to_Char(vSSN) || ' ' || vEmpRec.Fname );
end loop;
dbms_output.new_line;
dbms_output.put_line ('Adios');
END;
211
PL/SQL Example 5
Testing Example5
CSUPERSON SQL> exec example5
123456789 John
333445555
999887777
987654321
666884444
453453453
987987987
888665555
Adios
Franklin
Alicia
Jennifer
Ramesh
Joyce
Ahmad
James
212
Jdeveloper 10g (10.1.3) – SQL Developer
Using better tools for managing Oracle objects.
•
•
•
•
•
•
•
•
•
•
Donwload the Jdeveloper / SQLdeveloper tool from www.oracle.com
Create the subdirectory c:\Jdeveloper
Unzip the downloaded package into the subdirectory (there is no
setup.exe program)
Execute the program Jdeveloper.exe
From the main menu choose: View | Conection Navigator | Database
Run the Connection Wizard.
Enter OracleDBConnection at the “Connection Name” box
Enter CSUPERSON, EUCLID in the UserName & Password boxes
Enter XE (for Express Edition) in the SID box (replace ORCL)
Test the connection.
213
Jdeveloper – SQL Developer
214
Jdeveloper – SQL Developer
215
Jdeveloper – SQL Developer
NOTE
In order for user SCOTT to create/compile/debug stored Oracle code
when using the Jdeveloper tool you need to do this
•
Log into the system as a DBA
(either
connect system/manager
or
)
(
connect system/manager as sysdba )
•
Enter the commands
Grant DEBUG CONNECT SESSION to scott;
Grant DEBUG ANY PROCEDURE to scott;
216
Jdeveloper
Resources that can help you get started with Oracle JDeveloper.
Online Demos:
http://www.oracle.com/technology/products/jdev/viewlets/viewlet.html
Step by Step Getting Started Tutorials
http://www.oracle.com/technology/obe/obe1013jdev/index.htm
JDeveloper discussion forum:
http://www.oracle.com/technology/discussionforums/jdev.html
For more information on Oracle JDeveloper visit OTN:
http://www.oracle.com/technology/products/jdev/
JDeveloper RSS news feed:
http://www.oracle.com/technology/products/jdev/temp/whatisrss.html
217
PL/SQL Programming
SUPPLIED
PACKAGES
218
PL/SQL Programming
Supplied packages
•
DBMS_OUTPUT routes output from routines
– Put_Line(…)
– Put (…)
– New_Line
•
DBMS_RANDOM generates random numbers/string
– String(…)
– Seed(…)
– Value( )
•
writes line + CrLf
writes token
writes CrLf
returns STRING
starting point
returns NUMBER [0, 1)
UTL_FILE programs can read and write operating system text files
– Fclose
– Put_Line
– Get_Line
Fopen
Put
…
Fflush
Is_Open
New_line
219
PL/SQL Example 6
Using the DBMS_OUTPUT package
create or replace
PROCEDURE Example6
IS
BEGIN
for i in 0 .. 6 loop
if MOD(i,2) = 0 then
dbms_output.put ('Blip ');
else
dbms_output.put ('Blop ');
end if;
end loop;
dbms_output.New_Line;
dbms_output.put_line ('Adios');
dbms_output.put_line ('amigos');
END;
220
PL/SQL Example 6
Testing Example 6
CSUPERSON SQL> exec example6
Blip Blop Blip Blop Blip Blop Blip
Adios
amigos
PL/SQL procedure successfully completed.
221
PL/SQL Example-7
Using the DBMS_RANDOM package
--Create 10 random numbers and strings
PROCEDURE Example7
IS
myRandomNumber1 NUMBER(10);
myRandomNumber2 NUMBER(10);
myRandomString VARCHAR2(20);
BEGIN
for i in 0..9 loop
DBMS_OUTPUT.New_Line;
--make a random num. between 50 and 100
myRandomNumber1 := DBMS_RANDOM.Value(50, 101);
--make a random num. between 0 and 100
myRandomNumber2 := 101 * DBMS_RANDOM.Value();
--X (alphanumeric) A (alpha) P (printable)
myRandomString := DBMS_RANDOM.String('X', 10);
DBMS_OUTPUT.Put ( to_char(i) || ' ');
DBMS_OUTPUT.Put ( myRandomString || ' ' );
DBMS_OUTPUT.Put ( to_char(myRandomNumber1) || ' ' );
DBMS_OUTPUT.Put ( to_char(myRandomNumber2) || ' ' );
DBMS_OUTPUT.New_Line;
end loop;
END;
222
PL/SQL Example-7
Testing DBMS_RANDOM
CSUPERSON SQL> Exec Example7
0
1
2
3
4
5
6
7
8
9
HCOGHALDI0
8M6S2DKG6D
J6XGTPR3T5
NFRO7KFZZU
YLX9C620JM
0CGB6QBW2X
Y0G57QNIRV
VT4CSCKNS8
BRV1S4PWLE
WQJAHNHV5L
54
65
54
71
83
96
73
87
99
72
84
8
21
25
45
33
26
17
39
56
PL/SQL procedure successfully completed
223
PL/SQL Example-8
Using the UTL_FILE package
Create a bridge between Oracle and the local OS using IO routines to operate on local
OS (disk) text files.
Preparation
•
•
Log as DBA using SYS (connect system/manager as SYSDBA)
Install the UTL_FILE package by executing (@) the script
C:\oracle\product\10.1.0\db_1\RDBMS\ADMIN\utlFile.sql
or
Oracle 10g Express Edition (v10.2)
appears not to support this feature.
C:\oraclexe\app\oracle\product\10.2.0\server\RDBMS\ADMIN\utlFile.sql
•
Issue appropriate GRANT commands, finally create a (logical) working directory alias
CREATE OR REPLACE PUBLIC SYNONYM utl_file FOR sys.utl_file;
GRANT EXECUTE ON UTL_FILE TO PUBLIC;
CREATE DIRECTORY WIN_DIR AS 'C:/Temp';
GRANT READ
ON DIRECTORY WIN_DIR TO PUBLIC;
GRANT WRITE
ON DIRECTORY WIN_DIR TO PUBLIC;
224
PL/SQL Example-8
Log as CSUPerson/Euclid. Enter the following anonymous procedure
DECLARE
myFile
UTL_FILE.File_Type;
myBuffer varchar2(80);
BEGIN
myFile := UTL_FILE.Fopen('WIN_DIR','XYZ.TXT','W');
UTL_FILE.Put_Line(myFile, 'Uno');
UTL_FILE.Put_Line(myFile, 'Dos');
UTL_FILE.Put_Line(myFile, 'Tres');
UTL_FILE.Fclose(myFile);
BEGIN
myFile := UTL_FILE.Fopen('WIN_DIR','XYZ.TXT','R');
Loop
UTL_FILE.Get_Line (myFile, myBuffer);
DBMS_OUTPUT.Put_Line(myBuffer);
End Loop;
EXCEPTION
when NO_DATA_FOUND then
UTL_FILE.Fclose(myFile);
DBMS_OUTPUT.Put_Line ('Adios ...');
END;
DBMS_OUTPUT.Put_Line ('Amigos');
END;
225
PL/SQL Example-8
Testing anonymous procedure. Write then read some lines
CSUPERSON SQL> @Code/Example8
Uno
Dos
Tres
Adios ...
Amigos
PL/SQL procedure successfully completed.
Note: File c:/Temp/XYZ.TXT contains
Uno
Dos
Tres
226
PL/SQL Programming
COLLECTIONS
and
RECORDS
227
PL/SQL Programming
What are PL/SQL Collections and Records?
• A collection is an ordered group of elements, all of the same type. It
is a general concept that includes lists, arrays, tables and other
datatypes used in classic programming algorithms. Each element is
addressed by a unique subscript.
• A record is a group of related data items stored in fields, each with
its own name and datatype. You can think of a record as a variable that
can hold a table row, or some columns from a table row. The fields
(usually) correspond to table columns.
228
PL/SQL Example-9
Defining and Using a User-Defined Record Type
DECLARE
EmpName
TYPE BadgeT IS RECORD(
EmpName varchar2(40),
DeptName varchar2(40)
);
HelloTag
BEGIN
select
into
from
where
and
BadgeT;
(Fname || ' ' || Lname), (Dname)
HelloTag.EmpName, HelloTag.DeptName
Employee, Department
SSN= 123456789
Dno = Dnumber;
DBMS_OUTPUT.Put_Line ('--- HELLO ---');
DBMS_OUTPUT.Put_Line (HelloTag.EmpName);
DBMS_OUTPUT.Put_Line (HelloTag.DeptName);
EXCEPTION
when others then
DBMS_OUTPUT.Put_Line ('Problems');
END;
DeptName
RECORD TYPE
Print a HELLO tag for employee
123456789 showing name and dept.
--- HELLO --John Smith
Research
229
PL/SQL Programming
Understanding PL/SQL Collections
1. Associative arrays
2. Nested tables
3. Varrays
230
PL/SQL Programming
Understanding PL/SQL Collections
•
Associative arrays (using integer & string indices)
TYPE aa1T IS TABLE
INDEX
TYPE aa2T IS TABLE
INDEX
•
Varchar2(10)
BINARY_INTEGER;
EmployeeRec
Varchar2(20);
Nested tables
TYPE ntT IS
•
OF
BY
OF
BY
TABLE OF Varchar2(10);
Varrays
TYPE vaT IS
VARRAY(20) OF VARCHAR2(30);
231
PL/SQL Programming
Understanding PL/SQL Memory Collections
Associative arrays, also known as index-by tables, let you look up elements
using arbitrary numbers and strings for subscript values.
These are similar to hash tables in other programming languages.
Favorite City
Key 
Ohio
Spain
Value 
Cleveland
Madrid
India
...
Bangalore
France
...
Paris
232
PL/SQL Programming
Understanding PL/SQL Collections
•
•
•
Nested tables hold an arbitrary number of row elements.
They use sequential numbers as subscripts.
You can define equivalent SQL types, allowing nested tables to be stored in
database tables and manipulated through SQL.
Key 
1
Ohio
Cleveland
2
Spain
Madrid
3
India
Bangalore
Venezuela
Pampatar
…
Unlimited number of rows 
n
233
PL/SQL Programming
Understanding PL/SQL Collections
•
•
•
•
VARRAYS (short for variable-size arrays) hold a fixed number of elements
(although you can change the number of elements at runtime).
They use sequential numbers as subscripts.
You can define equivalent SQL types, allowing varrays to be stored in
database tables.
They can be stored and retrieved through SQL, but with less flexibility than
nested tables.
Favorite City
Key 
1
2
3
4
5
6
Value 
Cleveland
Madrid
San Francisco
Bangalore
Montreal
Paris
Limited (but dynamic) number of cells 
234
PL/SQL Programming
Understanding Associative Arrays (Index-By Tables)
•
Associative arrays are sets of key-value pairs, where each key is unique and is
used to locate a corresponding value in the array.
•
The key can be an integer or a string.
•
Assigning a value using a key for the first time adds that key to the associative
array. Subsequent assignments using the same key update the same entry.
•
Can not be inserted in a (SQL) table (as Varrays do)
•
Sparse (could have null segments: data + nulls)
•
Has methods/attributes:
– Delete(…), First(...), Next(…), Prior(...), Last(…), Exists(…), Count…
235
PL/SQL – Example 10
•
An associative array using integer
indices (stores employee records).
•
There are gaps in the collection
(entry 3 does not exist)
236
PL/SQL – Example 10B
•
An associative
array using
STRING
indices
237
PL/SQL – Example11
PROCEDURE Example11
IS
TYPE BadgeT IS RECORD(
EmpName varchar2(40),
DeptName varchar2(40)
);
TYPE SimpleTableT IS TABLE OF Varchar2(10)
INDEX BY BINARY_INTEGER;
TYPE WorkerT
IS TABLE OF Employee%ROWTYPE
INDEX BY BINARY_INTEGER;
TYPE BadgeTColl
IS TABLE OF BadgeT
INDEX BY BINARY_INTEGER;
BadgeTable
SimpleTable
Worker
BadgeTColl;
SimpleTableT;
WorkerT;
Associative Array used to
Store a user-defined
record type
TYPE definitions
INSTANCE definition
Table uses NUMERIC indices
BEGIN
-- Associative array
BadgeTable(0).EmpName := '1- John Smith';
BadgeTable(0).DeptName := 'Intl. Sales';
BadgeTable(1).EmpName := '2- Maria Macarena';
BadgeTable(1).DeptName := 'Intl. Salsa';
BadgeTable(2).EmpName := '3- Sam Dynamite';
BadgeTable(2).DeptName := 'Intl. Bang';
1- John Smith
2- Maria Macarena
3- Sam Dynamite
for i in 0..2 loop
dbms_output.put_line (BadgeTable(i).EmpName);
end loop;
END;
238
PL/SQL – Example11
Associative Arrays
KEY
VALUES
EmpName
DeptName
0
1- John Smith
Int. Sales
1
2- Maria Macarena
Int. Salsa
2
3- Sam Dynamite
Int. Bang
239
PL/SQL Example-12
Associative Arrays
PROCEDURE Example12
IS
TYPE SimpleTableT IS TABLE OF Varchar2(10) INDEX BY BINARY_INTEGER;
TYPE WorkerT
IS TABLE OF Employee%ROWTYPE INDEX BY BINARY_INTEGER;
SimpleTable
SimpleTableT;
Worker
WorkerT;
Data-5
BEGIN
Data-4
for i in 1..5 loop
Data-3
SimpleTable(i) := 'Data-' || i;
Data-2
end loop;
Data-1
for i in reverse 1..5 loop
3 Harry
DBMS_OUTPUT.Put_Line (SimpleTable(i));
5 Hermione
end loop;
worker(3).Fname := 'Harry';
worker(3).Lname := 'Potter';
worker(5).Fname := 'Hermione'; worker(5).Lname := 'Wranger';
for i in 1..6 loop
begin
DBMS_OUTPUT.Put_Line (to_char(i) || ' ' || worker(i).Fname);
exception
when others then null;
BEGIN…EXCEPTION…END
end;
block deals with the problem of
end loop;
sparse data (null data gaps)
END;
240
PL/SQL Example-12
Associative Arrays
KEY
VALUES
1
Data-1
2
Data-2
3
Data-3
4
Data-4
5
Data-5
KEY
SimpleTable
Worker
VALUES
Fname
3
Harry
5
Hermione
Lname …
Dno
241
Associative Arrays
PL/SQL Example-12
WATCH WINDOW displayed by
the Jdeveloper tool when tracing
the Procedure.
Observe the (Key, Value)
structure.
SimpleTable
Worker
242
PL/SQL Programming
Collection Methods
A collection method is a built-in function or procedure that operates on
collections and is called using dot notation.
You can use the methods
EXISTS,
COUNT,
LIMIT,
EXTEND, TRIM,
DELETE,
FIRST,
PRIOR,
LAST,
NEXT
to manage collections whose size is unknown or varies.
243
PL/SQL Programming
Collection Methods
COUNT
Returns the number of elements that a collection currently contains.
• For varrays, COUNT always equals LAST.
• For nested tables, normally, COUNT equals LAST. But, if you delete elements from
the middle of a nested table, COUNT is smaller than LAST.
DELETE
Eliminate (without shifting) entries from the collection (must be an associative array or
nested table). This procedure has three forms.
• DELETE
• DELETE(n)
removes all elements from a collection.
removes the n-th element from an associative array or nested table.
If n is null, DELETE(n) does nothing.
• DELETE(m,n) removes all elements in the range m..n from an associative array or
nested table. If m is larger than n or if m or n is null,
DELETE(m,n) does nothing.
244
PL/SQL Programming
Collection Methods
EXTEND
Enlarges the size of a collection. This procedure has three forms.
EXTEND
appends one null element to a collection.
EXTEND(n) appends n null elements to a collection.
EXTEND(n,i) appends n copies of the i-th element to a collection.
You cannot use EXTEND with associative arrays.
TRIM
TRIM
removes one element from the end of a collection.
TRIM(n) removes n elements from the end of a collection.
If n is greater than COUNT, TRIM(n) raises SUBSCRIPT_BEYOND_COUNT.
You cannot use TRIM with index-by tables.
If TRIM encounters deleted elements, it includes them in its tally.
245
PL/SQL Programming
Collection Methods
FIRST, LAST
FIRST and LAST return the first and last (smallest and largest) subscript values in a
collection.
The subscript values are usually integers, but can also be strings for associative arrays.
• If the collection is empty, FIRST and LAST return NULL.
• If the collection contains only one element, FIRST and LAST return the same
subscript value.
• For varrays, FIRST always returns 1 and LAST always equals COUNT.
• For nested tables, normally, LAST equals COUNT. But, if you delete elements from
the middle of a nested table, LAST is larger than COUNT.
246
PL/SQL Programming
Collection Methods
LIMIT
For nested tables, which have no maximum size, LIMIT returns NULL.
For varrays, LIMIT returns the maximum number of elements that a varray can contain
(which you must specify in its type definition).
NEXT, PRIOR
PRIOR(n) returns the subscript that precedes index n in a collection.
NEXT(n) returns the subscript that succeeds index n.
If n has no predecessor, PRIOR(n) returns NULL. Likewise, if n has no successor,
NEXT(n) returns NULL.
247
PL/SQL Programming
Collection Methods
EXISTS
EXISTS(n) returns TRUE if the n-th element in a collection exists. Otherwise returns
FALSE.
Mainly, you use EXISTS with DELETE to maintain sparse nested tables.
You can also use EXISTS to avoid raising an exception when you reference a
nonexistent element.
When passed an out-of-range subscript, EXISTS returns FALSE instead of raising
SUBSCRIPT_OUTSIDE_LIMIT.
248
PL/SQL Programming
Collection Methods
collection_name.{
COUNT |
DELETE [ (index [, index]) ] |
EXISTS (index) |
EXTEND [ (number [, index] ] |
FIRST |
LAST |
LIMIT |
NEXT (index) |
PRIOR (index) |
TRIM [ (number) ] }
249
PL/SQL Example-13
Associative Arrays
Navigation Methods: First(), Next(), Last()
create or replace
PROCEDURE Example13
IS
TYPE SimpleTableT IS TABLE OF Varchar2(10)
INDEX BY BINARY_INTEGER;
SimpleTable
SimpleTableT;
i
NUMBER;
BEGIN
SimpleTable(0) := 'DHL';
SimpleTable(1) := 'Fedex';
SimpleTable(2) := 'UPS';
SimpleTable(3) := 'USPS';
for i in 0..3 loop
dbms_output.put_line (simpleTable(i));
end loop;
DHL
Fedex
UPS
USPS
0
1
2
3
DHL
Fedex
UPS
USPS
i := SimpleTable.First;
Loop
exit when i is null;
dbms_output.put_line (to_char(i) || ' ' || simpleTable(i));
i := SimpleTable.Next(i);
End Loop;
END;
250
PL/SQL Example-14
Deleting rows from a table.
create or replace
PROCEDURE Example14
IS
TYPE SimpleTableT IS TABLE OF Varchar2(10)
INDEX BY BINARY_INTEGER;
SimpleTable
SimpleTableT;
i
NUMBER;
BEGIN
SimpleTable(0) := 'DHL';
SimpleTable(1) := 'Fedex';
SimpleTable(2) := 'UPS';
SimpleTable(3) := 'USPS';
0
1
2
3
Associative Arrays
DHL
Fedex
UPS
USPS
SimpleTable.Delete(2); --removing UPS from the table
0 DHL
1 Fedex
3 USPS
i := SimpleTable.First;
Loop
exit when i is null;
dbms_output.put_line (to_char(i) || ' ' || simpleTable(i));
i := SimpleTable.Next(i);
End Loop;
END;
251
PL/SQL Example-15A
Associative Arrays
PROCEDURE Example15A AS
TYPE
BaseBallType
Home
City
Team
BaseBallType;
VARCHAR2(64);
VARCHAR2(64);
IS TABLE OF VARCHAR2(64)
INDEX BY VARCHAR2(64);
BEGIN
-- Creates new entries
Home ('Indians') := 'Cleveland' ;
Home ('Yankees') := 'New York' ;
Home ('Dodgers') := 'Los Angeles' ;
Indians
Cleveland
Yankees
New York
Dodgers
Los Angeles
-- Looks up value associated with a baseball team (string type)
city := Home('Yankees');
dbms_output.put_line('The [Yankees] home is: '
|| City);
The [Yankees] home is: New York
252
PL/SQL Example-15A
Associative Arrays
cont.
-- Look into the collection
-- use: FIRST, NEXT, COUNT, PRIOR, LAST,...
Team := Home.FIRST;
Dodgers --> Los Angeles
loop
Indians --> Cleveland
exit when Team is NULL;
Yankees --> New York
city := Home(Team);
dbms_output.put_line( Team || ' --> ' || City);
Team := Home.NEXT(Team);
end loop;
-- Looks up value associated with a football team (string type)
BEGIN
Team := 'Browns';
city := Home(team);
dbms_output.put_line(Team || ' --> ' || City);
EXCEPTION
when others then
dbms_output.put_line('What? Check your baseball');
END;
What? Check your baseball
END;
253
PL/SQL Example-15B
DECLARE
TYPE population_type
country_population
continent_population
howmany
which
IS TABLE OF NUMBER INDEX BY VARCHAR2(64);
population_type;
population_type;
NUMBER;
VARCHAR2(64);
Associative Arrays
KEY is a string.
The structure is a HASH table
BEGIN
country_population('Greenland') := 100000; -- Creates new entry
country_population('Iceland') := 750000;
-- Creates new entry
-- Looks up value associated with a string
howmany := country_population('Greenland');
dbms_output.put_line('Greenland pop. is ' || howmany );
continent_population('Australia') := 30000000;
continent_population('Antarctica') := 1000; -- Creates new entry
continent_population('Antarctica') := 1001; -- Replaces previous value
-- Returns 'Antarctica' as that comes first alphabetically.
which := continent_population.FIRST;
dbms_output.put_line ('First KEY is: ' || which);
-- Returns 'Australia' as that comes last alphabetically.
which := continent_population.LAST;
dbms_output.put_line ('First LAST is: ' || which);
Greenland pop. is 100000
First KEY is: Antarctica
First LAST is: Australia
Population of Australia is 30000000
-- Returns the value corresponding to the last key, in this
-- case the population of Australia.
howmany := continent_population(which);
dbms_output.put_line('Population of ' || which || ' is ' || howmany);
END;
/
254
PL/SQL: VARRAY
• VARRAYs are one-dimensional arrays that can be stored in columns
of a database table.
• They are dense data objects (behave like arrays, a delete operation
doesn’t shift rows)
• A varray has a maximum size, which you specify in its type definition.
Its index has a fixed lower bound of 1 and an extensible upper bound.
TYPE dnames_var IS VARRAY(20) OF VARCHAR2(30);
• A varray can contain a varying number of elements, from zero (when
empty) to the maximum specified in its type definition.
255
PL/SQL: VARRAY
Invoking the VARRAY Primitive Constructor - Extending
DECLARE
-- In the varray, we put an upper limit (20) on the number of elements
TYPE dnamesType IS VARRAY(20) OF VARCHAR2(30);
dept_names dnamesType;
BEGIN
-- Because dnames is declared as VARRAY(20), we can put up to 20
-- elements in the constructor
dept_names := dnamesType('Shipping','Sales','Finance','Payroll');
-- after calling constructor COUNT is set to four elements
dbms_output.put_line('LAST ' || dept_names.LAST);
dbms_output.put_line('COUNT ' || dept_names.COUNT);
--adding a new element
dept_names.EXTEND(1);
dept_names(dept_names.LAST) := 'Research';
dbms_output.put_line('LAST ' || dept_names.LAST);
for i in 1..dept_names.LAST loop
dbms_output.put_line(i || ' --> ' || dept_names(i));
end loop;
END;
/
LAST 4
COUNT 4
1 --> Shipping
2 --> Sales
3 --> Finance
4 --> Payroll
5 --> Research
256
PL/SQL: VARRAY
Expanding and Shrinking VARRAYs
PROCEDURE Example16A
IS
TYPE VA is varray(3) of varchar2(10);
A va;
theCount number;
Count: 0
Count: 2
aaa
bbb
ccc
BEGIN
-- instantiate varray (no data)
a := VA();
theCount := a.COUNT; dbms_output.put_line('Count: ' || theCount);
-- place a pair of values using varray constructor
a := VA('aaa','bbb');
theCount := a.COUNT; dbms_output.put_line('Count: ' || theCount);
--add one more element using .EXTEND(…) [already at the limit]
a.extend(1);
a(3) := 'ccc';
for i in 1..a.LAST loop
dbms_output.put_line (a(i));
end loop;
END;
257
PL/SQL: VARRAY
Expanding and Shrinking VARRAYs
cont.
theCount := a.COUNT; dbms_output.put_line('Count: ' || theCount);
dbms_output.put_line(' Limit: ' || a.LIMIT);
--try to grow beyond the limit (it is not going to work!)
BEGIN
a.extend(1);
a(4) := 'ddd';
EXCEPTI
when others then dbms_output.put_line('Could NOT grow');
END;
--eliminate right-most element
a.trim;
theCount := a.COUNT; dbms_output.put_line('Count: ' || theCount);
dbms_output.put_line(' Limit: ' || a.LIMIT);
Count: 3
Limit: 3
for i in 1..a.LAST loop
Could NOT growth
dbms_output.put_line (a(i));
Count: 2
end loop;
Limit: 3
END;
aaa
.DELETE(…) can not be used with varrays
bbb
258
PL/SQL: VARRAY
Expanding and Shrinking NESTED TABLES
Repeat previous example with the following modification for array a:
TYPE NTType is TABLE of varchar2(10);
a NTType;
Try also .DELETE(…) operation on the LAST (OK!) and FIRST (will fail)
259
PL/SQL: VARRAY
Creating a Table with a Varray Column (sets of atomic values)
-- Each project has a 16-character code name.
-- We will store up to 50 projects at a time
-- in a single database column.
CREATE TYPE ProjectList AS VARRAY(50)
OF VARCHAR2(16);
-- create database table: dept_projects
-- Each department can have up to 50 projects.
CREATE TABLE dept_projects (
dept_id NUMBER(2),
name
VARCHAR2(15),
budget
NUMBER(11,2),
projects ProjectList);
NOTE. To force the destruction of the table and type use the commands
drop table dept_projects cascade constraints purge
drop TYPE ProjectList
260
PL/SQL: VARRAY
Creating a Table with a Varray Column
continuation
CREATE TYPE ProjectList AS VARRAY(50) OF VARCHAR2(16);
1
2
3
…
50
261
PL/SQL: VARRAY
Creating a Table with a Varray Column
continuation
CREATE TABLE dept_projects (
dept_id NUMBER(2),
name
VARCHAR2(15),
budget
NUMBER(11,2),
projects ProjectList);
Projects
Position
Dept_id
Name
Budget
1
2
3
4
…
50
1
2
3
…
262
PL/SQL: VARRAY
Varray Constructor Within a SQL Statement
cont.
BEGIN
INSERT INTO dept_projects
VALUES (60, 'Security', 750400,
ProjectList('New Badges',
'Track Computers',
'Check Exits'));
END;
/
Dept_id
Name
Budget
Projects
60
Security
750400
PROJECTLIST('New Badges', 'Track Computers', 'Check Exits’)
NOTE. To force column formatting you may have to issue the SQL-Plus commands
column name format a20
column dept_id format 9999
column budget format 999,999,999.99
column projects format a80
Select * from dept_projects;
263
PL/SQL: VARRAY
Creating a Table with a Varray Column
cont.
DECLARE
some_proj ProjectList;
BEGIN
SELECT projects INTO some_proj
FROM dept_projects
WHERE dept_id = 60;
Projects = New Badges
Projects = Track Computers
Projects = Check Exits
FOR i IN some_proj.FIRST .. some_proj.LAST
LOOP
DBMS_OUTPUT.PUT_LINE('Projects = ' || some_proj(i));
END LOOP;
END;
/
264
PL/SQL Varray
Non-First Normal Form Table holding a varray of a non-atomic data type
create or replace
TYPE PersonT AS OBJECT (
A single person OBJECT definition
EmpSSN
varchar2(10),
EmpName varchar2(40)
);
Defining a LIST of Person OBJECTS
/
(Collection Object)
create or replace
TYPE PersonListT AS VARRAY(50) of PersonT;
/
drop table CoWorker;
/
create table CoWorker (
A SQL table using a Collection of
ProjectNumber
number,
OBJECTS
ProjectName
varchar2(20),
(List of People)
People
PersonListT
)
/
insert into CoWorker values (10, 'Project X',
PersonListT( PersonT(123, 'Harry Potter'
),
PersonT(456, 'Hermione Wranger'),
PersonT(777, 'Prof. Dumbledore') )
)
/
insert into CoWorker values (20, 'Project Y',
PersonListT( PersonT(789, 'Roy Malfoy'
),
PersonT(999, 'Lord Voldemor' ) )
)
/
select * from CoWorker;/
265
PL/SQL Varray (cont.)
Non-First Normal Form Table holding a varray of a non-atomic data type
CSUPERSON SQL> select * from coworker;
PROJECTNUMBER PROJECTNAME PEOPLE(EMPSSN, EMPNAME)
------------- ----------- ----------------------10
Project X
PERSONLISTT(
PERSONT('123', 'Harry Potter'),
PERSONT('456', 'Hermione Wranger'),
PERSONT('777', 'Prof. Dumbledore'))
20
Project Y
PERSONLISTT(
PERSONT('789', 'Roy Malfoy'),
PERSONT('999', 'Lord Voldemor'))
Complex object: A LIST
(collection) of PersonT objects.
NOTE. To force column formatting you may have to issue the SQL-Plus commands
column ProjectName format a20
column ProjectNumber format 9999
column People format a40 WRAP
266
PL/SQL Varray (cont.)
Non-First Normal Form Table holding a varray of a non-atomic data type
CSUPERSON SQL> select * from coworker;
ProjectNumber
ProjectName
People
EmpSSN
10
Project X
123
456
777
20
Project Y
789
999
EmpName
Harry Potter
Hermione Wranger
Prof. Dumbledore
Roy Malfoy
Lord Voldemor
267
PL/SQL: Nested Tables
•
PL/SQL nested tables represent sets of values.
•
You can think of them as one-dimensional arrays with no declared
number of elements.
•
You can model multi-dimensional arrays by creating nested tables
whose elements are also nested tables.
•
Within the database, nested tables are column types that hold sets of
values. Oracle stores the rows of a nested table in no particular
order.
•
When you retrieve a nested table from the database into a PL/SQL
variable, the rows are given consecutive subscripts starting at 1.
That gives you array-like access to individual rows.
268
PL/SQL: Nested Tables
DECLARE
TYPE nested_type IS TABLE OF VARCHAR2(30);
i
number := 0;
n
nested_type;
aValue varchar2(20);
No INDEX BY clause
No size / storage is predefined
BEGIN
-- an arbitrary number of strings can be inserted in n
n := nested_type('Shipping','Sales','Finance','Payroll');
n.extend(1);
n(n.LAST) := 'Research';
i := n.FIRST; -- same as i:=1;
Loop
exit when i is null;
dbms_output.put_line (i || ' ' || n(i));
i := n.Next(i);
End Loop;
1 Shipping
2 Sales
3 Finance
4 Payroll
5 Research
END;
/
269
PL/SQL: Nested Tables
Nested tables differ from arrays in two important ways:
•
Nested tables do not have a declared number of elements, while
arrays have a predefined number. The size of a nested table can
increase dynamically; however, a maximum limit is imposed.
•
Nested tables might not have consecutive subscripts, while arrays
are always dense (have consecutive subscripts). Initially, nested
tables are dense, but they can become sparse (have nonconsecutive
subscripts). You can delete elements from a nested table using the
built-in procedure DELETE. The built-in function NEXT lets you
iterate over all the subscripts of a nested table, even if the sequence
has gaps.
270
PL/SQL: Nested Tables
PROCEDURE
Example16B AS
TYPE nested_type IS TABLE OF VARCHAR2(30);
i
number := 0;
n
nested_type;
BEGIN
-- call constructor, extend, and insert consecutive data cells
n := nested_type();
n.extend(4);
n(1):= '111';
n(2):= '222';
n(3):= '333';
n(4):= '444';
--show consecutive cells
for i in 1..n.LAST Loop
dbms_output.put_line (i || ' ' || n(i));
End Loop;
--add one more cell at the end, delete the one whose key is 2
n.extend(1);
n(n.LAST) := '555';
n.delete(2);
--traverse the collection (there is a hole on position 2)
i := n.FIRST; -- same as i:=1;
Loop
exit when i is null;
dbms_output.put_line (i || ' ' || n(i));
i := n.Next(i);
End Loop;
1
2
3
4
111
222
333
444
1
3
4
5
111
333
444
555
END;
271
PL/SQL: Nested Tables
Consider making a nested NF2 database table holding
• Dept. Name & Number.
• All Projects controlled by the department (size unknown).
• All Employees working in those project (size unknown).
DeptNum DeptName
Projects
Employees
{Pro-X, Pro-Y}
{Maria, Joe, Pete}
10
Research
20
Marketing {Pro-Z}
{Pete, Paul}
Ozsoyoglu G., Matos V. “Extending Relational Algebra and Relational Calculus with Set-Valued Attributes and Aggregate Functions”.
ACM Transactions on Database Systems. Vol. 12 (4): 566-592 (1987).
http://www.informatik.uni-trier.de/~ley/db/indices/a-tree/m/Matos:Victor.html
http://doi.acm.org/10.1145/32204.32219
272
PL/SQL: Nested Tables
DROP
DROP
DROP
DROP
DROP
DROP
DROP
TABLE ntE FORCE;
TABLE ntP FORCE;
TABLE DeptInfo FORCE;
TYPE ntProjectT FORCE;
TYPE ProjectT FORCE;
TYPE ntEmployeeT FORCE;
TYPE EmployeeT FORCE;
/* -------------------------------------------------------------------- */
/* Define Object Type for storing project & employee information
*/
/* -------------------------------------------------------------------- */
CREATE or REPLACE TYPE ProjectT AS OBJECT
( PNumb VARCHAR2(10),
PName VARCHAR2(20));
/
CREATE or REPLACE TYPE EmployeeT AS OBJECT
( EmpSSN
VARCHAR2(10),
EmpName
VARCHAR2(40));
/
SHOW ERRORS
273
PL/SQL: Nested Tables
/* -------------------------------------------------------------------- */
/* Define Nested Table Type of ProjectT & Employee object type
*/
/* -------------------------------------------------------------------- */
CREATE TYPE ntProjectT AS TABLE OF ProjectT;
/
CREATE TYPE ntEmployeeT AS TABLE OF EmployeeT;
/
/* -------------------------------------------------------------------- */
/* Table for storing Department related information
*/
/* -------------------------------------------------------------------- */
CREATE TABLE DeptInfo(
DNumber
VARCHAR2(10),
Dname
VARCHAR2(50),
Projects
ntProjectT,
Employees
ntEmployeeT)
NESTED TABLE Projects STORE AS ntP,
NESTED TABLE Employees STORE AS ntE;
274
PL/SQL: Nested Tables
INSERT INTO DeptInfo VALUES ( 10, 'Research',
ntProjectT(
ProjectT(1, 'Project X'),
ProjectT(2, 'Project Y')
),
ntEmployeeT(
EmployeeT(111, 'Joe'),
EmployeeT(222, 'Maria'),
EmployeeT(333, 'Pete')
)
);
INSERT INTO DeptInfo VALUES ( 20, 'Marketing',
ntProjectT(
ProjectT(1, 'Project Z')
),
ntEmployeeT(
EmployeeT(333, 'Pete'),
EmployeeT(444, 'Paul')
)
);
275
PL/SQL: Nested Tables
SQL > select * from DeptInfo;
DNUMBER
DNAME
PROJECTS(PNUMB, PNAME)
EMPLOYEES(EMPSSN, EMPNAME)
10
Research
NTPROJECTT(
PROJECTT('1', 'Project X'),
PROJECTT('2', 'Project Y'))
NTEMPLOYEET(
EMPLOYEET('111', 'Joe'),
EMPLOYEET('222', 'Maria'),
EMPLOYEET('333', 'Pete'))
20
Marketing
NTPROJECTT(
PROJECTT('1', 'Project Z'))
NTEMPLOYEET(
EMPLOYEET('333', 'Pete'),
EMPLOYEET('444', 'Paul'))
NOTE. To force column formatting you may have to issue the SQL-Plus commands
column dname format a15
column Projects format a40 wrap
column Employees format a40 wrap
276
PL/SQL Programming
Objects
277
Oracle Objects
Oracle OBJECTS
Advantages of Objects
•
In general, the Oracle object-type model is similar to the class
mechanism found in C++ and Java.
•
Objects consists of attributes and methods
•
Oracle objects features: encapsulation, single inheritance,
polymorphism, and type evolution..
•
No mapping layer is required between client-side objects and the
relational database columns and tables that contain the object data.
278
Oracle Objects
Oracle OBJECTS
279
Oracle Objects
Creating/Using a Simple Oracle OBJECT
drop type t_person_name;
/
CREATE TYPE t_Person_Name AS OBJECT
(
first_name
VARCHAR2(20),
last_name
VARCHAR2(20),
middle_initial
CHAR,
INTERFACE
Public Attributes
Public Methods
MEMBER FUNCTION Get_Name RETURN VARCHAR2,
MEMBER PROCEDURE Capitalize
);
/
T_PERSON_NAME
+ first_name
+ last_name
+ middle_initial
+ Get_Name ( )
+ Capitalize ( )
drop table emp_boss purge;
drop type emp_boss_type;
drop type t_person_name;
280
Oracle Objects
Creating/Using an Oracle OBJECT
CREATE TYPE BODY t_Person_Name AS
IMPLEMENTATION
MEMBER FUNCTION Get_Name RETURN VARCHAR2 IS
BEGIN
RETURN InitCap(Lower(first_name))
|| ' ' ||
Upper(middle_initial)
|| ' ' ||
InitCap(Lower(last_name));
END;
MEMBER PROCEDURE Capitalize IS
BEGIN
first_name := Upper(first_name);
last_name := Upper(last_name);
middle_initial := Upper(middle_initial);
END;
END; -- end create type -----------------------------/
281
Oracle Objects
Creating/Using an Oracle OBJECT
>Desc t_person_name
Name
Type
--------------------- -----------------------FIRST_NAME
VARCHAR2(20)
LAST_NAME
VARCHAR2(20)
MIDDLE_INITIAL
CHAR(1)
T_PERSON_NAME
+ first_name
+ last_name
+ middle_initial
+ Get_Name ( )
+ Capitalize ( )
METHOD
-----MEMBER FUNCTION GET_NAME RETURNS VARCHAR2
MEMBER PROCEDURE CAPITALIZE
282
Oracle Objects
Oracle OBJECTS - Constructor
•
•
As in Java, the language provides an implicit (default) constructor for
each object type.
Arguments of the default constructor are not defaulted, therefore you
must supply a value for each parameter (even if that value is null) .
EXAMPLES
P t_person_type;
…
P := t_person_name(); -- ERROR invalid definition
P := t_person_type(null, null, null);
P := t_person_type('Maria', 'Macarena', 'S');
P := t_person_type('Jose', 'Cuervo', null);
283
Oracle Objects
Creating/Using a simple Oracle OBJECT
declare
p t_person_name;
begin
p := t_person_name(null,null,null);
select
into
from
where
T_PERSON_NAME
+ first_name
+ last_name
+ middle_initial
+ Get_Name ( )
+ Capitalize ( )
fname, lname, minit
p.first_name, p.last_name, p.middle_initial
employee
ssn=123456789;
dbms_output.put_line('>>> ' || p.Get_Name() );
p.Capitalize();
dbms_output.put_line('>>> ' || p.last_name );
end;
/
>>> John B Smith
>>> SMITH
284
Oracle Objects
Creating a Table of Oracle OBJECTS
•
Object persistency could be achieved by defining
Object-Tables (objects + optional primitive
types)
Create table MyAmigos of t_person_name;
285
Oracle Objects
Creating a Table of Oracle OBJECTS
T_PERSON_NAME
+ first_name
+ last_name
+ middle_initial
CREATE TABLE objPeople OF t_Person_Name
+ Get_Name ( )
+ Capitalize ( )
/
INSERT INTO objPeople VALUES (t_Person_Name ('Maria','Macarena', 'S'));
INSERT INTO objPeople VALUES (t_Person_Name ('Carmen','SanDiego', 'L'));
INSERT INTO objPeople VALUES (t_Person_Name ('Harry','Potter', null) );
INSERT INTO objPeople VALUES (t_Person_Name ('Porky', 'Pig', null))
/
286
Oracle Objects
Using a Table of Oracle OBJECTS
T_PERSON_NAME
>desc objPeople
Name
----------------------------------FIRST_NAME
LAST_NAME
MIDDLE_INITIAL
Type
-----------VARCHAR2(20)
VARCHAR2(20)
CHAR(1)
+ first_name
+ last_name
+ middle_initial
+ Get_Name ( )
+ Capitalize ( )
>select * from objPeople;
FIRST_NAME
-------------------Maria
Carmen
Harry
Porky
LAST_NAME
-------------------Macarena
SanDiego
Potter
Pig
M
S
L
287
Oracle Objects
Using a Table of Oracle OBJECTS
> select p.*, p.get_name()
from objPeople p
where p.first_name like '_a%'
FIRST_NAME
------------Maria
Carmen
Harry
LAST_NAME
----------Macarena
SanDiego
Potter
M
S
L
T_PERSON_NAME
+ first_name
+ last_name
+ middle_initial
+ Get_Name ( )
+ Capitalize ( )
P.GET_NAME()
-----------------------Maria S Macarena
Carmen L SanDiego
Harry Potter
288
Oracle Objects
Using a Table of Oracle OBJECTS
select VALUE(p) from objPeople p;
T_PERSON_NAME
+ first_name
+ last_name
+ middle_initial
VALUE(P)(FIRST_NAME, LAST_NAME, MIDDLE_INITIAL)
-----------------------------------------------T_PERSON_NAME('Maria', 'Macarena', 'S')
T_PERSON_NAME('Carmen', 'SanDiego', 'L')
T_PERSON_NAME('Harry', 'Potter', NULL)
T_PERSON_NAME('Porky', 'Pig', NULL)
select VALUE(p).Get_Name()
from objPeople p
where p.Last_Name LIKE 'Mac%';
+ Get_Name ( )
+ Nullify ( )
•
The VALUE function returns rows
as object instances.
•
The argument MUST be a
correlated variable.
VALUE(P).GET_NAME()
-----------------------------------Maria S Macarena
289
Oracle Objects
Using a Table of Oracle OBJECTS
References
•
A REF is a logical pointer to a row object that is constructed from the object
identifier (OID) of the referenced object and is an Oracle built-in datatype.
•
Function REF(e) requires e to be a correlation variable (alias). It returns the
OID of a persistent (table bound) object.
•
REFs and collections of REFs model associations among objects,
particularly many-to-one relationships, reducing the need for foreign keys.
•
REFs provide an easy mechanism for navigating between objects. You can
use the dot notation to follow the pointers.
•
The DEREF(e) functions takes a pointer e and returns the object instance
referenced by e.
290
Oracle Objects
Using a Table of Oracle OBJECTS
select REF(p), VALUE(p).Get_Name()
from objPeople p
where p.Last_Name LIKE 'Mac%';
REF(P)
--------------------------------------------------VALUE(P).GET_NAME()
-------------------------------------------------0000280209F7283D94DA8B4A6894E6043F14D4E48
26BCDD86D79E64B49801F9B5ADCFD3032010001960000
Maria S Macarena
291
Oracle Objects
Creating/Linking Tables of
Oracle OBJECTS
drop table emp_boss purge
/
drop type emp_boss_type
/
CREATE TYPE emp_boss_type AS OBJECT
(
emp
VARCHAR2(30),
boss
REF t_Person_Name
)
/
CREATE TABLE emp_boss
OF emp_boss_type;
INSERT INTO emp_boss
SELECT emp_boss_type ('Paula Salsa1', REF(b))
FROM objPeople b
WHERE b.last_name LIKE 'Mac%'
/
INSERT INTO emp_boss
SELECT emp_boss_type ('Jose Salsa2', REF(b))
FROM objPeople b
WHERE b.last_name LIKE 'Mac%'
/
INSERT INTO emp_boss
SELECT emp_boss_type ('Hermione', REF(b))
FROM objPeople b
WHERE b.last_name LIKE 'Potter'
/
292
Oracle Objects
Creating/Linking Tables of Oracle OBJECTS
293
Oracle Objects
Creating/Linking Tables of Oracle OBJECTS
select e.emp, e.boss,
(e.boss).last_name, (e.boss).Get_Name()
from emp_boss e;
EMP
BOSS
(E.BOSS).LAST_NAME
(E.BOSS).GET_NAME()
--------------- ------------------------------------- -------------------- -------------------Paula Salsa1
0000220208F7283D94DA8B4A6894E6043F14D Macarena
Maria S Macarena
4E4826BCDD86D79E64B49801F9B5ADCFD3032
Jose Salsa2
0000220208F7283D94DA8B4A6894E6043F14D Macarena
4E4826BCDD86D79E64B49801F9B5ADCFD3032
Maria S Macarena
Hermione
0000220208983E6EEDF6CB402D9B7133727B8 Potter
A458D6BCDD86D79E64B49801F9B5ADCFD3032
Harry
Reference to
POTTER
Potter
Reference to
MACARENA
294
Oracle Objects
Creating/Linking Tables of Oracle OBJECTS
select e.*, DEREF(e.boss) from emp_boss e;
EMP
BOSS
--------------- ------------------------------------DEREF(E.BOSS)(FIRST_NAME, LAST_NAME, MIDDLE_INITIAL)
----------------------------------------------------Paula Salsa1
0000220208F7283D94DA8B4A6894E6043F14D
4E4826BCDD86D79E64B49801F9B5ADCFD3032
T_PERSON_NAME('Maria', 'Macarena', 'S')
Jose Salsa2
0000220208F7283D94DA8B4A6894E6043F14D
4E4826BCDD86D79E64B49801F9B5ADCFD3032
T_PERSON_NAME('Maria', 'Macarena', 'S')
Dereferencing REFs
•
Accessing the object referred
to by a REF is called
dereferencing the REF.
•
Oracle provides the DEREF
operator to do this.
•
Dereferencing a dangling REF
returns a null object (the
predicate IS DANGLING could
be used to test null REFs.
Hermione
0000220208983E6EEDF6CB402D9B7133727B8
A458D6BCDD86D79E64B49801F9B5ADCFD3032
T_PERSON_NAME('Harry', 'Potter', NULL)
295
Oracle Objects
Tables holding Objects and Simple DataTypes
drop table objPeople2;
drop type t_person_name_phone
/
CREATE TYPE t_Person_Name_Phone AS OBJECT
(
phone
VARCHAR2(20),
guy
t_person_name,
MEMBER FUNCTION
Get_Phone RETURN VARCHAR2
);
/
CREATE TYPE BODY t_Person_Name_Phone AS
MEMBER FUNCTION Get_Phone RETURN VARCHAR2 IS
BEGIN
if LENGTH(phone) < 10 then
return '(216)' || phone;
else
return phone;
end if;
END;
END;
/
296
Oracle Objects
Tables holding Objects and Simple DataTypes cont.
create table objPeople2 of t_person_name_phone
/
insert into objPeople2 values
( t_person_name_phone
t_person_name
);
insert into objPeople2 values
( t_person_name_phone
t_person_name
);
insert into objPeople2 values
( t_person_name_phone
t_person_name
);
/
('2165551234',
('F1F1','L1L1', null) )
('333-1234',
('F2F2','L2L2', null) )
('444-4321',
('F3F3','L3L3', null) )
297
Oracle Objects
Tables holding Objects and Simple DataTypes cont.
objPeople2
Guy
[t_person_name]
Phone
First_Name
Last_Name
Midle_Initial
216 555 1234
F1F1
L1L1
Null
333 1234
F2F2
L2L2
Null
444 4321
F3F3
L3L3
Null
298
Oracle Objects
Tables holding Objects and Simple DataTypes cont.
CSUPERSON SQL> set describe depth all
CSUPERSON SQL> desc objPeople2
Name
Null?
Type
--------------------------------------- -------- ------------PHONE
VARCHAR2(20)
GUY
T_PERSON_NAME
FIRST_NAME
VARCHAR2(20)
LAST_NAME
VARCHAR2(20)
MIDDLE_INITIAL
CHAR(1)
METHOD
-----MEMBER FUNCTION GET_NAME RETURNS VARCHAR2
MEMBER PROCEDURE CAPITALIZE
299
Oracle Objects
Tables holding Objects and Simple DataTypes cont.
select p.*,
REF(p),
p.get_phone(),
value(p),
p.guy.last_name,
p.guy.get_name()
from objPeople2 p
where p.guy.first_name = 'F1F1‘;
PHONE
GUY
----------- ----------------------------------------------------------------2165551234 T_PERSON_NAME('F1F1', 'L1L1', NULL)
0000280209FBFC690AFB4C434C859A9796D037 . . . E46BCDD7092ADF0100058C0000
2165551234
2165551234 T_PERSON_NAME_PHONE('2165551234', T_PERSON_NAME('F1F1', 'L1L1', NULL))
L1L1
F1F1
L1L1
300
Oracle Objects
Nested Objects
STUDENTT
Create or replace
Type STUDENTT as object (
stud
t_person_name,
gpa
number,
Stud : T_PERSON_NAME
First_name
Last_name
GPA
Middle_initial
static function NEW (pPerson t_person_name, pGpa number)
return STUDENTT
);
301
Oracle Objects
Nested Objects cont.
create or replace
type body STUDENTT as
static function NEW ( pStud t_person_name, pGpa number)
return StudentT is
begin
return StudentT (pStud , pGpa);
end;
end;
/
302
Oracle Objects
Tables holding Objects and Simple DataTypes cont.
CSUPERSON SQL> desc studentT
Name
Null?
------------------------------------------- -------STUD
FIRST_NAME
LAST_NAME
MIDDLE_INITIAL
Type
------------T_PERSON_NAME
VARCHAR2(20)
VARCHAR2(20)
CHAR(1)
METHOD
-----MEMBER FUNCTION GET_NAME RETURNS VARCHAR2
MEMBER PROCEDURE CAPITALIZE
GPA
NUMBER
METHOD
-----STATIC FUNCTION NEW RETURNS STUDENTT
Argument Name
Type
------------------------------ ----------------------PPERSON
T_PERSON_NAME
PGPA
NUMBER
In/Out Default?
------ -------IN
IN
303
Oracle Objects
Nested Objects cont.
declare
s1 studentT;
Begin
s1 := studentT.new( t_person_name('Juan', 'Valdez', null), 3.98 );
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
('GPA:
' ||
('First: ' ||
('Last: ' ||
('Get_Name: '
s1.gpa);
s1.stud.first_name );
s1.stud.last_name );
|| s1.stud.Get_Name() );
end;
/
GPA:
3.98
First: Juan
Last: Valdez
Get_Name: Juan
Valdez
304
Oracle Objects
Comparing Objects.
•
The MAP method is used to compare two objects.
•
It returns a scalar-value which can be used to compare and
order the object type.
•
MAP accepts as its parameter the SELF built-in parameter.
•
An object type can only have one MAP method defined.
305
Oracle Objects
Comparing Objects.
Create or replace
Type STUDENTT as object (
stud
t_person_name,
gpa
number,
map member function Merits return number,
member function ShowMe return varchar2;
static function NEW ( pStud t_person_name,
pGpa
number)
return STUDENTT
) NOT FINAL;
/
306
Oracle Objects
Comparing Objects.
create or replace
type body STUDENTT as
static function NEW ( pStud t_person_name, pGpa number) return StudentT
is
begin
return StudentT (pStud , pGpa);
end;
member function ShowMe return varchar2 is
begin
return ' Sut. Name: ' || self.stud.get_name() ||
' Gpa: ' || self.gpa;
end;
map member function Merits return number is
begin
return self.gpa;
end;
end;
/
307
Oracle Objects
Comparing Objects.
T_PERSON_NAME
+ first_name
+ last_name
+ middle_initial
+ Get_Name ( )
+ Capitalize ( )
STUDENTT
+ Stud
+ GPA
t_person_name
number
+ Merits ( )
return number
+ ShowMe ( ) return varchar2
+ NEW ( t_person_name, number)
308
Oracle Objects
Comparing Objects.
declare
--testing the MAP/ORDER function
s1 studentT;
s2 studentT;
begin
s1 := studentT.new( t_person_name('Juan', 'Valdez', null), 3.98 );
s2 := studentT.new( t_person_name('Diego','DeLaVega',null), 4.00);
if s1 > s2 then
dbms_output.put_line
dbms_output.put_line
else
dbms_output.put_line
dbms_output.put_line
end if;
end;
('Numero UNO is : ' || s1.stud.Get_Name() );
('Numero DOS is : ' || s2.stud.Get_Name() );
('Numero UNO is : ' || s2.stud.Get_Name() );
('Numero DOS is : ' || s1.stud.Get_Name() );
Numero UNO is : Diego Delavega
Numero DOS is : Juan Valdez
309
Oracle Objects
Object Inheritance.
INHERITANCE
Create or replace
Type Graduate_STUDENTT UNDER StudentT (
Credits
NUMBER,
overriding member function ShowMe return varchar2
) NOT FINAL;
/
create or replace
type body Graduate_STUDENTT as
POLYMORPHISM
overriding member function ShowMe return varchar2 is
begin
return ' Sut. Name: ' || self.stud.get_name() ||
' Gpa: '
|| self.gpa
' Credits: '
|| self.credits;
end;
end;
/
310
Oracle Objects
Inheritance.
T_PERSON_NAME
+ first_name
+ last_name
+ middle_initial
+ Get_Name ( )
+ Capitalize ( )
STUDENTT
HAS_A
+ Stud
+ GPA
t_person_name
number
+ Merits ( ) return number
+ ShowMe ( ) return varchar2
+ NEW ( t_person_name, number)
IS_A
GRADUATE_STUDENTT
+ Credits
number
+ ShowMe ( ) return varchar2
311
Oracle Objects
Object Inheritance.
declare
--exploring the base class: STUDENTT (reviewing)
ugs StudentT;
begin
ugs := studentT( t_person_name('Juan', 'Valdez', null),
3.98 );
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
('First: ' ||
('Last: ' ||
('GPA:
' ||
('Get_Name: '
gs.stud.first_name );
gs.stud.last_name );
gs.gpa);
|| gs.stud.Get_Name() );
dbms_output.put_line ('ShowMe>>> ' || gs.ShowMe() );
end;
/
First: Juan
Last: Valdez
GPA:
3.98
Get_Name: Juan
ShowMe>>>
Valdez
Sut. Name: Juan
Valdez Gpa:
3.98
312
Oracle Objects
Object Inheritance.
declare
--extending the base class: STUDENTT
gs Graduate_StudentT;
begin
gs := graduate_studentT( t_person_name('Juan', 'Valdez', null),
3.98,
132 );
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
dbms_output.put_line
('First: ' ||
('Last: ' ||
('GPA:
' ||
('Get_Name: '
gs.stud.first_name );
gs.stud.last_name );
gs.gpa);
|| gs.stud.Get_Name() );
dbms_output.put_line ('Credits: ' || gs.credits);
dbms_output.put_line ('ShowMe >> ' || gs.ShowMe() );
end;
/
First: Juan
Last: Valdez
GPA:
3.98
Get_Name: Juan
Valdez
Credits: 132
ShowMe >> Sut. Name: Juan
Valdez Gpa:
3.98 Credits: 132
313
PL/SQL Programming
CURSORS
314
PL/SQL Cursors
• A cursor is a type of pointer built into PL/SQL to
provide sequential (one row at a time) access to
the rows produced by a SQL statement.
• Depending on the cursor’s life cycle and
management code there are two types
 Implicit cursors (controlled by PL/SQL on execution of
DML-maintenance or select … into statements)
 Explicit cursors (created with a select statement)
315
PL/SQL Cursors
cursor points to the current
row in the present table.
It also provides additional
information such as the
availability of data, number
of visited records, etc.
Position
Column1
…
Column n
1
2
…
…
N-1
N
316
PL/SQL Cursors Attributes
Attribute
Definition
%Found
True when last FETCH operation finds a record
in the result set made by the cursor.
%NotFound
True when last FETCH operation does not find a
record.
%RowCount
Returns the count of records that have been
fetched from the cursor at the current point.
%IsOpen
True when the cursor has been opened.
317
PL/SQL Implicit Cursors
• Implicit cursors are opened/closed automatically by
Oracle.
• Created as a result of some operation on your PL/SQL.
However you dot explicitly create any CURSOR type
variable.
• They could be created in association to the execution of
– DML SQL code (insert, delete, update)
– A CURSOR-FOR-LOOP
318
PL/SQL Implicit Cursors
--Implicit cursor in SQL code
Records affected: 0
No project found with given Pnumber
Records affected: 6
PROCEDURE EXAMPLE12 AS
BEGIN
update Project set Pname = Pname where Pnumber = -1;
Implicit cursor’s
name is SQL
dbms_output.put_line('Records affected: ' || sql%RowCount );
if sql%NotFound then
dbms_output.put_line ('No project found with given
end if;
Pnumber');
update Project set Pname = Pname;
dbms_output.put_line('Records affected: ' || sql%RowCount );
END;
319
PL/SQL Implicit Cursors
For_Loop Cursor
PROCEDURE EXAMPLE13 AS
BEGIN
CSUPERSON SQL> exec example13;
Emp:
Emp:
Emp:
Emp:
Emp:
John Smith makes $30000
Franklin Wong makes $40000
Ramesh Narayan makes $38000
Ahmad Jabbar makes $25000
James Borg makes $55000
for guy in (select fname, lname, salary
from employee
where sex = 'M') loop
dbms_output.put (' Emp: ' || guy.Fname || ' ' || guy.Lname );
dbms_output.put (' makes $' || guy.salary );
end loop;
END;
320
PL/SQL Explicit Cursors
Why & When to Use EXPLICIT CURSORS
– For full control over query processing, you can use explicit
cursors in combination with the OPEN, FETCH, and CLOSE
statements.
– You might want to specify a query in one place but retrieve the
rows somewhere else, even in another subprogram.
– Or you might want to choose very different query parameters,
such as ORDER BY or GROUP BY clauses, depending on the
situation.
– Or you might want to process some rows differently than others,
and so need more than a simple loop.
321
PL/SQL Explicit Cursors
Used with select statements returning more than one row.
Explicit Cursors are declared with the construct
CURSOR cursorName [(parameter(s)]
[RETURN RowType ]
IS
some_Sql_Select_Statement;
The life-cycle of the cursor involves
• Open the cursor
• Fetch a row from the cursor
• Close the cursor
322
PL/SQL Cursors Attributes
Every explicit cursor has access to the four attributes:
%FOUND, %NOTFOUND, %ROWCOUNT, %ISOPEN
OPEN
First FETCH
Next FETCH(es)
Last FETCH
CLOSE
%FOUND
%ISOPEN
%NOTFOUND
%ROWCOUNT
before
exception
FALSE
exception
exception
after
NULL
TRUE
NULL
0
before
NULL
TRUE
NULL
0
after
TRUE
TRUE
FALSE
1
before
TRUE
TRUE
FALSE
1
after
TRUE
TRUE
FALSE
data dependent
before
TRUE
TRUE
FALSE
data dependent
after
FALSE
TRUE
TRUE
data dependent
before
FALSE
TRUE
TRUE
data dependent
after
exception
FALSE
exception
exception
Notes:
1.
2.
Referencing %FOUND, %NOTFOUND, or %ROWCOUNT before a cursor is opened or after it is closed raises
INVALID_CURSOR.
After the first FETCH, if the result set was empty, %FOUND yields FALSE, %NOTFOUND yields TRUE, and %ROWCOUNT
yields 0.
323
PL/SQL Explicit Cursors
-- Get SSN of male employees
Explicit definition of the cursor variable
DECLARE
CURSOR C1
IS SELECT ssn FROM employee WHERE sex =
BEGIN
' M ';
OPEN, CLOSE, FETCH is taken care of
by the FOR-LOOP.
FOR person IN C1
LOOP
DBMS_OUTPUT.PUT_LINE('SSN = ' || person.ssn);
END LOOP;
END;
/
324
PL/SQL Explicit Cursors
-- Get Fname & Salary of male employees
Explicit definition of the cursor variable
DECLARE
CURSOR C1 RETURN Employee%rowtype
IS SELECT * FROM employee WHERE sex = 'M';
BEGIN
OPEN, CLOSE, FETCH is taken care of
FOR person IN C1
by the FOR-LOOP.
LOOP
DBMS_OUTPUT.PUT_LINE(person.Fname '' || person.Lname);
END LOOP;
END;
John Smith
Franklin Wong
Ramesh Narayan
Ahmad Jabbar
James Borg
Harry Potter
325
PL/SQL Explicit Cursors
-- Find the top three projects using the highest number of employees of a given
gender.
PROCEDURE Proj_Using_Most_People_ByGender (TheGender Employee.Sex%Type)
IS
ProjId Works_On.Pno%TYPE;
Explicit cursor finding the project
ProjCnt number;
CURSOR
number and count of employees by
gender.
Get_People_Involved(Gender IN Employee.Sex%Type)
IS
select w.Pno, count(*) as TotalPeople
from Works_On w, Employee e
where e.Sex = Gender
and e.Ssn = w.Essn
TheGender = {M, F}
group by w.Pno
Cursor finds the projects employing the most
order by TotalPeople desc;
female/male workers in the company
BEGIN
open Get_People_Involved(TheGender);
Just in case we don’t
for i in 1..3 loop
have three projects
fetch Get_People_Involved into ProjId, ProjCnt;
exit when Get_People_Involved%NOTFOUND;
dbms_output.put_line (' Project: ' || ProjId ||' Personnel: ' || ProjCnt );
end loop;
close Get_People_Involved;
EXCEPTION
when others then
OPEN, CLOSE, FETCH is explicitly
dbms_output.PUT_LINE ( 'Problems' );
managed by the user’s code
END;
326
PL/SQL Explicit Cursors
Find the three projects using the most FEMALE employees.
CSUPERSON
Project:
Project:
Project:
SQL> exec Proj_Using_Most_People_ByGender ('F');
30 Personnel: 2
1 Personnel: 1
2 Personnel: 1
PNO
TotalPeople
30
2
1
1
2
1
10
1
20
1
Temporary table is created after the command
OPEN Get_People_Involved(TheGender)
is executed
This row will be retrieved the second time the
FETCH operator is executed
327
PL/SQL Explicit Cursors
Find top three salaries in the company
PROCEDURE EXAMPLE19 AS
cursor ThreePeople is
Select * from employee
where rowNum <= 3
order by salary desc;
OneEmp employee%rowType;
Looking at rec. no. 1 Name: Wong Salary: 40000
Looking at rec. no. 2 Name: Smith Salary: 30000
Looking at rec. no. 3 Name: Zelaya Salary: 25000
BEGIN
open ThreePeople;
fetch ThreePeople into OneEmp;
loop
if ThreePeople%FOUND then
dbms_output.put_line('Looking at rec. no. ' ||
ThreePeople%RowCount ||
' Name: ' || OneEmp.Lname ||
' Salary: ' || OneEMp.Salary );
fetch ThreePeople into OneEmp;
elsif ThreePeople%NOTFOUND then
exit; --finish the loop
end if;
end loop;
if ThreePeople%ISOPEN then
close ThreePeople;
end if;
END;
328
PL/SQL Ref Cursors
Using Cursor Variables (REF CURSORs)
• Implicit and Explicit cursors are static. They are defined at
compile time.
• Ref Cursors are dynamic in the sense they are created and
processed at run-time.
• You use them when you want to perform a SQL query in one
(producer) subprogram, and process the results in a
different (consumer) subprogram (possibly one written in a
different language).
329
PL/SQL Ref Cursors
Using Cursor Variables (REF CURSORs)
• A result set could be produced by a PL/SQL Function or
Procedure and returned using a SYS_REFCURSOR
variable.
• The OPEN-FOR statement associates a cursor variable
with a multi-row query, executes the query, and identifies the
result set.
330
PL/SQL Ref Cursors
Get the name of each department and its corresponding manager
PROCEDURE EXAMPLE15(Managers IN OUT SYS_REFCURSOR) AS
BEGIN
open Managers for
select (e.Fname || ' ' || e.Lname) FullName, d.Dname
from Department d, Employee e
where (d.MgrSsn = e.SSN) ;
END;
CSUPERSON SQL> var x refCursor;
CSUPERSON SQL> exec example15( :x );
PL/SQL procedure successfully completed.
CSUPERSON SQL> print x;
FULLNAME
-------------------------Franklin Wong
James Borg
Jennifer Wallace
DNAME
--------------Research
Headquarters
Administration
331
PL/SQL Ref Cursors
(Dynamically) Return a Database table using a
SYS_RefCursor variable
PROCEDURE EXAMPLE16 (theTable IN varchar2,
myResult IN OUT SYS_REFCURSOR) AS
BEGIN
CSUPERSON SQL> var x RefCursor;
if theTable = 'E' then
CSUPERSON SQL> exec Example16('D', :x );
open myResult for
CSUPERSON SQL> print x;
select * from employee;
DNAME
DNUMBER MGRSSN
MGRSTARTD
elsif theTable = 'D' then
--------------- ---------- --------- --------open myResult for
Research
5 333445555 22-MAY-78
select * from department;
Administration
4 987654321 01-JAN-85
elsif theTable = 'P' then
Headquarters
1 888665555 19-JUN-71
open myResult for
CSUPERSON SQL> exec Example16('P', :x);
select * from project;
CSUPERSON SQL> print x;
else
open myResult for
PNAME
PNUMBER PLOCATION
DNUM
select * from works_on;
----------------- ---------- ---------- ---------end if;
ProductX
1 Bellaire
5
ProductY
2 Sugarland
5
END;
ProductZ
Computerization
Reorganization
Newbenefits
3
10
20
30
Houston
Stafford
Houston
Stafford
5
4
1
4
332
PL/SQL Ref Cursors
Passing Cursor Variables As Parameters
• You can declare cursor variables as the formal parameters
of functions and procedures.
• The following example defines a REF CURSOR type, then
declares a cursor variable of that type as a formal
parameter:
333
PL/SQL Ref Cursors
DECLARE
TYPE EmpCurTyp IS REF CURSOR RETURN Employee%ROWTYPE;
emp EmpCurTyp;
-- Once we have a result set, we can process all the rows
-- inside a single procedure rather than calling a procedure
-- for each row.
PROCEDURE process_emp_cv (emp_cv IN EmpCurTyp) IS
person Employee%ROWTYPE;
BEGIN
dbms_output.put_line('-----');
dbms_output.put_line('Here are the names from the result set:');
LOOP
----FETCH emp_cv INTO person;
Here are the names from the
EXIT WHEN emp_cv%NOTFOUND;
result set:
dbms_output.put_line('Name = ' ||
person.fname ||' ' || person.lname); Name = John Smith
END LOOP;
Name = Franklin Wong
END;
Name = Alicia Zelaya
Name = Jennifer Wallace
BEGIN
Name = Ramesh Narayan
-- First find 10 arbitrary employees.
Name = Joyce English
OPEN emp FOR SELECT * FROM employee WHERE ROWNUM < 11;
Name = Ahmad Jabbar
process_emp_cv(emp);
Name = James Borg
CLOSE emp;
------ Then find employees matching a condition.
Here are the names from the
OPEN emp FOR SELECT * FROM employee WHERE lname LIKE 'W%';
result set:
process_emp_cv(emp);
Name = Franklin Wong
CLOSE emp;
Name = Jennifer Wallace
END;
/
334
PL/SQL Nested Cursors
A cursor could be opened inside the scope of another. This nesting
of cursors provides a powerful programming tool for more
complex queries.
Example:
A department number is given. Find all the employees working for
this department and their corresponding assignments. Provide
only one row for each employee (regardless of the total number of
projects in which they work)
For instance
Emp SSN: 333445555 Project(s): {2, 3, 10, 20}
335
PL/SQL Example 16
Nesting loops. Employees and their SET of projects
PROCEDURE Example17(DeptNumber number)
IS
EmpRec
Employee%ROWTYPE;
WorkRec
Works_On%ROWTYPE;
Message1
VARCHAR2(40);
Message2
VARCHAR2(40);
Comma
VARCHAR2(3):= ' ';
CURSOR
Guys_in_Dept ( DeptNumber number ) IS
select * from employee
where Dno = DeptNumber
order by ssn;
CURSOR
Working_On ( EmpSsn varchar ) IS
select * from works_on
where Essn = EmpSsn
order by pno;
336
PL/SQL Example 16 cont.
--Nesting
loops. Employees and their SET of projects
BEGIN
FOR EmpRec IN Guys_in_Dept(DeptNumber) LOOP
Message1:= ' Emp SSN: ' || EmpRec.Ssn;
Message2:= ' Project(s): {';
Comma := '';
FOR WorkRec IN Working_On(EmpRec.SSN) LOOP
Message2:= Message2 || Comma || WorkRec.Pno;
Comma := ', ';
END LOOP;
DBMS_OUTPUT.PUT_LINE(Message1 || Message2 || '}' );
END LOOP;
EXCEPTION
WHEN Others THEN
DBMS_OUTPUT.PUT_LINE('Problems. ssn ' || EmpRec.SSN);
END;
SQL> exec Example16(5)
Emp SSN: 123456789 Project(s):
Emp SSN: 333445555 Project(s):
Emp SSN: 453453453 Project(s):
Emp SSN: 666884444 Project(s):
{1, 2}
{2, 3, 10, 20}
{1, 2}
{3}
337
PL/SQL Programming
BATCH Processing.
338
PL/SQL Cursors – Batch Operations
Batch Processing
• A group of transactions (insert, delete, and update) are stored in a
transaction table.
• Those operations will be applied to the master database at a later time.
Read one Transaction
until no more data
INSERTION
code
UPDATE
code
DELETE
code
INVALID
OPERATIONS
339
PL/SQL Cursors – Batch Operations
Example:
The following work-assignments will be used to change the
WORKS_ON table.
Transactions: (i) insert, (d) delete, (u) update
SQL> select * from WorkAction;
SSN
---------123456789
123456789
666884444
666884444
123456789
PNUM
---1
10
3
1
30
OPER NEW_HOURS STATUS
TIMEMARK
---- --------- ---------- --------u
10
24-SEP-06
i
15
25-SEP-06
d
25-SEP-06
u
40
26-SEP-06
y
10
27-SEP-06
master file
SQL> select * from Works_On;
ESSN
PNO
HOURS
--------- --------- --------123456789
1
32.5
123456789
2
7.5
666884444
3
40
453453453
1
20
453453453
2
20
333445555
2
10
333445555
3
10
333445555
10
10
333445555
20
10
999887777
30
30
999887777
10
10
987987987
10
35
987987987
30
5
987654321
30
20
987654321
20
15
888665555
20
0
16 rows selected.
340
PL/SQL Cursors – Batch Operations
/* -----------------------------------------------------------------** This program modifies the WORKS_ON table based on instructions
** stored in the WorkAction table. Each row of the ACTION table
** contains a (SSN,ProjecNumber) key, an action to be taken (u,i,d =
** insert, update, or delete), a number of Hours by which to update the
** work load, and a time stamp.
**
** On an insert, if the assignment already exists, an update is
** performed instead. On an update, if the assignment does not exist,
** it is created by an insert. On a delete, if the row does not
** exist, no action is taken.
** ------------------------------------------------------------------*/
Create or replace
PROCEDURE BatchUpdate
IS
CURSOR cTransaction IS
SELECT ssn, pnumb, oper_type, new_hours
FROM WorkAction
ORDER BY TimeMark
FOR UPDATE OF Status;
341
PL/SQL Cursors – Batch Operations
BEGIN
FOR wload IN cTransaction LOOP -- process each row from WorkAction
wload.oper_type := upper(wload.oper_type);
/*------------------------------------------------------------*
* Process an UPDATE. If the assignment to be updated doesn't *
* exist, create a new assignment.
*
*------------------------------------------------------------*/
IF wload.oper_type = 'U' THEN
BEGIN
UPDATE works_on
SET hours = wload.new_Hours
WHERE (essn = wload.ssn) AND (pno = wload.Pnumb);
IF ( SQL%NOTFOUND )THEN
/* work load didn't exist. Create it. */
INSERT INTO Works_On
VALUES (wload.ssn, wload.pnumb, wload.new_Hours);
UPDATE WorkAction
SET status = 'Update: ID not found. Value inserted.'
WHERE CURRENT OF cTransaction;
ELSE
UPDATE WorkAction
SET status = 'Update: Success.'
WHERE CURRENT OF cTransaction;
END IF;
END;
342
PL/SQL Cursors – Batch Operations
/*------------------------------------------------------------*
* Process an INSERT. If the assignment already exists, do an *
* update of the assignment instead.
*
*-------------------------------------------------------------*/
ELSIF wload.oper_type = 'I' THEN
BEGIN
INSERT INTO Works_On
VALUES (wload.ssn, wload.pnumb, wload.new_Hours);
UPDATE WorkAction
SET status = 'Insert: Success.'
WHERE CURRENT OF cTransaction;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
/* assignment already exists */
UPDATE Works_On
SET Hours = wload.new_Hours
WHERE (essn = wload.ssn) AND
(pno = wload.Pnumb);
UPDATE WorkAction
SET status = 'Insert: exists. Updated instead.'
WHERE CURRENT OF cTransaction;
END;
343
PL/SQL Cursors – Batch Operations
/*-------------------------------------------------------------*
* Process a DELETE. If the assignment doesn't exist, set the *
* status field to say that the assignment wasn't found.
*
*--------------------------------------------------------------*/
ELSIF wload.oper_type = 'D' THEN
BEGIN
DELETE FROM Works_On
WHERE (essn = wload.ssn) AND (pno = wload.Pnumb);
IF ( SQL%NOTFOUND ) THEN
-- work assignment didn't exist.
UPDATE WorkAction
SET status = 'Delete:ID not found.'
WHERE CURRENT OF cTransaction;
ELSE
UPDATE WorkAction
SET status = 'Delete: Success.'
WHERE CURRENT OF cTransaction;
END IF;
END;
344
PL/SQL Cursors – Batch Operations
/*-----------------------------------------------------------*
* The requested operation is invalid.
*
*------------------------------------------------------------*/
ELSE
/* oper_type is invalid */
UPDATE workAction
SET status = 'Error op. No action taken.'
WHERE CURRENT OF cTransaction;
END IF;
END LOOP;
COMMIT;
END;
345
PL/SQL Cursors – Batch Operations
WORKACTION: Transaction file BEFORE updating.
SSN
PNUMB O NEW_HOURS STATUS
--------- ---------- - ---------- ---------------------------------------123456789
1 U
10
123456789
10 I
15
666884444
3 D
666884444
1 U
40
123456789
30 X
10
TIMEMARK
--------24-JAN-05
25-JAN-05
25-JAN-05
26-JAN-05
27-JAN-05
WORKACTION: Transaction file AFTER update
SSN
PNUMB O NEW_HOURS STATUS
--------- ---------- - ---------- ---------------------------------------123456789
1 U
10 Update: Success.
123456789
10 I
15 Insert: Success.
666884444
3 D
Delete: Success.
666884444
1 U
40 Update: ID not found. Value inserted.
123456789
30 X
10 Error op. No action taken.
TIMEMARK
--------24-JAN-05
25-JAN-05
25-JAN-05
26-JAN-05
27-JAN-05
346
PL/SQL Cursors – Batch Operations
Works_ON table BEFORE updating
Works_On table AFTER updating
ESSN
PNO
HOURS
--------- ---------- ---------123456789
1
32.5
123456789
2
7.5
333445555
2
10
333445555
3
10
333445555
10
10
333445555
20
10
453453453
1
20
453453453
2
20
666884444
3
40
888665555
20
0
987654321
20
15
987654321
30
20
987987987
10
35
987987987
30
5
999887777
10
10
999887777
30
30
ESSN
PNO
HOURS
--------- ---------- ---------123456789
1
10
123456789
2
7.5
123456789
10
15
333445555
2
10
333445555
3
10
333445555
10
10
333445555
20
10
453453453
1
20
453453453
2
20
666884444
1
40
888665555
20
0
987654321
20
15
987654321
30
20
987987987
10
35
987987987
30
5
999887777
10
10
999887777
30
30
347
PL/SQL Cursors – Batch Operations
Try the example using the WorkAction table specification given below
drop table WORKACTION;
create table WORKACTION (
SSN
VARCHAR2(9),
PNUMB
NUMBER(5),
OPER_TYPE
VARCHAR2(1),
NEW_HOURS
NUMBER(5,1),
STATUS
VARCHAR2(40),
TIMEMARK
DATE);
INSERT
INSERT
INSERT
INSERT
INSERT
INTO
INTO
INTO
INTO
INTO
WORKACTION
WORKACTION
WORKACTION
WORKACTION
WORKACTION
VALUES
VALUES
VALUES
VALUES
VALUES
(123456789,
(123456789,
(666884444,
(666884444,
(123456789,
1 ,
10,
3 ,
1 ,
30,
'U',
'I',
'D',
'U',
'X',
10,
15,
NULL,
40,
10,
NULL,
NULL,
NULL,
NULL,
NULL,
'24-JAN-2005'
'25-JAN-2005'
'25-JAN-2005'
'26-JAN-2005'
'27-JAN-2005'
);
);
);
);
);
COMMIT;
348
PL/SQL Programming
EXCEPTIONS
349
PL/SQL Exceptions
• PL/SQL implements error detection and processing with
Exceptions and Exception Handlers.
• Errors fall into two categories
– Compile-Time errors (PL/SQL compiler is responsible)
– Run-Time errors (programmer is on charge)
• Undetected run-time errors produce abnormal program
termination –and usually total loss of the job.
350
PL/SQL Exceptions
The exception handler is similar to a CASE statement in which the
programmer could detect what type of error has been risen
Syntax is
EXCEPTION
[WHEN exceptionExpression1 THEN
statement(s);
[WHEN exceptionExpression2 THEN
statement(s);
[ . . .
]
]
]
exceptionExpression could be
– An Oracle pre-defined exception
– An user-define condition
– A PRAGMA EXCEPTION_INIT exception.
351
PL/SQL Exceptions
• An internal exception is raised automatically if your
PL/SQL program violates an Oracle rule or exceeds a
system-dependent limit.
• PL/SQL predefines some common Oracle errors as
exceptions.
– For example, PL/SQL raises the predefined exception
NO_DATA_FOUND if a SELECT INTO statement returns no
rows.
352
PL/SQL Exceptions
PL/SQL declares predefined exceptions globally in package
STANDARD (You don’t need to declare them yourself)
Oracle
Error
Exception
Description
ORA-0001
DUP_VAL_ON_INDEX
Unique constraint key violated
ORA-0051
TIMEOUT_ON_RESOURCE
Timeout occurred while waiting for a
resource
ORA-0904
INVALID_COLUMN_NAME
Illegal name
ORA-1001
INVALID_CURSOR
Illegal cursor operation
ORA_1403
NO_DATA_FOUND
No data found
ORA_1422
TOO_MANY_ROWS
A SELEC INTO statement matches more
than one row
ORA-1722
INVALID_NUMBER
Conversion to a number failed.
See. User’s Guide and Reference. Handling Run-Time PL/SQL Errors.
353
PL/SQL Exceptions
User-defined-Exceptions. Ordering a cup of coffee.
PROCEDURE EXAMPLE30 (LiquidTemperature NUMBER) AS
too_hot
EXCEPTION;
too_cold
EXCEPTION;
BEGIN
--order a cup of coffee
IF LiquidTemperature < 90 THEN
RAISE too_cold;
ELSIF LiquidTemperature > 104 THEN
RAISE too_hot;
ELSE
dbms_output.put_line('Uhhh, good coffee!!!');
END IF;
EXCEPTION
WHEN too_cold THEN
dbms_output.put_line('Problem - call manager and complaint');
WHEN too_hot THEN
dbms_output.put_line('Problem - call a good lawyer and sue');
WHEN OTHERS THEN
dbms_output.put_line('Problem - just complaint');
END;
354
PL/SQL Exceptions
User-Defined-Cond. Raise exception if video (book, bill, …) is overdue.
PROCEDURE EXAMPLE31 AS
past_due
EXCEPTION;
due_date
DATE := SYSDATE - 1;
todays_date DATE := SYSDATE;
acct_num
NUMBER;
BEGIN
CSUPERSON SQL> exec example17
IF due_date < todays_date THEN
RAISE past_due;
Problem – (my) PAST_DUE exception.
END IF;
EXCEPTION
WHEN past_due THEN --take care of the user-defined exception here
dbms_output.put_line('Problem – (my) PAST_DUE exception.');
--due something here (if possible!)
--to correct the problem
WHEN OTHERS THEN
dbms_output.put_line('Problem-something really bad happened');
END;
355
PL/SQL Exceptions
PRAGMA EXCEPTION_INIT
• Pragmas are pseudo-instructions telling the compiler to do something.
• PRAGMA EXECTION_INIT is a mechanism the developer could use
to trick Oracle into accepting that one of the developer’s exceptions is
(temporarily) replacing a pre-defined Oracle condition.
• You can use the pragma EXCEPTION_INIT to associate exception
names with other Oracle error codes that you can anticipate.
356
PL/SQL Exceptions
Write your own version of exception ORA-0904 “Invalid Column Name”
PROCEDURE EXAMPLE32 (tableName
varchar2,
updColumnName varchar2, updColumnValue varchar2,
keyName
varchar2, keyValue
varchar2)
as
MyInvalid_Column
EXCEPTION;
PRAGMA EXCEPTION_INIT (MyInvalid_Column, -904);
cmd_Update_Text varchar2(200);
begin
cmd_Update_Text :=
'update ' || tableName
||
'
set ' || updColumnName || ' = ''' || updColumnValue || '''' ||
' where ' || keyName
|| ' = ' || keyValue ;
execute immediate cmd_Update_Text; --dynamic SQL code
exception
when MyInvalid_Column then
dbms_output.put_line('**MY ERROR** invalid column name in command ');
dbms_output.put_line(cmd_Update_Text);
dbms_output.put_line('SqlCode: ' || sqlcode);
dbms_output.put_line('SqlErrm: ' || sqlErrm);
end;
exec Example32 ('project','Pnameeee','XYZ','Pnumber', '10');
**MY ERROR** invalid column name in command
update project set Pnameeee = 'XYZ' where Pnumber = 10
SqlCode: -904
SqlErrm: ORA-00904: "PNAMEEEE": invalid identifier
357
PL/SQL Example19 cont.
Observations
• Dynamic PL/SQL. Some programs must build and process
SQL statements where some information is not known in
advance.
• Dynamic SQL statements are made as strings at run time. The
strings contain the text of a SQL statement or PL/SQL block.
• To process most dynamic SQL statements, you use the
EXECUTE IMMEDIATE statement.
358
PL/SQL Example19 cont.
Apply the following changes on Example19
1.
Change “Pnameeee” to “Pname” on line
Exec Example32('project','Pnameeee','XYZ','Pnumber', '10');
1.
Change error code “904” to “7777” on line
PRAGMA EXCEPTION_INIT (invalid_Column, -904);
359
PL/SQL Exceptions
Defining Your Own Error Messages:
Procedure RAISE_APPLICATION_ERROR
The procedure RAISE_APPLICATION_ERROR lets you issue user-defined ORAerror messages from stored subprograms. That way, you can report errors to your
application and avoid returning unhandled exceptions.
Syntax
raise_application_error (error_number, message[, {TRUE | FALSE}]);
• error_number is a negative integer in the range -20000 .. -20999
• message is a character string up to 2048 bytes long.
• If the optional third parameter is TRUE, the error is placed on the stack of previous
errors. If the parameter is FALSE (the default), the error replaces all previous errors.
• An application can call raise_application_error only from an executing stored
subprogram (or method).
• When called, raise_application_error ends the subprogram and returns a user-defined
error number and message to the application.
• The error number and message can be trapped like any Oracle error.
360
PL/SQL Exceptions
Defining Your Own Error Messages: Procedure RAISE_APPLICATION_ERROR
DECLARE
num_tables NUMBER;
BEGIN
SELECT COUNT(*) INTO num_tables FROM USER_TABLES;
-- Issue your own error code (ORA-20101) with your own error message.
IF num_tables < 1000 THEN
raise_application_error(-20101,
'You need to work harder -- ' ||
' Expecting at least 1000 tables');
ELSE
-- Do the rest of the processing (for the non-error case).
NULL;
END IF;
END;
/
361
PL/SQL Programming
PACKAGES
362
PL/SQL Packages
•
A package is a schema object that groups logically related PL/SQL objects
•
Packages usually have two parts, a specification and a body (sometimes the
body is unnecessary).
•
The specification is the interface to the package. It declares the
–
–
–
–
–
–
•
types,
variables,
constants,
exceptions,
cursors, and the
signature of the subprograms that can be referenced from outside the package.
The body defines the queries for the cursors and the code for the subprograms.
363
PL/SQL Packages
Syntax
Package Specification
PACKAGE package_name
IS
[ declaration of public variables and user-defined-types]
[ specification of constants, exceptions ]
[ specification of cursors ]
[ signatures of procedures and functions ]
END [package_name ];
364
PL/SQL Packages
Package body definition
PACKAGE BODY package_name
IS
[ private variables, constants, exceptions and types ]
[ CURSOR specifications and SELECT stmts ]
[ Specification of Procedures and Functions ]
[ BEGIN ]
[ Executable statements ]
[ EXCEPTION ]
[ Exception handlers ]
END [ package_name ]
365
PL/SQL Packages
Advantages of PL/SQL Packages
•
Modularity
•
•
Easier Application Design
•
•
With packages, you can specify which types, items, and subprograms are public (visible and
accessible) or private (hidden and inaccessible).
Added Functionality
•
•
When designing an application, all you need initially is the interface information in the package
specs.
Information Hiding
•
•
Packages let you encapsulate logically related types, items, and subprograms in a named PL/SQL
module.
Packaged public variables and cursors persist for the duration of a session.
Better Performance
•
When you call a packaged subprogram for the first time, the whole package is loaded into
memory. Later calls to related subprograms in the package require no disk I/O.
366
PL/SQL Packages
Example of a PL/SQL Package
• The example below shows the package way of how to
support operations for the company database.
• The package contains
– A constant, a global variable, a cursor, an exception, and subs.
• The procedures hire_employee and fire_employee
– Check the existence of the person, verifies business rules and
either executes or aborts execution by raising an exception.
367
PL/SQL Packages
The Package Specification (Interface)
PACKAGE Emp_Actions AS
BAD_OPERATION
myPI
myStr
TYPE
EmpRecTyp
CURSOR desc_salary
EXCEPTION;
NUMBER := 3.141592;
VARCHAR2(120);
IS RECORD (SSN VARCHAR2(9), salary NUMBER(10,2));
RETURN EmpRecTyp;
PROCEDURE hire_employee (
pFNAME VARCHAR2
,pMINIT VARCHAR2
,pLNAME VARCHAR2
,pSSN VARCHAR2
,pBDATE DATE
,pADDRESS VARCHAR2
,pSEX VARCHAR2
,pSALARY NUMBER
,pSUPERSSN VARCHAR2
,pDNO NUMBER
);
PROCEDURE fire_Employee (pSSN NUMBER);
END emp_actions;
368
PL/SQL Packages
The Package Implementation
PACKAGE BODY emp_actions AS
CURSOR desc_salary
RETURN
SELECT
FROM
ORDER
EmpRecTyp IS
SSN, salary
employee
BY salary DESC;
PROCEDURE fire_Employee (pSSN NUMBER) IS
myCount NUMBER;
BEGIN
--here you add logic to make sure the employee could be
--safely removed from the table (without violating any
--business rules and/or referential integrity constraints)
select count(*) into myCount from employee where ssn = pSSN;
if (myCount = 0) then
--employee not found
RAISE emp_actions.BAD_OPERATION;
end if;
DELETE FROM employee WHERE SSN = pSSN;
END fire_Employee;
369
PL/SQL Packages
PROCEDURE hire_employee (
pFNAME VARCHAR2
,pMINIT VARCHAR2
,pLNAME VARCHAR2
,pSSN VARCHAR2
,pBDATE DATE
,pADDRESS VARCHAR2
,pSEX VARCHAR2
,pSALARY NUMBER
,pSUPERSSN VARCHAR2
,pDNO NUMBER
) IS
BEGIN
--Here you add logic to validate the data and make sure
--no business rules are violated
INSERT INTO employee VALUES (
pFNAME ,pMINIT ,pLNAME ,pSSN ,pBDATE ,pADDRESS
,pSEX ,pSALARY ,pSUPERSSN ,pDNO
);
EXCEPTION
When others then
raise emp_actions.BAD_OPERATION;
END hire_employee;
END emp_actions;
370
PL/SQL Packages
Testing the package (assume you are CSUperson/euclid)
1. CSUPERSON SQL> grant execute on emp_actions to scott;
2. Connect scott/tiger
3. Scott SQL> select * from csuPerson.employee;
… insuficient priviledges
4. SCOTT SQL> exec csuperson.emp_actions.fire_employee(123);
BEGIN csuperson.emp_actions.fire_employee(123); END;
ERROR at line 1:
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at "CSUPERSON.EMP_ACTIONS", line 17
ORA-06512: at line 1
5.
SCOTT SQL> var X number;
6.
SCOTT SQL> exec :x := emp_actions.myPi;
7.
SCOTT SQL> print x;
8.
X
9.
-----------10.
3.1415
371
PL/SQL Programming
TRIGGERS
372
PL/SQL Triggers
•
Triggers are SERVER SIDE stored blocks of code that execute -or fire- automatically when
some database events occur.
•
Triggers are similar to parameter-less procedures, however they can not be called directly.
•
Triggers can NOT (call code or) include the COMMIT / ROLLBACK statements.
•
Traditionally triggers are associated to maintenance of database tables and are invoked by the
run-time Oracle processes on DELETE, UPDATE, INSERT operations.
•
User Event Triggers could fire on non-maintenance events such as: startup, shutdown,
create, alter, drop, grant, revoke, ... operations.
•
In general, triggers appear to execute quietly without the user even knowing of their existence.
373
PL/SQL Triggers. Example
Insert into works_on(Essn,Pno, Hours) values (123456789, 10, 40);
WORKS_ON table
ESSN
PNO
HOURS
--------- ---------- ---------123456789
1
32.5
123456789
2
7.5
666884444
3
40
453453453
1
20
453453453
2
20
333445555
2
10
333445555
3
10
333445555
10
10
333445555
20
10
999887777
30
30
999887777
10
10
987987987
10
35
987987987
30
5
987654321
30
20
987654321
20
15
888665555
20
0
TRIGGER T008B
BEFORE INSERT OR UPDATE OR DELETE ON WORKS_ON
FOR EACH ROW
. . .
. . .
TRIGGER T008A
BEFORE INSERT OR UPDATE OR DELETE ON WORKS_ON
BEGIN
--Employees can not work more than 40 hours/week
. . .
. . .
END;
ERROR at line 1:
ORA-20008: T008A - Excessive work load violation (PK_WORKS_ON)
Employee 123456789, Project 10, Hours 4. Operation rejected.
ORA-04088: error during execution of trigger 'CSUPERSON.T008A'
374
PL/SQL Triggers
Uses of triggers
•
•
•
•
•
•
Provide sophisticated auditing / logging
Prevent invalid transactions
Enforce referential integrity
Enforce data integrity
Enforce complex business rules
Enforce complex security authorizations
375
PL/SQL Triggers
Consulting Database Dictionary
desc user_triggers;
select trigger_name
from user_triggers
where table_name='WORKS_ON';
Enable / Disable
Alter trigger T001 enable;
Alter trigger T001 disable;
ALTER TABLE Employee ENABLE ALL TRIGGERS;
ALTER TABLE Employee DISABLE ALL TRIGGERS;
DROP TRIGER triggerName;
376
PL/SQL Triggers
Abbreviated Trigger syntax
Create or replace
trigger triggerName
{ before | after | instead of } eventClause
on [ schema | database ]
[ referencing new … old ]
[ for each row
]
[ when condition ]
PL/SQL block | call_procedure_statement
377
PL/SQL Triggers
Row Triggers and Statement Triggers
When you define a trigger, you can specify
the number of times the trigger action is to
be run:
• Once for every row affected by the triggering
statement, such as a trigger fired by an UPDATE
statement that updates many rows
• Once for the triggering statement, no matter
how many rows it affects.
378
PL/SQL Triggers
Statement Triggers
A statement trigger is fired once on behalf of the triggering
statement (regardless of the number of rows in the table that the
triggering statement affects, even if no rows are affected).
For example, if a DELETE statement deletes several rows from a
table, a statement-level DELETE trigger is fired only once.
Statement triggers are useful if the code in the trigger action does not
depend on the data provided by the triggering statement or the rows
affected. For example, use a statement trigger to:
– Make a complex security check on the current time or user
– Generate a single audit record.
379
PL/SQL Triggers
Row Triggers
A row trigger is fired each time the table is affected by
the triggering statement.
For example, if an UPDATE statement modifies
multiple rows of a table, a row trigger is fired once for
each row affected by the UPDATE statement.
– If a triggering statement affects no rows, a row trigger is not
run.
– Row triggers are useful if the code in the trigger action depends
on data provided by the triggering statement or rows that are
affected (New: Old: data).
380
PL/SQL Triggers
TRIGGER "CSUPERSON"."T4S"
AFTER UPDATE ON "CSUPERSON"."PROJECT"
BEGIN
dbms_output.put_line ('Greetings from T4S your humble STATEMENT LEVEL trigger');
END;
TRIGGER "CSUPERSON"."T4ROW"
AFTER UPDATE ON "CSUPERSON"."PROJECT"
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
BEGIN
dbms_output.put_line ('Greetings from T4ROW your useful ROW LEVEL trigger');
END;
CSUPERSON SQL>update
PROJECT set pname=pname;
Greetings from T4ROW your useful ROW LEVEL trigger
Greetings from T4ROW your useful ROW LEVEL trigger
Greetings from T4ROW your useful ROW LEVEL trigger
Greetings from T4ROW your useful ROW LEVEL trigger
Greetings from T4ROW your useful ROW LEVEL trigger
Greetings from T4ROW your useful ROW LEVEL trigger
Greetings from T4S your humble STATEMENT LEVEL trigger
381
PL/SQL Triggers
BEFORE Triggers
BEFORE triggers run the trigger action before the triggering statement is
run. This type of trigger is commonly used in the following situations:
– When the trigger action determines whether the triggering statement should
be allowed to complete. Using a BEFORE trigger for this purpose, you can
eliminate unnecessary processing of the triggering statement and its eventual
rollback in cases where an exception is raised in the trigger action.
– To derive specific column values before completing a triggering INSERT or
UPDATE statement.
AFTER Triggers
AFTER triggers run the trigger action after the triggering statement is run.
382
PL/SQL Before-After Triggers
TRIGGER T007A BEFORE INSERT OR UPDATE
DECLARE
oldSalary NUMBER;
BEGIN
select sum(salary) into oldSalary
insert into MYLOG values (sysdate
'Before Salary:
END;
OR DELETE ON EMPLOYEE
from employee;
|| ' ' || user,
' || oldsalary);
TRIGGER T007B AFTER INSERT OR UPDATE OR DELETE ON EMPLOYEE
DECLARE
newSalary NUMBER;
BEGIN
select sum(salary) into newSalary from employee;
insert into MYLOG values ( sysdate || ' ' || user,
'After Salary: ' || newsalary);
END;
383
PL/SQL Before-After Triggers
CSUPERSON SQL>select sum(salary) from employee;
SUM(SALARY)
----------281000
1 row selected.
CSUPERSON SQL>update employee set salary=salary+100000 where ssn=123456789;
1 row updated.
CSUPERSON SQL>select * from mylog;
C1
-------------------------------------------------04-OCT-06 CSUPERSON
04-OCT-06 CSUPERSON
C2
-------------------------Before Salary: 281000
After Salary: 381000
384
PL/SQL Triggers – Row Level
Example:
--Business Rule 1: Job assignments to project 10 must be between 4 & 6 hours.
TRIGGER CSUPERSON.T001
BEFORE INSERT OR UPDATE OF hours ON CSUPERSON.WORKS_ON
REFERENCING OLD AS OLD_VALUE NEW AS NEW_VALUE
FOR EACH ROW
WHEN (new_value.pno = 10)
BEGIN
if :new_value.hours >= 6 or
:new_value.hours <= 4 then
raise_application_error
(-20001,
'Proj. 10 load must be between 4-6 hours/week'
);
end if;
END;
385
PL/SQL Triggers
Testing T001
Add employee 1 to project 10 for a total of 9 hours/week.
CSUPERSON SQL> insert into works_on values (1,10,9);
insert into works_on values (1,10,9)
*
ERROR at line 1:
ORA-20001: Proj. 10 load must be between 4-6 hours/week
ORA-06512: at "CSUPERSON.T001", line 4
ORA-04088: error during execution of trigger 'CSUPERSON.T001'
create table myLog (C1 varchar2(40), C2 varchar2(40) );
386
PL/SQL Triggers
Observation
Firing trigger on a particular column
BEFORE INSERT OR UPDATE OF hours ON CSUPERSON.WORKS_ON
Aliasing :NEW :OLD
REFERENCING OLD AS OLD_VALUE NEW AS NEW_VALUE
Note: Goal of [optional] referencing clause is improving readability
‘NEW’ could be referenced as: Nuevo, Kotha, Novo, Nouveau, Neu, …
‘OLD’ could be referenced as: Viejo, Patha, Velho, Vieux, Alt, …
387
PL/SQL Triggers
EXAMPLE 2
• The following trigger is fired when a new
dependent record is inserted.
• If the record corresponds to a new born child ( < 1 year)
several gifts are ordered for the baby.
• If the new entry is not related to an existing employee the
insertion is rejected (referential integrity).
• Assume there is a logging table MYLOG(c1,c2)
388
PL/SQL Triggers
TRIGGER T002
BEFORE INSERT on Dependent
FOR EACH ROW
DECLARE
mName
varchar(20):= NULL;
BEGIN
select Lname into mName
from employee
where ssn = :new.Essn;
if (months_between(sysdate,:new.Bdate) < 12 ) then
insert into Mylog values (sysdate || ' Personnel Dept-->',
'Send NEW_BABY greeting card to '|| mName);
insert into Mylog values (sysdate || ' Marketing Dept.-->',
'Mail $100 company stock to '|| mName);
insert into mylog values (sysdate || ' Purchasing Dpt.-->',
'Order one-year diapers for '|| mName);
end if;
EXCEPTION
when others then
raise_application_error(-20002,'Dependent problem: ' || :new.essn );
END;
389
PL/SQL Triggers
Testing T002
-- Anonymous block to test T002
DECLARE
BEGIN
-- Intentionally done! this insertion will be rejected
BEGIN
insert into dependent values
(777000777, 'Angel' , 'M', '03-SEP-96','Son' );
EXCEPTION
when others then
dbms_output.put_line (sqlErrm );
END;
-- This second insertion is valid and will be accepted
-- all the gifts will be ordered for the new baby (change bdate!).
BEGIN
insert into dependent values
(123456789, 'Jose', 'M', SYSDATE + 30, 'Son' );
END;
-- This third insertion is valid and will be accepted
-- not a baby.
BEGIN
insert into dependent values
(123456789, 'Joe', 'M', '04-JUL-2001', 'Son' );
END;
END;
390
PL/SQL Triggers
Testing T002
ORA-20002: Dependent problem: 777000777
ORA-06512: at "CSUPERSON.T002", line 24
ORA-04088: error during execution of
trigger 'CSUPERSON.T002'
MYLOG
F1
--------------------------------------15-FEB-05 Personnel Dept-->
15-FEB-05 Marketing Dept.-->
15-FEB-05 Purchasing Dpt.-->
F2
--------------------------------------Send NEW_BABY greeting card to Smith
Mail $100 company stock to Smith
Order one-year diapers for Smith
DEPENDENT
ESSN
--------333445555
333445555
333445555
987654321
123456789
123456789
123456789
123456789
123456789
DEPENDENT_
---------Alice
Theodore
Joy
Abner
Michael
Alice
Elizabeth
Jose
Joe
S
F
M
F
M
M
F
F
M
M
BDATE
--------05-APR-76
02-OCT-73
03-MAY-48
29-FEB-32
01-JAN-78
31-DEC-78
05-MAY-57
01-JAN-05
04-JUL-01
RELATIONSH
---------Daughter
Son
Spouse
Spouse
Son
Daughter
Spouse
Son
Son
391
PL/SQL Triggers
Your turn → How to enforce
REFERENTIAL INTEGRITY?
Try a ROW LEVEL trigger fixing the
CASCADE/NULLIFY/MANDATORY
retention modes of EMPLOYEE and
DEPENDENT.
Extend the results for dealing with job
assignments and other meaningful
relationships in the database.
392
PL/SQL Triggers
Your turn → How to enforce REFERENTIAL INTEGRITY?
A typical way of defining referential integrity using DDL is given below
ALTER TABLE table_name
ADD CONSTRAINT constraint_name
FOREIGN KEY (col1, col2) REFERENCES table_2 (cola,colb);
To enforce/ignore the constraint we may use the statements
ALTER TABLE table-name DISABLE constraint-specification;
ALTER TABLE table-name ENABLE constraint-specification;
You may choose to enforce referential integrity using a trigger. For instance
DEPENDENT.ESSN → EMPLOYEE.SSN
could be implemented as follows
393
PL/SQL Triggers
Your turn → How to enforce REFERENTIAL INTEGRITY?
--enforcing the rule:
DEPENDENT.ESSN → EMPLOYEE.SSN
TRIGGER T007C BEFORE INSERT ON DEPENDENT
FOR EACH ROW
DECLARE
empCounter number;
BEGIN
-- is there a PARENT employee with the given Soc. Sec. Numb. ?
select count(*) into empCounter from employee where ssn = :new.essn;
-- if not, throw an EXCEPTION
if empCounter = 0 then
raise_application_error ('20004',
'REF. INTEGRITY VIOLATION ' || :new.essn);
end if;
END;
394
PL/SQL Statement-Level Triggers
Example: Tracking the salary gap between male and female employees
TRIGGER "CSUPERSON"."T007"
AFTER INSERT or UPDATE ON "CSUPERSON"."EMPLOYEE"
DECLARE
LadiesSal NUMBER;
GentSal
NUMBER;
BEGIN
select avg(salary) into LadiesSal from employee where sex = 'F';
select avg(salary) into GentSal
from employee where sex = 'M';
If (GentSal - LadiesSal) > 10000 then
insert into myLOG values (
'WARNING',
'Salary gap between ladies and gentlemen exceeds $10K');
end if;
END;
395
PL/SQL Triggers
Example: Statement Level trigger.
Execute only once for the entire statement ( rather than on a row-by-row basis ).
TRIGGER "CSUPERSON"."T003"
BEFORE INSERT OR UPDATE OR DELETE ON "CSUPERSON"."WORKS_ON"
BEGIN
-- RULE: Only CSUPERSON is allowed to change the works_on table
if user != 'CSUPERSON' then
raise_application_error(-20004,
'T003. You are not authorized to make changes on Works_On'
);
end if;
-- RULE: changes to WORKS_ON are accepted only from Mon-Fri between
-- working hours 8:00 AM. and 6:00 PM. Reject otherwise.
if (to_char(sysdate,'HH24:MI') not between '08:00' and '18:00' )
or
(to_char(sysdate,'DY') in ('SAT', 'SUN') )
then
raise_application_error(-20005,
'T003. Changes are only accepted during normal office hours'
);
end if;
END;
396
PL/SQL Triggers
Tell me more! What is going on?
You may use the following predicates to
exactly determine what is happening in the
trigger’s code:
• if INSERTING then …
• if DELETING then …
• if UPDATING then …
397
PL/SQL Triggers
T004. Testing the action Predicates.
TRIGGER "CSUPERSON"."T004"
BEFORE INSERT OR UPDATE OR DELETE ON "CSUPERSON"."PROJECT"
FOR EACH ROW
BEGIN
--tell us what is going on during the execution of the trigger
/*************************************************************
INSERTING (only :NEW data exists for the record)
*************************************************************/
if INSERTING then
dbms_output.put_line ('Inserting a new Project ');
dbms_output.put_line (:NEW.Pname || '-' || :NEW.Pnumber|| '-' ||
:NEW.Plocation || '-' || :NEW.Dnum);
return;
end if;
/*************************************************************
DELETING (there is no :NEW image - ask only for :OLD)
*************************************************************/
if DELETING then
dbms_output.put_line ('Deleting an old Project ');
dbms_output.put_line (:OLD.Pname || '-' || :OLD.Pnumber|| '-' ||
:OLD.Plocation || '-' || :OLD.Dnum);
return;
end if;
398
PL/SQL Triggers
/********************************************************************
UPDATING (there are :NEW and :OLD images for the record
*********************************************************************/
if UPDATING then
-- do we have a new project name ?
if (:NEW.Pname != :OLD.Pname ) then
dbms_output.put_line ('Updating PNAME of an old Project ');
dbms_output.put_line (:NEW.Pname || '-' || :NEW.Pnumber|| '-' ||
:NEW.Plocation || '-' || :NEW.Dnum);
dbms_output.put_line ('Old Pname: ' || :OLD.Pname );
end if;
-- do we have a new project location?
if (:NEW.Plocation != :OLD.Plocation ) then
dbms_output.put_line ('Updating PLOCATION of an old Project ');
dbms_output.put_line (:NEW.Pname || '-' || :NEW.Pnumber|| '-' ||
:NEW.Plocation || '-' || :NEW.Dnum);
dbms_output.put_line ('Old Plocation: ' || :OLD.Plocation );
end if;
--do we have a new controlling department?
if (:NEW.Dnum != :OLD.Dnum ) then
dbms_output.put_line ('Updating DNUM of an old Project ');
dbms_output.put_line (:NEW.Pname || '-' || :NEW.Pnumber|| '-' ||
:NEW.Plocation || '-' || :NEW.Dnum);
dbms_output.put_line ('Old DNUM: ' || :OLD.Dnum );
end if;
end if; -- updating
END;
399
PL/SQL Triggers
1. Testing triggering predicates
PROJECT Table
PNAME
PNUMBER PLOCATION
DNUM
----------------- ---------- ---------- ---------ProductX
1 Bellaire
5
ProductY
2 Sugarland
5
ProductZ
3 Houston
5
Computerization
10 Stafford
4
Reorganization
20 Houston
1
Newbenefits
30 Stafford
4
SQL> insert into project values ('XYZ', 40, 'Cleveland', 4);
Inserting a new Project
XYZ-40-Cleveland-4
1 row created.
CSUPERSON SQL> select * from project;
PNAME
PNUMBER PLOCATION
DNUM
----------------- ---------- ---------- ---------ProductX
1 Bellaire
5
ProductY
2 Sugarland
5
ProductZ
3 Houston
5
Computerization
10 Stafford
4
Reorganization
20 Houston
1
Newbenefits
30 Stafford
4
XYZ
40 Cleveland
4
400
PL/SQL Triggers
2. Testing triggering predicates
SQL> update project set pname='Rock and Roll', Dnum=1 where pnumber=40;
Updating PNAME of an old Project
Rock and Roll-40-Cleveland-1
Old Pname: XYZ
Updating DNUM of an old Project
Rock and Roll-40-Cleveland-1
Old DNUM: 4
1 row updated.
PROJEC table
PROJEC table
PNAME
PNUMBER PLOCATION
DNUM
----------------- ---------- ---------- ---------ProductX
1 Bellaire
5
ProductY
2 Sugarland
5
ProductZ
3 Houston
5
Computerization
10 Stafford
4
Reorganization
20 Houston
1
Newbenefits
30 Stafford
4
XYZ
40 Cleveland
4
PNAME
PNUMBER PLOCATION
DNUM
----------------- ---------- ---------- ---------ProductX
1 Bellaire
5
ProductY
2 Sugarland
5
ProductZ
3 Houston
5
Computerization
10 Stafford
4
Reorganization
20 Houston
1
Newbenefits
30 Stafford
4
Rock and Roll
40 Cleveland
1
401
PL/SQL Triggers
MUTATING TABLES
402
PL/SQL Triggers
MUTATING TABLES
• Oracle enforces a reading of data that guarantees logical consistency.
• The mutation error is encountered when a row-level trigger
accesses the same (changing, unfinished, transient) table on
which it is based.
• Mutation will not occur if a single record is inserted in the table (using
VALUES clause).
• If bulk insertion is done or data is inserted from another table mutation
will occur.
• STATEMENT LEVEL triggers are immune to mutating tables.
403
PL/SQL Triggers
MUTATING Tables
• Mutating table exceptions occur when we try to reference the triggering
table in a query from within row-level trigger code.
• A mutating table is a relation that is being modified by an UPDATE,
DELETE, or INSERT statement, or
• A table that might be updated by the effects of a DELETE CASCADE
constraint.
Consequences

– The session that issued the triggering statement cannot query or modify a
mutating table.
– This restriction prevents a trigger from seeing an inconsistent set of
data.
– This restriction applies to all triggers that use the FOR EACH ROW
clause.
404
PL/SQL Triggers
Example: Limit assignments to a max of 4.
TRIGGER "CSUPERSON"."T007"
BEFORE INSERT OR UPDATE OR DELETE ON "CSUPERSON"."WORKS_ON"
FOR EACH ROW
DECLARE
myCounter Number;
BEGIN
-- count on how many projects the employee is currently working.
select count(*) into myCounter from works_on where essn = :NEW.essn;
-- if four or more reject operation raising error condition 20007
if myCounter >= 4 then
raise_application_error (-20007,
'Excessive work load violation ' ||'Employee: ' || :new.essn );
end if;
END;
NOTE:
In this example Delete & Update will run into mutating-table conflict, however a single Insert will not.
405
PL/SQL Triggers
Example: Limit assignments to a max of 4.
CSUperson SQL> update works_on set Hours = hours;
update works_on set Hours = hours
*
ERROR at line 1:
ORA-04091: table CSUPERSON.WORKS_ON is mutating, trigger/function
may not see it
bb
ORA-06512:
at "CSUPERSON.T007", line 5
ORA-04088: error during execution of trigger 'CSUPERSON.T007'
CSUPERSON SQL>insert into works_on values (333445555,7,1);
insert into works_on values (333445555,7,1)
*
ERROR at line 1:
ORA-20007: Excessive work load violation Employee: 333445555
ORA-06512: at "CSUPERSON.T007", line 9
ORA-04088: error during execution of trigger 'CSUPERSON.T007'
NOTE: In this example Delete & Update will run into mutating-table conflict, however a single Insert will not.
406
PL/SQL Triggers
Example: Limit assignments to a max of 4.
CSUPERSON SQL> insert into works_on select * from works_on;
insert into works_on select * from works_on
*
ERROR at line 1:
ORA-04091: table CSUPERSON.WORKS_ON is mutating, trigger/function
may not see it
ORA-06512: at "CSUPERSON.T007", line 5
ORA-04088: error during execution of trigger 'CSUPERSON.T007‘
NOTE:
The INSERT operation finds each new records has already a previous image having the same
primary key and concludes they are OLD versions of the new data, therefore the table itself is
mutating.
407
PL/SQL Triggers
Example: Limit assignments to a max of 4.
• Assign ladies to new project 77 for 1 hour/week
SQL> insert
into works_on
select ssn, 77, 1 from employee where sex = ‘F’;
insert into works_on
*
ERROR at line 1:
ORA-04091: table CSUPERSON.WORKS_ON is mutating, trigger/function
may not see it
ORA-06512: at "CSUPERSON.T007", line 5
ORA-04088: error during execution of trigger 'CSUPERSON.T007‘
NOTE:
The INSERT operation finds each new records has already a previous image having the same
primary key and concludes they are OLD versions of the new data, therefore the table itself is
mutating.
408
PL/SQL Triggers
Dealing with mutating tables
Order of DML trigger execution
1.
BEFORE STATEMENT_LEVEL, if present (could include cursors,
select, and maintenance SQL statements on any table).
2.
For each ROW LEVEL trigger linked to the table
1.
2.
3.
3.
Run BEFORE ROW LEVEL, if present.
Execute the statement (insert/delete/update).
Run AFTER ROW LEVEL, if present.
AFTER STATEMENT_LEVEL, if present (could include cursors,
select, and maintenance SQL statements on any table).
NOTE:
On Step2; SQL select and maintenance statements raise mutating table exception.
409
PL/SQL Triggers
Dealing with mutating tables
A common technique for solving the mutating table
problem consists on writing two triggers around the –
otherwise- mutating table.
1.
Write a BEFORE statement-level trigger, saving in (a) DB
tables, or (b) memory table(s) -defined in a package- the
relevant data needed by the forthcoming row-level triggers.
2.
Write a ROW LEVEL trigger that gets access to the :NEW
rows and the data saved in table(s) by the previously executed
statement-level trigger.
3.
If needed, conclude with an AFTER statement-level trigger.
410
PL/SQL Triggers
Example
Use triggers to enforce the following rules
1. Employees can not work on more than 4 projects.
2. Employees can not work more than 40 hours/week.
411
PL/SQL Triggers
Example. Avoiding Mutating Tables
Rules to be enforced
1.
Employees can not work on more than 4 projects.
2.
Employees can not work more than 40 hours/week.
2.
1.
Trigger-B
Trigger-A
Before Row-Level Trigger
Before Statement Trigger
For demonstration purposes
Uses a cursor to reach
WORKS_ON records and
summarize data in memory
table: EMPLOAD
Displays memory table.
3.
MEMORY TABLE
SSN
PROJ HOURS
T008A 1 123456789 2 40
T008A 2 333445555 4 40
T008A 3 453453453 2 40
T008A 4 666884444 1 40
T008A 5 888665555 1 0
T008A 6 987654321 2 35
T008A 7 987987987 2 40
T008A 8 999887777 2 40
Trigger-C
Before Row-Level Trigger
Uses memory table
EMPLOAD, as well as
:OLD and :NEW images.
Raises EXCEPTIONS.
ORACLE database
412
PL/SQL Triggers
Supporting PACKAGE
PACKAGE "MYTRIGGERAID" AS
TYPE
EmpLoadT IS RECORD(
EmpSSN
varchar2(9),
EmpProjectCount number,
EmpHoursCount
number
);
TYPE EmpLoadArrayT
IS TABLE OF EmpLoadT
INDEX BY BINARY_INTEGER;
EmpLoad
EmpLoadArrayT;
EmpLoadSize number;
END;
413
PL/SQL Triggers
-- T008A. STATEMENT LEVEL TRIGGER
TRIGGER "CSUPERSON"."T008A"
BEFORE INSERT OR UPDATE OR DELETE ON "CSUPERSON"."WORKS_ON"
DECLARE
i number:= 0;
BEGIN
-- DEMO/TESTING: (remove printing-code later!!!)
-- Fill up the array "EmpLoad" defined in the utility package
-- "myTriggerAid" with a list of records, each of the form
-<essn, countProjects, sumHours>
-- this data will be used by other ROW-LEVEL triggers
myTriggerAid.EmpLoadSize := 0;
for w in (select essn,
count(*)
as totalProjects,
sum(hours) as totalHours
from works_on
group by essn) loop
i := i + 1;
myTriggerAid.EmpLoad(i).EmpSSN := w.essn;
myTriggerAid.EmpLoad(i).EmpProjectCount := w.TotalProjects;
myTriggerAid.EmpLoad(i).EmpHoursCount
:= w.TotalHours;
dbms_output.put_line('T008A ' || i || ' ' ||
w.essn || ' ' || w.totalProjects || ' ' ||
w.totalHours );
end loop;
myTriggerAid.EmpLoadSize := i;
dbms_output.put_line(' ------------------------------------- ');
END;
414
PL/SQL Triggers
-- (Testing Purposes) ROW LEVEL trigger.
TRIGGER "CSUPERSON"."T008B"
BEFORE INSERT OR UPDATE OR DELETE ON "CSUPERSON"."WORKS_ON"
FOR EACH ROW
DECLARE
w
myTriggerAid.EmpLoadT;
i
number;
n
number := myTriggerAid.EMpLoadSize;
keyESSN integer;
BEGIN
-- T008B is used here only for demonstration purposes (drop it later!).
-- The T008B trigger uses an "indexed-by" table and variables created by a
-- BEFORE statement-level (T008A) that also fires on this table.
-- Each entry in the table contains <ESSN,CountProjects,SumHours>
-- The table is sequentially scanned looking for data in the array associated
-- to the current :NEW record. Try a better search (perhaps binary, hashing…)
if deleting then
keyESSN := :old.ESSN;
else
keyESSN := :new.ESSN;
end if;
for i in 1..myTriggerAid.EmpLoadSize loop
w.EmpSSN := myTriggerAid.EmpLoad(i).EmpSSN;
w.EmpProjectCount := myTriggerAid.EmpLoad(i).EmpProjectCount;
w.EmpHoursCount
:= myTriggerAid.EmpLoad(i).EmpHoursCount;
if (keyESSN = myTriggerAid.EmpLoad(i).EmpSSN) then
dbms_output.put_line('T008B ' || i || ' ' ||
w.EmpSSN || ' ' || w.EmpProjectCount || ' ' ||
w.EmpHoursCount );
end if;
end loop;
END;
415
PL/SQL Triggers
CSUPERSON SQL> update works_on set hours=hours;
T008A 1 123456789 2 40
T008A 2 333445555 4 40
T008A 3 453453453 2 40
T008A 4 666884444 1 40
T008A 5 888665555 1 0
T008A 6 987654321 2 35
T008A 7 987987987 2 40
T008A 8 999887777 2 40
------------------------------------T008B 1 123456789 2 40
T008B 1 123456789 2 40
T008B 4 666884444 1 40
T008B 3 453453453 2 40
T008B 3 453453453 2 40
T008B 2 333445555 4 40
T008B 2 333445555 4 40
T008B 2 333445555 4 40
T008B 2 333445555 4 40
T008B 8 999887777 2 40
T008B 8 999887777 2 40
T008B 7 987987987 2 40
T008B 7 987987987 2 40
T008B 6 987654321 2 35
T008B 6 987654321 2 35
T008B 5 888665555 1 0
Written by T008A
BEFORE level statement
Written by T008B
FOR EACH ROW level
416
PL/SQL Triggers
Part2: ROW-Level Trigger.
-- T008C. Enforcing rule 40hours/week max.
TRIGGER "CSUPERSON"."T008C"
BEFORE INSERT OR UPDATE OR DELETE ON "CSUPERSON"."WORKS_ON"
FOR EACH ROW
DECLARE
w
i
myPos
myValue
keyESSN
myTriggerAid.EmpLoadT;
number;
number;
number;
integer;
-- <EmpSSN, EmpProjectCount, EmpHoursCount>
-- index for the table
-- search index, -1 if not found
-- ESSN coming from the OLD or NEW rec.
BEGIN
-------------
The T008C trigger uses an "indexed-by" table and variables created by a
BEFORE statement-level (T008A) that also fires on this table.
Each entry in the table contains <ESSN,CountProjects,SumHours>
The table is sequentially scanned looking for data in the array associated
to the current :NEW record.
EXCEPTIONS TO BE CONSIDERED
Condition -20007 will be raised if the employee already works on 4 projects.
Condition -20008 will be raised if the employee is placed on 40+ hours/week.
OBSERVATION
if the SQL statement is a DELETE or UPDATE and it finds no matching record
in the WORKS_ON database, this trigger is not executed. Please notice there
is no image for the :OLD record.
417
PL/SQL Triggers
/***************************************************************************
PREAMBLE: Get ready to FIND
(myPos -1 signals not found)
****************************************************************************/
-- a location value of -1 indicates not found (not really possible!)
myPos := -1;
-- key (ESSN) comes from either :NEW or :OLD record’s image
if deleting then
keyESSN := :old.ESSN;
else
keyESSN := :new.ESSN;
end if;
-- scan sequentially the memory list looking for a key match
for i in 1..myTriggerAid.EmpLoadSize loop
if (keyESSN = myTriggerAid.EmpLoad(i).EmpSSN) then
w.EmpSSN := myTriggerAid.EmpLoad(i).EmpSSN;
w.EmpProjectCount := myTriggerAid.EmpLoad(i).EmpProjectCount;
w.EmpHoursCount
:= myTriggerAid.EmpLoad(i).EmpHoursCount;
myPos := i;
exit; --consider using a modified Binary search (faster?)
end if;
end loop;
--remember the position in the table in which employee rec. was found
i:= myPos;
418
PL/SQL Triggers
--display these lines only for demonstration purpose
dbms_output.put_line('New record (ESSN,PNO,HOURS):
:new.eSSN || ', ' ||
:new.pno || ', ' ||
:new.hours);
dbms_output.put_line('Old record (ESSN,PNO,HOURS):
:old.eSSN || ', ' ||
:old.pno || ', ' ||
:old.hours);
' ||
' ||
dbms_output.put_line('Loc: ' || i ||
' Contains (SSN, ProjectCount, TotalHours):
w.EmpSSN
|| ', ' ||
W.EmpProjectCount || ', ' ||
W.EmpHoursCount);
' ||
419
PL/SQL Triggers
/******************************************************************
get ready to DELETE.
******************************************************************/
if deleting then
dbms_output.put_line('Deleting ---');
-- update memory table EmpLoad (less assignments & hours).
myTriggerAid.EmpLoad(i).EmpProjectCount :=
myTriggerAid.EmpLoad(i).EmpProjectCount - 1;
myTriggerAid.EmpLoad(i).EmpHoursCount :=
myTriggerAid.EmpLoad(i).EmpHoursCount - :old.Hours;
end if; --deleting
420
PL/SQL Triggers
/******************************************************************
get ready to UPDATE an existing record.
******************************************************************/
if updating then
dbms_output.put_line('updating ---');
--adjust sum of hours
myValue := myTriggerAid.EmpLoad(i).EmpHoursCount +
:new.Hours - :old.hours;
if myValue > 40 then
--if more than 40 hour/week raise the exception
raise_application_error(-20007,
'Error. More than 40 hours/week');
end if;
-- OK. update memory table EmpLoad using
-- the current modification of hours
myTriggerAid.EmpLoad(i).EmpHoursCount := myValue;
end if; --updating
421
PL/SQL Triggers
/******************************************************************
get ready to INSERT.
Caution! this could be the FIRST record.
******************************************************************/
if myPos = -1 then
-- New person.
-- This is the first entry for this emp in the table.
-- make room in the table for a new entry
myTriggerAid.EmpLoadSize := myTriggerAid.EmpLoadSize + 1;
i := myTriggerAid.EmpLoadSize;
myTriggerAid.EmpLoad(i).EmpSSN := :new.Essn;
myTriggerAid.EmpLoad(i).EmpHoursCount := 0;
myTriggerAid.EmpLoad(i).EmpProjectCount := 0;
myValue := :new.Hours;
else
--this employee has already received some assignments
myValue := myTriggerAid.EmpLoad(i).EmpHoursCount + :new.Hours;
end if; --testing if this is the FIRST time in the table
422
PL/SQL Triggers
if inserting then
dbms_output.put_line('Inserting ---');
-- make sure we do not exceed 40 hour/week
--(TODO: Check too many assignments !!!)
if myValue > 40 then
raise_application_error(-20007,
'Error. More than 40 hours/week');
end if;
-- OK. update memory table EmpLoad.
-- Modify the existing emp. cell with NEW data.
myTriggerAid.EmpLoad(i).EmpHoursCount := myValue;
if myPos = -1 then
--this is the first entry for the employee
myTriggerAid.EmpLoad(i).EmpProjectCount := 1;
else
--the employee had already some assignments
myTriggerAid.EmpLoad(i).EmpProjectCount :=
myTriggerAid.EmpLoad(i).EmpProjectCount + 1;
end if; -- fixing the FIRST entry for this employee
end if;
END;
-- inserting
423
PL/SQL Triggers
1. Testing: T008A and T008C on 40 hours/week rule.
WORKS_ON table
ESSN
PNO
HOURS
--------- ---------- ---------123456789
1
31.5
123456789
2
7.5
666884444
3
40
453453453
1
20
453453453
2
20
333445555
2
10
333445555
3
10
333445555
10
10
333445555
20
10
999887777
30
30
999887777
10
10
987987987
10
35
987987987
30
5
987654321
30
20
987654321
20
15
888665555
20
0
SQL>
update works_on set hours= hours+1 where essn=123456789;
T008A 1 333445555 4 40
T008A 2 987987987 2 40
T008A 3 123456789 2 40
T008A 4 666884444 1 40
T008A 5 987654321 2 35
T008A 6 453453453 2 40
T008A 7 888665555 1 0
T008A 8 999887777 2 40
------------------------------------New record (ESSN,PNO,HOURS):
Old record (ESSN,PNO,HOURS):
Written by T008A
BEFORE statement level trigger
T008C finds a possible change from
32.5 to 33.5 hours on project 1
123456789, 1, 33.5
123456789, 1, 32.5
Loc: 3 Contains (SSN, ProjectCount, TotalHours):
123456789 already
works 40 hours/week
123456789, 2, 40
updating --update works_on set hours = hours+1 where essn = 123456789
ERROR at line 1:
The UPDATE operation
fails. Trigger T008C throws
an Excepttion
ORA-20007: Error. More than 40 hours/week
ORA-06512: at "CSUPERSON.T008C", line 85
ORA-04088: error during execution of trigger 'CSUPERSON.T008C‘
424
PL/SQL Triggers
2. Testing: T008A and T008C on 40 hours/week rule.
WORKS_ON table
ESSN
PNO
HOURS
--------- ---------- ---------123456789
1
31.5
123456789
2
7.5
666884444
3
40
453453453
1
20
453453453
2
20
333445555
2
10
333445555
3
10
333445555
10
10
333445555
20
10
999887777
30
30
999887777
10
10
987987987
10
35
987987987
30
5
987654321
30
20
987654321
20
15
888665555
20
0
The INSERT operation succeeds.
(Note: on this example we do not
check Foreign – Primary key
constraints)
SQL> insert into works_on values (777777777, 1, 40);
T008A 1 333445555 4 40
Written by T008A
T008A 2 987987987 2 40
BEFORE statement level trigger
T008A 3 123456789 2 40
T008A 4 666884444 1 40
T008C finds that 777777777
T008A 5 987654321 2 35
could be inserted.
T008A 6 453453453 2 40
T008A 7 888665555 1 0
(it was not found in the memory
T008A 8 999887777 2 40
table, but was added to it)
------------------------------------New record (ESSN,PNO,HOURS):
777777777, 1, 40
Old record (ESSN,PNO,HOURS):
, ,
Loc: -1 Contains (SSN, ProjectCount, TotalHours):
, ,
Inserting --1 row created.
425
PL/SQL Triggers
3. Testing: T008A and T008C on 40 hours/week rule.
WORKS_ON table
ESSN
PNO
HOURS
--------- ---------- ---------123456789
1
31.5
123456789
2
7.5
666884444
3
40
453453453
1
20
453453453
2
20
333445555
2
10
333445555
3
10
333445555
10
10
333445555
20
10
999887777
30
30
999887777
10
10
987987987
10
35
987987987
30
5
987654321
30
20
987654321
20
15
888665555
20
0
777777777
1
40
The INSERT
operation FAILS
SQL> insert into works_on values (777777777,2,5);
T008A 1 333445555 4 40
T008A 2 987987987 2 40
T008A 3 123456789 2 40
T008A 4 666884444 1 40
T008A 5 987654321 2 35
T008A 6 453453453 2 40
T008A 7 888665555 1 0
T008A 8 777777777 1 40
T008A 9 999887777 2 40
-------------------------------------
Written by T008A
BEFORE statement level trigger
T008C finds the record
777777777 could NOT be
inserted. Emp already works
40 hours/week
New record (ESSN,PNO,HOURS):
777777777, 2, 5
Old record (ESSN,PNO,HOURS):
, ,
Loc: 8 Contains (SSN, ProjectCount, TotalHours):
777777777, 1, 40
Inserting --insert into works_on values (777777777,2,5)
*
ERROR at line 1:
ORA-20007: Error. More than 40 hours/week
ORA-06512: at "CSUPERSON.T008C", line 113
ORA-04088: error during execution of trigger 'CSUPERSON.T008C'
426
PL/SQL Triggers
4. Testing: T008A and T008C on 40 hours/week rule.
WORKS_ON table
ESSN
PNO HOURS
--------- ---------- ---------123456789
1
31.5
123456789
2
7.5
666884444
3
40
453453453
1
20
453453453
2
20
333445555
2
10
333445555
3
10
333445555
10
10
333445555
20
10
999887777
30
30
999887777
10
10
987987987
10
35
987987987
30
5
987654321
30
20
987654321
20
15
888665555
20
0
777777777
1
40
SQL> delete from works_on where essn = 777777777;
T008A 1 123456789 2 39
T008A 2 333445555 4 40
Written by T008A
T008A 3 453453453 2 40
BEFORE statement level trigger
T008A 4 666884444 1 40
T008A 5 777777777 1 40
T008A 6 888665555 1 0
T008A 7 987654321 2 35
T008A 8 987987987 2 40
T008A 9 999887777 2 40
------------------------------------NEW
-T008C finds the rec. 777777777
Found: 5 ** 777777777-1-40
could be delete.
Deleting --1 row deleted.
The DELETE operation
succeeds
427
OLD NOTES
Example of a COMPANY personnel PACKAGE
428
PL/SQL Programming
Invoking a Stored Function from a SQL Query
The numbers in the BaseBall table are hard to read. A function BigBucks()
is called to facilitated the reading of the big numbers in the table
SQL> select * from baseball;
PNAME
PSALARY
-------------------- -----------A. Belle
987654321
K. Griffey
1987654322
B. Bonds
1234567890
D. Cone
123456
P. Butterfingers
900
429
PL/SQL Programming
Invoking a Stored Function from a SQL Query
-- Playball.sql
-- This is a small SCRIPT (not an anonymous proc.)
-- The pretty function is called from the SQL comnd
column psalary format 99999999999
column bigbucks(psalary) format a30
select pname, psalary, BigBucks(psalary)
from baseball;
SQL> @Playball
PNAME
PSALARY BIGBUCKS(PSALARY)
-------------------- ------------ --------------------A. Belle
987654321
987.65 Millions
K. Griffey
1987654322
1.99 Billions
B. Bonds
1234567890
1.23 Billions
D. Cone
123456
123.46 Thousands
P. Butterfingers
900
900.00 Peanuts
430
PL/SQL Programming
A Stored Function for Beautifying Big Numbers
Create or Replace
Function BIGBUCKS ( salary number ) Return varchar
IS
Billion
number := 1000000000;
Million
number :=
1000000;
Thousand number :=
1000;
LPAD( ) adds n spaces on
Message
varchar(30);
on left side of the string
Dollars
number(6,2);
begin
if (salary >= Billion) then
Dollars:= salary / billion;
message:= LPAD(to_char(dollars),8) || ' Billions';
return (message);
elsif (salary >= Million) then
Dollars:= salary / Million;
message:= LPAD(to_char(dollars),8) || ' Millions';
return (message);
elsif (salary >= Thousand) then
Dollars:= salary / Thousand;
message:= LPAD(to_char(dollars),8) || ' Thousands';
return (message);
Numeric format
else
message:= to_char(Salary,'999.00');
message:= LPAD(message,8)||' Peanuts';
return (message);
end if;
end;
431
PL/SQL Programming
Writing a Procedure to Securely Insert Works_On records
The procedure Insert_WorksOn() is invoked to reliably add new records to
the table Works_On. Each call to the function provides the programmers
authentication code and data (SSN, ProjNumb, Hour). For example:
Result:= Insert_WorkOn(‘JB007’,123456789,10,40)
• If the programmer ‘JB007’ is not in the list of people authorized to make insertions,
the operation is rejected and MYLOG file is update with a rejection message
• If the SSN and PNO provided are already in the Works_On table the current insertion
is rejected and the log file is updated
• The function returns a numeric code 1, -1, -2, etc. to indicate the status of the execution.
This number is stored into the variable Result (1: success, negative values: problems).
432
PL/SQL Programming
create or replace
FUNCTION Insert_WorksOn (
Programmer_Id
EmployeeSsn
ProjectNumber
WeeklyHours
number,
number,
number,
number )
RETURN number
IS
Programmer_Name
varchar(20);
Message
varchar(70);
BEGIN
-- First block: Is the programmer allowed to insert records?
-- Note: All code goes into one BEGIN...END block.
BEGIN
select Operator_Name into Programmer_Name
from
Valid_Operators
where Operator_Id = Programmer_Id;
EXCEPTION
when No_Data_Found then
Insert into Mylog values (Programmer_Id,
'ERROR** unauthorized used of function');
RETURN -1;
END;
-- first block
433
PL/SQL Programming
-- INSERTWORKSON cont.
-- Second block: Here other conditions could be checked
-- before accepting record into the works_on table
BEGIN
insert into Works_On values
(EmployeeSsn, ProjectNumber, WeeklyHours);
RETURN 1;
EXCEPTION
When Dup_Val_on_Index then
Message:= ' Emp ' || to_char(EmployeeSsn) ||
' already working in project '
||
to_char(ProjectNumber);
insert into Mylog values (NULL, Message);
RETURN -2;
When Others then
Message:= ' Emp ' || to_char(EmployeeSsn) ||
' can not be placed on project ' ||
to_char(ProjectNumber);
insert into Mylog values (NULL, Message);
RETURN -3;
END; -- second block
END;
434
PL/SQL Programming
Writing a Secure Procedure to Delete a Works_On record
The procedure Delete_WorksOn() is invoked to remove records from the
Works_On table. In the function-call the programmers authentication code
and the Works_On key field(s) are supplied. For example: in the following
call programmer ‘JB007’ asks to remove employee 123456789 from proj. 1.
Result:= Delete_WorkOn(‘JB007’,123456789,1)
• If the programmer ‘JB007’ is not authorized to make such a deletion, the
operation is rejected and MYLOG file is update with a rejection message
• If employee 123456789 is not in the Works_On table the current deletion is
rejected and the log file is updated otherwise, the record is eliminated
• The function returns a numeric code 1, -1, -2, etc. to indicate the status of
the execution. (1: success, negative values: problems).
435
PL/SQL Programming
-- DELETE_WORKSON script
create or replace
FUNCTION Delete_WorksOn (
Programmer_Id
EmployeeSsn
number,
number )
RETURN number
IS
Programmer_Name
varchar(20);
Message
varchar(70);
BEGIN
-- First block: Verify that programmer is allowed to delete
-- Note: all code goes in one BEGIN...END block
BEGIN
select Operator_Name into Programmer_Name
from
Valid_Operators
where Operator_Id = Programmer_Id;
EXCEPTION
when No_Data_Found then
Message:= 'Programmer not allowed to ' ||
'delete Works_On rec.';
Insert into Mylog values(Programmer_Id, Message );
RETURN -1;
END;
-- first block
436
PL/SQL Programming
-- DELETE_WORKSON script cont.
-- Second block: Other conditions could be checked here
-- before deleting the record
BEGIN
delete from Works_On
where Essn= EmployeeSsn;
RETURN 1;
EXCEPTION
When No_Data_Found then
Message:= ' Emp ' || to_char(EmployeeSsn) ||
' does not exist in Works_On table';
insert into Mylog values (NULL, Message);
RETURN -2;
When Others then
Message:= ' Emp ' || to_char(EmployeeSsn) ||
' can not be deleted from Works_On';
insert into Mylog values (NULL, Message);
RETURN -3;
END; -- second block
END;
/
437
PL/SQL Programming
Writing a Secure Procedure to Update Project records
The procedure Update_Project( ) is used to modify existing records in the Project table.
Individual records are located using the Pnumber values as search-key. The updating of
projects occurs in the context of a function call such as the example bellow.
The arguments passed to the function are: Programmer_Id, project number, name, location;
and number of responsible department.
Result:= Update_Project(‘JB007’,1,‘Cerveza XXX’,‘Margarita’,NULL);
•
•
•
•
•
•
•
Each project record to be updated must include the project number
More than one field could be updated in a single function call
Project numbers are not changeable (instead delete whole rec. and re-insert with a new number)
If the programmer ‘JB007’ is authorized to make deletion, the operation is rejected
If there is no record for project number 1, the current update is rejected
If a field is not going to be updated, the word NULL must be written in the proper column
The function returns a numeric code 1, -1, -2, etc. to indicate the status of the execution.
438
PL/SQL Programming
Writing a Secure Procedure to Update Project records
create or replace
FUNCTION Update_Project( Programmer_Id
ProjectNumber
ProjectName
ProjectLocation
DepartmentNumber
RETURN number
IS
Programmer_Name
varchar(20);
Message
varchar(70);
VarPnumber
number;
number,
number,
varchar,
varchar,
number )
439
PL/SQL Programming
Writing a Secure Procedure to Update Project records cont.
BEGIN
-- First block: Is programmer allowed to update projects?
-- NOTE: all code goes in one BEGIN...END block
BEGIN
select Operator_Name into Programmer_Name
from
Valid_Operators
where Operator_Id = Programmer_Id;
EXCEPTION
when No_Data_Found then
Message:= 'Programmer not allowed to ' ||
'update Projects';
Insert into Mylog
values (Programmer_Id, Message);
RETURN -1;
END;
-- first block
440
PL/SQL Programming
Writing a Secure Procedure to Update Project records cont.
-- Second block: Verify there is a project record matching
-- Pnumber key. If the field is not NULL, modify using given
-- parameter
BEGIN
select Pnumber into VarPnumber from
Project
where Pnumber= ProjectNumber;
if (ProjectName is not NULL) then
update Project
set
Pname= ProjectName
where Pnumber = ProjectNumber;
end if;
if (ProjectLocation is not NULL) then
update Project
set
Plocation= ProjectLocation
where Pnumber = ProjectNumber;
End if;
if (DepartmentNumber is not NULL) then
update Project
set
Dnum = DepartmentNumber
where Pnumber = ProjectNumber;
End if;
441
RETURN 1 ; -- success !
PL/SQL Programming
Writing a Secure Procedure to Update Project records cont.
-- Deal with Update problems here
EXCEPTION
When No_Data_Found then
Message:= ' Project ' ||
to_char(ProjectNumber) ||
' does not exist ';
insert into Mylog values (NULL, Message);
RETURN -2;
When Others then
Message:= ' Project '
||
to_char(ProjectNumber)
||
' can not be updated ';
insert into Mylog values (NULL, Message);
RETURN -3;
END; -- second block
END;
442