61 Role and Privileges 256 62 Object Privileges 257 63 Distributed Database System 259 64 Clusters 260 65 Temporary Tables 261 66 Materialize View 262 67 List of Predefined Packages 264 68 Index Organized Table 264 69 No Copy Compiler hint 265 70 BitMap Index 266 71 SDLC Stages 267 72 Performance Tuning 267 73 Normalization 269 5
Table of Contents What is DBMS? Drawbacks of file management system What is Database? Models used for DBMS RDBMSs used in the market C/S (Two Tier) Architecture N Tier Architecture Syllabus and Important topics SQL (Structured Query Language) Categories of SQL statements Database Objects Object Naming Rules and Guidelines Data Dictionary Data Types
What is Database and DBMS? 1. It is a collection of logically related data stored in a specific format 2. What is Data? What is information? 3. Drawbacks of file management systems Duplication of Data Data integrity problem Lengthy processing time Lengthy code, increased development costs High maintenance costs as complex to change 4. DBMS (Database Management System)
Application Database DBMS 6
Models used for DBMS Model determine how data is organized in the disk The following models are used for DMBS:- Hierarchic Model (HDBMS) Network Model (NDBMS) Relations Model (RDBMS) Object Model (OODBMS) Hierarchic Model The Hierarchical model was developed by IBM in 1968 One to Many relationship (parent node has the links to its child nods). SYSTEM2000 is an example of hierarchical database IBMs Information Management System (IMS). If we want to search a record, we have to traverse the tree from the root through all its parent nodes to reach the specific record. Thus, Searching for a record is very time consuming. This model uses pointers to navigate between stored data. Network Model In 1971, the conference on Data Systems Languages (CODASYL) formally defined the network model Many to Many relationship DBTG codasyl was the first network database Simplified searching as record has many access paths This model uses pointer to navigate between stored data Relational Model
EMPNO ENAME SAL 1001 SACHIN 50000 1002 SAURAV 35000 Introduced by Ted codd, IBM Researcher, in 1970 Database is a collection of normalized relations Attributes Tuples 7
Relation is a collection of tuples and attributes Every relation is independent Built in query language support(SQL) Different RDBMSs RDBMS Vendors RDBMS Computer Associates INGRES IBM DB2 Informix Software INFORMIX Oracle Corporation Oracle Microsoft Corporation MS Access Microsoft Corporation SQL Server MySQL AB MySQL PostgreSQL Dvlp Grp PostgreSQL Sybase Sybase11
C/S (Two Tier) Architecture
8
N Tier Architecture
SQL (Structured Query Language) History 1) Developed at IBM by Donald D. Chamberlin and Raymond F. Boyce in the early 1970 2) Initially Called SEQUEL (Structured English Query Language) 3) Designed to manipulate and retrieve data stored in IBMs original Relational database management system, System R 4) later Changed to SQL because SEQUEL was a trademark of the UK-based Hawker Siddeley aircraft company 5) Relation software, Inc. Introduced the first commercially available implementation of SQL, Oracle V2 (Version2) It is an Interface between database and requestor
9
Categories of SQL Statements Data Definition Statements (DDL) Used to Create and maintain database objects CREATE, ALTER, DROP, RENAME, TRUNCATE
Data Manipulation Statements (DML) Used to manipulate the data stored in the database INSERT, UPDATE, DELETE
Data Query Statement (DQL) Used to retrieve the data stored in the database SELECT
Data Control Statements (DCL) Used to manage / control the privileges GRANT, REVOKE
Transaction Control Statements (TCL) Used to manage the transaction COMMIT, ROLLBACK, SAVEPOINT, SET TRANSACTION
What is Transaction It is a logical UNIT of a work that contains one or more DML Statements. It begins with a DML statement and ends with COMMIT or ROLLBACK.
Session Control Statements They are used to change the properties of the session. ALTER SESSION, SET ROLE
System Control Statements It is used to change the properties of the Oracle Instance ALTER SYSTEM
10
What is an INSTANCE It is a collection of SGA(System/ Shared Global Area) and Background Process
11
Database Objects Oracle Database is a collection of various types of objects They are divided into two categories Schema Objects Non Schema Objects Schema It is a place where objects created by the user are stored Each user has schema by the same name as the user name Schema Objects If object created by User is stored in his/her own schema then it is called as schema object Non Schema Objects Irrespective of the user creating an object, if it is always stored in the schema SYS Then it is called as Non Schema Object. Object Naming Rules and Guidelines 1) Name must be 1 to 30 chars long 2) Name must begin with an alphabet 3) Name can contain alpha numeric characters, #, $, or _ 4) Name is not case sensitive 5) Reserve keyword cannot be used as a name 6) To ignore rule 2, 3, 4 and 5 name can be enclosed in 7) Name Must be unique within the schema Guidelines 1. Use Full, descriptive and pronounceable name 2. Use same name to describe same entity/ attribute Data Dictionary: - It is a Read only set of tables that store following information. 1) The definitions of all schema objects in the database 2) How much has been allocated for, and is currently used by, the schema objects 3) Default values for columns 4) Integrity constraint information 5) The name of Oracle users 12
6) Privileges and roles each user has been granted 7) Auditing information, such as who has accessed or updated various schema objects. Data Types Oracle provides the following categories of built-in data types 1. Character Data Types 2. Numeric Data Types 3. DATE Data type 4. RAW and LONG RAW Data Types 5. ROWID and UROWID Data types 6. LOB Data types Character Data Types 1. CHAR (NCHAR for supporting Unicode-multi byte) a. Stores fixed length character strings b. Default size 1 char c. Max size is 2000 chars d. If you provide shorter value then it is blank-padded to the fixed length e. If a value is too large, oracle returns an error f. Oracle compares CHAR values using blank-padded comparison semantics 2. VARCHAR2 (NVARCHAR2 for supporting Unicode-multi byte) a. Stores variable length character strings b. Saves on the space used by the table c. Max size is 4000 chars d. If a value is too large, Oracle returns an error e. Oracle compares VARCHAR2 values using Non-padded comparison semantics
NUMBER NUMBER (P,S) It stores fixed and floating-point, negative numbers 13
Number having precision P and scale s. The precision p can range from 1 to 38 . the scale s can range from -84 to 127
Actual Data Specified As Stored As 7456123.89 NUMBER 7456123.89 7456123.89 NUMBER(9) 7456124 7456123.89 NUMBER(9,2) 7456123.89 7456123.89 NUMBER(9,1) 7456123.9 7456123.89 NUMBER(6) Exceeds precision 7456123.89 NUMBER(7,-2) 7456100 7456123.89 NUMBER(7,2) Exceeds precision
DATE It stores Century, Year, Month, Day, Hour, Minute, Seconds Oracle can store dates in the Julian era, ranging from January 1, 4712 BCE through December 31 4712 CE (Common Era) Date data is stored in fixed-length fields of seven bytes each, corresponding to century, year, month, day, hour, minute, and second For input and output of dates, the standard Oracle date format is DD-MON-YY NLS_DATE_FORMAT can be used to change the standard date format TO_DATE function with a format mask can be used to INSERT date value in different format than the standard one Default time is 00:00:00 and date is date of first day of current month LONG It used to store the character data up to 2 GB in size This data type is provided only for backward compatibility with existing applications The use of LONG values is subject to these restrictions: o A table can contain only one LONG column. o You cannot create an object type with a LONG attribute. o LONG columns cannot appear in WHERE clauses or in integrity constraints (except that they can appear in NULL and NOT NULL constraints). o LONG columns cannot be indexed. o LONG data cannot be specified in regular expressions. o A stored function cannot return a LONG value. o You can declare a variable or argument of a PL/SQL program unit using the LONG data type. However, you cannot then call the program unit from SQL. o In addition , LONG columns cannot appear in these parts of SQL statements o GROUP BY clauses, ORDER BY clauses, or CONNECT BY clauses or with the DISCTINCT operator in SELECT statements o SQL built-in functions, expressions, or conditions 14
o SELECT lists of CREATE TABLE AS SELECT statements
RAW and LONG RAW Data types Used to store binary data For example, LONG RAW can be used to store graphics, sound, documents, or arrays of binary data ROWID and UROWID Data types Oracle uses a ROWID data type to store the address (ROWID) of every row in the database Physical ROWID, LOGICAL ROWID (will be explained later) LOB Data types They enable you to store large blocks of unstructured data (such as text, graphic images, video clips, and sound waveforms) up to 4 gigabytes in size Oracle Corporation recommends that you always use LOB data types over LONG data types 1. BLOB stores unstructured binary data in the database 2. CLOB and NCLOB stores character data in the database 3. BFILE a. Stores unstructured binary data in operating-system files outside the database b. BFILE column or attribute stores a file locator that points to an external file containing the data c. FILEs are read-only; you cannot modify them
15
There are various tools available in the market which can be used at the client machine side to connect to the Oracle Database Serevr and perform Database operation. Few of such tools are TOAD Sequel Developer. Oracle also offers you the tool by the name SQL PLUS which is the character made tool. While you want connect from client machine to the Database server you need to provide the Authorized USER ID and PASSWORD along with the connect string (Host String). This Hoststring is mapped name which can be found in TNS NAMES.ORA file on the client machine. This Hoststring is mapped to the IP ADDRESS and PORT NUMBER of the machine where Database server is mounted / located. How to connect Database : Connect xxxxx (User Name) / xxxxx (Password) How to Disconnect Database: Disconnect; 1. CREATE Table Syntax: we can define in Table 1 (Min) to 1000 (Max) columns.
Impact of Create Table: Oracle allocates data segment to store the data of this table. Information of this table is stored into data dictionary. Recursive SQLs: These are the statements fired by Oracle (internally) in response to the statements issued by user. They are fired to update the information/data stored in the data dictionary tables 22-May-2011 Table Name Datatype Length Column Name Both ways we can create Table as shown in above & below Figures 16
2. INSERT VALUES Syntax:
or
or
In Sequel plus last sequel statements is stored in the Buffer. If you want to modify the stored Database in server. We have 2 Options: 1. Sequel Command can be used. 2. Editor can be work to change that. Note: If you are using ED in windows default editor is Notepad & Linux default editor is VI. Using DEFAULT Clause: In Oracle by Default is NULL. If you want to change you assign DEFAULT clause. It can be used to provide the default values for the columns. In such cases, when you dont provide any values for these columns, instead of inserting NULL, ORACLE will insert values provided with DEFAULT clause. Use of & (Ampersand): It can be used in SQL*PLUS to accept the values on the prompt. 3. SELECT Statement syntax: SELECT <column_name(s)> | <*>||<expr> FROM <table_name> [WHERE <condition>] [GROUP BY <expr>] [HAVING <condition>] [ORDER BY <expr>]
These ways we can Data Insert in Table as shown in above & below Figures. 17
4. Comparison Operators: Logical Operators: 1. AND 2. OR 3. NOT (This Operator always TRUE=FALSE & FALSE=TRUE) Among these Logical Operators AND has get the higher precedence then OR, NOT. So overwrite this presidency use brackets. Operator Meaning = Equal to !=, <>, ^= Not Equal to > Greater Than < Less Than >= Greater Than Equal to <= Less Than Equal to IN (<list of values>) Equal to one the values given in the list BETWEEN <x> AND <y> Value is in the range of <x> and <y> including values given in <x> and <y> IS NULL and IS NOT NULL LIKE <pattern> % = Multi character replacement _ Single character replacement 18
5. Using ORDER BY clause syntax:
19
Expression Example:
Oracle Instance : SGA + Background Process Page setting command : set linesize XXXX; or set pagesize XXXX;
20
As specified in the above diagram Data & Information stored in the SGA is shared among the all sessions are connected (After Checking Privileges). 29-May-2011
ROLLBACK SEGMENT SGA (Shared / System) Global area Database Buffer Cache Redolog Buffer Cache Shared Pool PGA PGA PGA Database Server Session 1 Session 3 Session 2 Private/Program Global area Data files (Hard disk) 21
SGA is divided in to 3 Parts : 1. Database Buffer Cache 2. Redolog Buffer 3. Shared Pool PGA: Whenever Session will be established Oracle allocates to the space at the server side to store the session private information.
Database Engine: Every SQL statement goes to Database Engine for Execution. Database Engine has 2 Parts 1) Optimizer 2) SQL statement Executor 1) Optimizer: Optimizer is responsible for generating the Execution plan. 2) SQL statement Executor: Execute the Sequel statements as per the plan generated by the Optimizer. Shared Sequel Area: For every Unique Sequel statements Oracle generate the Execution plans Pars tree (a steps) which is stored in the Shared pool in the form of Shared Sequel Area. For every sequel statement Oracle checks the Information store in the Data Dictionary which is stored in the Data Dictionary cache inside the Shared Pool. 6. Following things happens internally when following Sequel (SQL) statements are executed?
Database Buffer Cache: It is newly Inserted data is stored into the Database Buffer Cache. This Inserted data available only that session that has inserted this data unless it is committed data has not available to any other sessions. Redolog Buffer: Redo entry generate by the insert statements is stored in the Redolog Buffer. When Session issues commit statement this redo entry saved in the Redolog Buffer and this new inserted data stored in to Data Files (Hard Disk). Note: Select Statement -----Oracle 1st checks into Database Buffer Cache. If require data is there if not then its load that data from Datafiles (Harddisk) to the Database Buffer Cache.
22
7. UPDATE Ststement UPDATE <table_name> SET <column_name1> = <value1> [, <column_name2> = <value2> [WHERE <condition>] DELETE FROM <name> [WHERE <condition>]
Oracle checks in the Database Buffer Cache for required Data. If it is not there it will load from Datafiles (Harddisk). In case WHERE condition is not given and requires to manipulate the all records. It will lock that record transfer the old values to the ROLLBACK SEGMENT and manipulates the new values in to the Database Buffer Cache. Redo entry stored in to the Redolog Buffer. In case filter condition is given Oracle scans through each record. If the condition is satisfied then locks that record and transverse to the old value ROLLBACK SEGMENT and update the record new value in the Database Buffer Cache. Records to the locks for other sessions and only as read-only. For other sessions for updated records old values will be read from ROLLBACK SEGMENT.
8. ALTER statement syntax:
Add one more columns to the existing table Modify the properties (Name, Data type, Length) of the existing columns 23
enable, disable & drop integrity constraints [INTEGRITY CONSTRAINTS] enable, disable all database triggers applied on the table [PLSQL] change the storage clause and data block usage parameters [Oracle Internal Concepts]
While modifying properties of the existing columns following should be kept in mind.
You can Increase length whenever you want 24
To decrease the length either column must be empty or The length you specified is not less than the length of the actual value stored in that column. Datatype of the column change if data is empty. If column contains values then Datatype cannot be changed (Exception: Char to Varchar2 or varchar2 to Char)
RENAME: ALTER TABLE <name> RENAME COLUMN <source name> TO <target name>
25
Note: After 9.I version only it will work ALTER COLUMN RENAME;
9. DROP Table Statement:
Syntax: DROP TABLE POLLACK; Effects of Dropping Table: All records will be Deleted and Data segment will be released (freed) All relevant information will be removed from the Data Dictionary. Integrity constraints, Indexes and Database Triggers will be dropped along with the table. View, Synonyms, Stored Procedures, Stored Functions and packages will remain but it will be in Invalid.
10. TRUNCATE Table Statement:
Syntax: TRUNCATE TABLE POLLACK; The following are the differences between TRUNCATE and DELETE 11. RENAME Table Statement: Syntax: RENAME POLLACK TO JADEJA; S.No DELETE TRUNCATE 1 It is a DML statement It is a DDL statement 2 You can DELET specific record(s) using WHERE clause Can't use WHERE clause 3 Oracle maintains REDO entries Oracle doesn't maintain REDO entries 4 Deleted records can be recovered (using ROLLBACK) Truncated records cannot be recovered (using ROLLBACK) 5 Fires Database Triggers Doesnt fire Database Triggers 6 Can be used to DELETE the records from Parent and clustered table Cannot be used to DELETE the records from Parent and clustered table 7 It is slower than TRUNCATE It is faster than DELETE 26
12. Transaction control Statement:
COMMIT: It is used to save the changes made by the given Transactions. All DDL, System control, Session control, DCL statements have implicit commit.
ROLLBACK: It is used to cancel the changes made by the Transactions. SAVEPOINT: It is used to mark the portion of transaction by using unique name so that rolling back till that portion of transaction is possible. ROLLBACK to statement can be used to ROLLBACK portions of transaction to specific SAVEPOINT. When you rollback to a particular SAVEPOINT, the save points THAT are applied after that will be removed. When you use ROLLBACK or COMMIT, all the SAVEPOINTs applied in that transactions are removed. Oracle recommends you to use unique name for the save points in a given transaction.
Example: SAVEPOINT A; INSERT INTO emp (empno, ename, sal, deptno) VALUES (1007,SACHIN, 7500, 10); SELECT * FROM emp; SAVEPOINT B; UPDATE emp SET SAL = SAL+1000; SELECT * FROM emp; DELETE FROM emp WHERE job=CLERK; SELECT * FROM emp; DELETE FROM emp; SELECT * FROM emp; ROLLBACK TO B; SELECT * FROM emp; ROLLBACK; SELECT * FROM emp;
27
13. SET Transaction Statement:
Syntax: SET TRANSACTION READ ONLY; Once you set the transaction to READ ONLY you can issue only select statements. To come out of READ ONLY mode you have to issue COMMIT/ROLLBACK statement. All these select statement will read the data as of the point when the transaction was set read only. All the changes made and committed by other session will not be visible to the select statements issued by you.
28
Sr. No. Term Explanation 1 BPS Bits per Second 2 CPS characters per second 3 DBMS Database Management System 4 DOS Disk Operating System 5 DPI Dot per Inch 6 Ethernet IEEE 802.3 Standard LAN protocol 7 GB Gigabyte 8 Hz Hertz (cycles per second) 10 ISO International Standards Organization 11 KB kilobyte 12 KVA Kilovolt ampere 13 LAN Local area network 14 LPI Lines per inch 15 LPM Lines per minute 16 MB Megabyte 17 MTBF Mean time between failures 18 NIC Network interface card 19 NOS Network operating system 20 ODBC Open Database Connectivity 21 OLE Object Linking and Embedding 22 OS Operating system 23 PCL Printer Command Language 24 PPM Pages per minute 25 PS PostScript -- Adobe page description language 26 RAID Redundant array of inexpensive disks 27 RAM Random access memory 28 RISC Reduced Instruction-set computer 29 SCSI Small Computer system Interface 30 SNMP Simple Network management Protocol 31 SQL Structure Query language 32 TB Terabyte 33 TCP/IP Transmission Control Protocol/Internet Protocol 34 V Volt 35 WLAN Wireless LAN 36 GEC Groundwater Estimation Committee. 37 DC Data Center 38 DR Disaster Recovery 39 CGWB Central Ground Water Board 40 GEMS Groundwater Estimation Management System.
29
SQL Functions Functions are a very powerful feature of SQL and can be used to do the following: Perform calculations on data Modify individual data items Manipulate output for groups of rows Format dates and numbers for display Convert values between data types
SQL functions sometimes take arguments and always return a value.
There are two distinct types of functions: Single-row functions Multi-row functions/Group Functions/Aggregate Functions
30
Single-Row Functions Single-row functions are used to manipulate data items. They accept one or more arguments and return one value for each row. An argument can be one of the following: User-supplied constant Variable value Column name Expression
Syntax
function_name [(arg1, arg2,...)]
function_name is the name of the function. arg1, arg2 is any argument to be used by the function. This can be represented by a column name or expression. 31
Character Number Date Conversion List Functions/General Functions
Character Functions and Operators
Single-row character functions accept character data as input and can return both character or Numeric values. Based on their return type they are further classified as. Character Functions Returning Character Values Character Functions Returning Number Values
Operator: 1) || (Concatenation Operator) - It is used to combine two more strings together 32
SELECT ename || ' Is working as '||job FROM emp
Character Functions Returning Character Values : The character functions that return character values are: CHR
CHR returns char for the given ASCCI value Examples
SELECT CHR(67)||CHR(65)||CHR(84) "Dog" FROM DUAL;
Dog --- CAT
CONCAT
CONCAT returns char1 concatenated with char2. This function is equivalent to the concatenation operator (||). Examples
SELECT CONCAT(Sachin, Tendulkar ') as Name FROM dual;
Name SachinTendulkar 33
INITCAP
INITCAP returns char, with the first letter of each word in uppercase, all other letters in lowercase. Words are delimited by white space or characters that are not alphanumeric. Examples
SELECT INITCAP(the tiger) "Capitals" FROM DUAL;
Capitals --------- The Tiger
LOWER
LOWER returns char, with all letters lowercase. Examples
SELECT LOWER('MR. SACHIN TENDULKAR') "Lowercase" FROM DUAL;
Lowercase -------------------- mr. sachin tendulkar
34
UPPER
UPPER returns the given char argument in upper case Examples
SELECT sachin tendulkar as "Uppercase" FROM dual;
Uppercase ---------------- SACHIN TENDULKAR
LPAD
LPAD (<expr>,<n>, [,<char>]) LPAD returns the given expr, left-padded to length n with the sequence of characters in <char>. The argument n must be a NUMBER integer or a value that can be implicitly converted to a NUMBER integer. If you do not specify <char>, then the default is a blank space. If expr is longer than n, then this function returns the portion of expr that fits in n. The argument n is the total length of the return value. Examples
SELECT LPAD(SACHIN,15,'*') "LPAD example" FROM DUAL;
LPAD example --------------- 35
*********SACHIN RPAD RPAD (<expr>,<n>, [,<char>])
Opposite to LPAD Examples
SELECT last_name, RPAD(last_name,10, '*') "Name" FROM employees WHERE department_id = 80 ORDER BY last_name;
LAST_NAME Name ------------------------- ---------- Abel Abel****** Ande Ande****** Banda Banda***** Bates Bates*****
LTRIM LTRIM(<expr>[,<char>)
1. It removes the given char from the left side of the given expr (till it finds another letter). 2. If char is not given then it removes blank spaces Examples
SELECT first_name, LTRIM(first_name, 'V') "Name" FROM employees;
FIRST_NAME Name 36
-------------------- --------------- Sachin Tendulkar Sachin Tendulkar Saurav Ganguly Saurav Ganguly Rahul Dravid Rahul Dravid M S Dhoni M S Dhoni Virendra Sehwag irendra Sehwag Zaheer Khan Zaheer Khan Anil Kumble Anil Kumble VVS Laxman S Laxman
RTRIM RTRIM (<expr>[,<char>)
Opposite to LTRIM Examples
SELECT RTRIM('Sachin Tendulkar**********','*') "RTRIM example" FROM DUAL;
RTRIM exam ---------- Sachin Tendulkar
37
TRIM
TRIM enables you to trim leading or trailing characters (or both) from a character string. If you specify LEADING, then Oracle removes characters from left side (works like LTRIM) If you specify TRAILING, then Oracle removes characters from right side (works like RTRIM) If you specify BOTH or none of the three, then Oracle removes leading and trailing characters equal to trim_character. If you do not specify trim_character, then the default value is a blank space. If you specify only trim_source, then Oracle removes leading and trailing blank spaces. The function returns a value with datatype VARCHAR2. The maximum length of the value is the length of trim_source. If either trim_source or trim_character is null, then the TRIM function returns null. Examples
SELECT First_Name,TRIM(LEADING V FROM FIRST_NAME) as Name FROM employees.
FIRST_NAME Name -------------------- --------------- Sachin Tendulkar Sachin Tendulkar Saurav Ganguly Saurav Ganguly Rahul Dravid Rahul Dravid M S Dhoni M S Dhoni Virendra Sehwag irendra Sehwag Zaheer Khan Zaheer Khan 38
1. It searches for the given search_string into the given expr, replaces those occurrences with the replacement_string and then returns that expression 2. The search_string and replacement_string may vary in the length 3. If replacement_string is not given then all occurrences of search_string are removed Examples
SELECT REPLACE('JACK and JUE','J','BL') "Changes" FROM DUAL;
Changes -------------- BLACK and BLUE
TRANSLATE TRANSLATE (<expr>, <from>, <to>)
1. TRANSLATE returns the given expr, with all occurrences of from character to be replaced by its corresponding character in to. 2. from and to length must match, if not then a. If from has more chars than to THEN they are removed 39
b. If to has more chars than from then they are ignored Examples
SELECT TRANSLATE(SACHIN TENDULKAR, 'ABC', 'XYZ') as TranslateFROM DUAL;
Translate -------------------- SXZHIN TENDULKXR
SUBSTR SUBSTR (<expr>,<m>[,<n>])
The SUBSTR function returns a portion of the given expr, starting at mth location and n characters long. N is optional and in absence of the same, it returns entire string of given expr starting at mth location If M is negative then it will start from the end of the given expr N can not be negative Examples
SELECT SUBSTR('ABCDEFG',3,4) "Substring" FROM DUAL;
Substring --------- CDEF
SELECT SUBSTR('ABCDEFG',-5,4) "Substring" FROM DUAL;
Substring --------- CDEF 40
Character Functions Returning Number Values Character functions that return number values can take as their argument any character datatype. The character functions that return number values are: ASCII
ASCII returns the ASCII value of the given character If string is passed then it returns the ASCII value of the 1st character of that string Examples
SELECT ASCII(L) as VALUE FROM dual;
VALUE ----- 76
INSTR INSTR(<expr>, <search>[,<m>[,<n>]] )
1. It returns the position of the search_string when found in to the given expr 2. Default values of M and N are 1 3. M stands for the search location. Value of N can be negative to start the search from end of the expr 4. N stands for the occurrence 5. returns 0 if search_string is not found Examples 41
SELECT INSTR('CORPORATE FLOOR','OR', 3, 2) "Instring" FROM DUAL;
Instring ---------- 14
SELECT INSTR('CORPORATE FLOOR','OR', -3, 2) "Reversed Instring" FROM DUAL;
Reversed Instring ----------------- 2
LENGTH length::=
The LENGTH functions return the length of char. The return value is of datatype NUMBER. If char has datatype CHAR, then the length includes all trailing blanks. If char is null, then this function returns null. The following example uses the LENGTH function using a single-byte database character set: Examples
SELECT LENGTH('SACHIN TENDULKAR') "Length in characters" FROM DUAL;
1. ROUND returns n rounded to m places to the right of the decimal point 2. If you omit m, then n is rounded to 0 places 3. m can be negative to round off digits left of the decimal point Examples
SELECT ROUND(15.193,1) "Round" FROM DUAL;
Round ---------- 15.2
SELECT ROUND(15.193,-1) "Round" FROM DUAL;
Round ---------- 20
SELECT ROUND(1.5), ROUND(2.5) FROM DUAL;
ROUND(1.5) ROUND(2.5) ---------- ---------- 2 3
43
TRUNC (number) TRUNC(<n>[,<m>)
4. TRUNC returns n TRUNCATED to m places to the right of the decimal point 5. If you omit m, then n is TRUNCATED to 0 places 6. m can be negative to TRUNCATE digits left of the decimal point Examples
SELECT TRUNC(15.79,1) "Truncate" FROM DUAL;
Truncate ---------- 15.7
SELECT TRUNC(15.79,-1) "Truncate" FROM DUAL;
Truncate ---------- 10
CEIL
CEIL returns NEAREST integer greater than or equal to n. Examples
SELECT CEIL(268651.8) as Truncate FROM dual; 44
Truncate ---------- 268652
FLOOR
FLOOR returns NEAREST integer less than or equal to n. Examples
SELECT FLOOR(15.7) "Floor" FROM DUAL;
Floor ---------- 15
POWER POWER (<n> ,<m>)
It returns n raised to power of m Examples
SELECT POWER(3,2) "Raised" FROM DUAL;
Raised ---------- 9
45
ABS ABS (<n>)
It returns the absolute value n
Date Functions
Oracle Date Format
1. Oracle database stores dates in an internal numeric format, representing the century, year, month, day, hours, minutes, and seconds. 2. The default display and input format for any date is DD-MON-YY or DD-MON-YYYY. Valid Oracle dates are between January 1, 4712 B.C. TO December 31, 9999 A.D.
SYSDATE It returns the date and time information of the database server Examples
SELECT SYSDATE as TODAY FROM DUAL;
TODAY --------- 12-JUL-10
Note: Default date format is DD-MON-YY
46
Arithmetic with Dates You can perform calculations using arithmetic operators such as + and -. You can add and subtract number constants as well as dates. You can perform the following operations:
Operation Result Description date + number Date Adds a number of days to a date date - number Date Subtracts a number of days from a date date - date Number of days Subtracts one date from another date + number/24 Date Adds a number of hours to a date Examples
SELECT first_name , hiredate , hiredate + 1 as NEXT DAY , hiredate 1 as PREV DAY FROM dual; FIRST_NAME HIREDATE NEXT DAY PREV DAY ---------- --------- --------- --------- SACHIN 12-JUL-10 13-JUL-10 11-JUL-10
Note: SELECT 12-JAN-10 + 10 FROM dual;
The above example will throw an error. Because it is a character string.
47
ADD_MONTHS ADD_MONTHS (<date> , <n>)
1. It adds given number of months to the given date 2. N can be negative to subtract the months Examples
SELECT ADD_MONTHS(hire_date,1) "Next month" FROM employees WHERE last_name = 'SACHIN';
Next Month ----------- 07-JUL-89
MONTHS_BETWEEN
1. MONTHS_BETWEEN returns number of months between dates date1 and date2 2. If date1 is later than date2, then the result is positive. If date1 is earlier than date2, then the result is negative 3. If date1 and date2 are either the same days of the month or both last days of months, then the result is always an integer. Otherwise Oracle Database calculates the fractional portion of the result based on a 31-day month and considers the difference in time components date1 and date2. Examples
SELECT MONTHS_BETWEEN('02-FEB-1995','01-JAN- 1995') "Months" FROM DUAL;
48
Months ---------- 1.03225806
NEW_TIME
NEW_TIME returns the date and time in time zone timezone2 when date and time in time zone timezone1 are date. The arguments timezone1 and timezone2 can be any of these text strings: AST|ADT: Atlantic Standard or Daylight Time BST|BDT: Bering Standard or Daylight Time CST|CDT: Central Standard or Daylight Time EST|EDT: Eastern Standard or Daylight Time GMT: Greenwich Mean Time HST|HDT: Alaska-Hawaii Standard Time or Daylight Time. MST|MDT: Mountain Standard or Daylight Time NST: Newfoundland Standard Time PST|PDT: Pacific Standard or Daylight Time YST|YDT: Yukon Standard or Daylight Time The following example returns an Atlantic Standard time, given the Pacific Standard time equivalent: Examples
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY HH24:MI:SS';
SELECT NEW_TIME(TO_DATE( '11-10-99 01:23:45', 'MM-DD-YY HH24:MI:SS'), 'AST', 'PST') "New Date and Time" FROM DUAL;
New Date and Time 49
-------------------- 09-NOV-1999 21:23:45
SELECT TO_CHAR(NEW_TIME(SYSDATE,'EST','PST'),'DD-MON-YYYY HH24:MI:SS') FROM DUAL / NEXT_DAY
NEXT_DAY (<date>, <day>) It returns the date of the day when it occurs after the given date. Examples
SELECT NEXT_DAY('21-AUG-2011','SUNDAY') "NEXT DAY" FROM DUAL;
NEXT DAY ----------- 28-AUG-2011
LAST_DAY
LAST_DAY returns the date of the last day of the month of given date Examples
SYSDATE Last Days Left --------- --------- ---------- 30-MAY-01 31-MAY-01 1
Assignments 1. Want to count how many 'A' are there in the name 'AAMIR KHAN' 2. Find out how many days are left in the current month
Conversion Functions Conversion functions convert a value from one data type to another
51
Function Purpose TO_CHAR(number|date,[fmt ]) Converts a number or date value to a VARCHAR2 character string as per the given fmt TO_NUMBER(char,[fmt]) Converts a character string containing digits to a number as per the given fmt TO_DATE(char,[fmt]) Converts a character string representing a date to a date value according to the fmt specified. If fmt is omitted, the format is DD-MON-YY or DD-MON-YYYY unless you have changed it
Examples
SELECT employee_id, TO_CHAR(hire_date, MM/YY) Month_Hired FROM employees WHERE last_name = Sachin;
SELECT TO_DATE( '15/01/1989', 'dd/mm/yyyy) AS Value FROM DUAL;
Value --------- 15-JAN-89
SELECT TO_NUMBER($3,103.00, $99,999.00) VALUE FROM dual;
Value -------- 3103
53
Element Description SCC or CC Century; server prefixes B.C. date with - Years in dates YYYY or SYYYY Year; server prefixes B.C. date with - YYY or YY or Y Last three, two, or one digits of year Y,YYY Year with comma in this position IYYY, IYY, IY, I Four, three, two, or one digit year based on the ISO standard SYEAR or YEAR Year spelled out; server prefixes B.C. date with - BC or AD B.C./.D. indicator B.C. or A.D. B.C./A.D. indicator with periods Q Quarter of year MM Month: two-digit value MONTH Name of month padded with blanks to length of nine characters MON Name of month, three-letter abbreviation RM Roman numeral month WW or W Week of year or month DDD or DD or D Day of year, month, or week DAY Name of day padded with blanks to a length of nine characters 54
DY Name of day; three-letter abbreviation J Julian day; the number of days since 31 December 4713 B.C. AM or PM Meridian indicator A.M. or P.M. Meridian indicator with periods HH or HH12 or HH24 Hour of day, or hour (112), or hour MI Minute (059) SS Second (059) SSSSS Seconds past midnight (086399) / . , Punctuation is reproduced in the result of the Quoted string is reproduced in the result TH Ordinal number (for example, DDTH for 4TH) SP Spelled-out number (for example, DDSP for FOUR) SPTH or THSP Spelled-out ordinal numbers (for example, DDSPTH for FOURTH) 9 Represents a number 0 Forces a zero to be displayed $ Places a floating dollar sign L Uses the floating local currency symbol . Prints a decimal point , Prints a thousand indicator MI Minus signs to right (negative values) 55
999999MI 1234- PR Parenthesize negative numbers 999999PR <1234> EEEE Scientific notation (format must specify four Es) 99.999EEEE 1.234E+03 V Multiply by 10 n times (n = number of 9s after V) 9999V99 123400 B Display zero values as blank, not 0
List Functions
GREATEST
GREATEST returns the greatest of the list of one or more expressions. Oracle Database uses the first expr to determine the return type. If the first expr is numeric, then Oracle determines the argument with the highest numeric precedence, implicitly converts the remaining arguments to that datatype before the comparison, and returns the value of that datatype. If the first expr is not numeric, then each expr after the first is implicitly converted to the datatype of the first expr before the comparison.
Examples 56
SELECT GREATEST ('HARRY', 'HARRIOT', 'HAROLD') "Greatest" FROM DUAL;
Greatest -------- HARRY
LEAST
Purpose LEAST returns the least of the list of exprs. All exprs after the first are implicitly converted to the datatype of the first expr before the comparison
Examples
SELECT LEAST('HARRY','HARRIOT','HAROLD') "LEAST" FROM DUAL;
LEAST ------ HAROLD
57
NVL
If expr1 is null, then NVL returns expr2. If expr1 is not null, then NVL returns expr1. Examples
SELECT last_name, NVL(TO_CHAR(commission_pct), 'Not Applicable') "COMMISSION" FROM employees;
LAST_NAME COMMISSION ------------------------- --------------------- ------------------- Sachin Not Applicable Saurav Not Applicable Anil .1 Rahul .15 Gautam Not Applicable Sehwag .25 Zaheer Not Applicable Dhoni .2 Laxman Not Applicable
SIGN
SIGN returns the sign of n. For value of NUMBER type, the sign is: -1 if n<0 0 if n=0 1 if n>0 Examples 58
SELECT SIGN(2000-3000),SIGN(200-200),SIGN(20- 10) FROM DUAL /
DECODE Syntax DECODE(<expr>, <search>, <result>, <default>) DECODE(<expr>, <search>, <result>, <search>, <result>, <search>, <result>, <searchn>, <resultn>, <default>) DECODE compares expr to each search value one by one. If expr is equal to a search, then Oracle returns the corresponding result. If no match is found, then Oracle returns default. If default is omitted, then Oracle returns null. DECODE can contain arithmetic operators, SQL functions but it can not contain COMPARISON and LOGICAL operators The maximum number of components in the DECODE function, including expr, searches, results, and default, is 255. Nested DECODE can be given inside Result and/or DEFAULT One DECODE can have only one expr and default Examples
NAME LOCATION_ID LOCATION ------------------------- ------------- --- ----------------- Sachin 4 Seattle Saurav 3 New Jersey Anil 2 San Francisco Rahul 5 Non Domestic Gautam 1 Southlake Sehwag 4 Seattle
20,DECODE(UPPER(job),'MANAGER',sal+2500, sal+1200), sal+700 ) "Incr Sal" from emp /
Assignment CONDITION Result sal > 5000 1500 sal <= 5000 and >=3000 1200 sal < 3000 and > 2000 700 else
UPDATE emp SET sal = DECODE(SIGN(sal-5000),1,sal+1500, DECODE(sign(sal-2999),1,sal+1200, DECODE(sign(sal-2000),1,sal+700, sal+500))) /
61
Aggregate Functions/Group Functions 1. Aggregate functions return a single result based on groups of rows, rather than on single row. 2. Oracle applies the aggregate functions to each group of rows and returns a single result for each group. If you omit the GROUP BY clause, then Oracle applies aggregate functions to all the rows stored in that column. 3. All aggregate functions except COUNT(*) ignore nulls 4. You can use the NVL function in the argument to an aggregate function to substitute a value for a null. 5. COUNT never returns null, but returns either a number or zero. 6. For all the remaining aggregate functions, if the data set contains no rows, or contains only rows with nulls, then the function returns null.
AVG AVG (<expr>) AVG returns average value of expr. Examples
SELECT AVG(salary) "Average" FROM employees;
Average -------- 6425
SUM SUM(<expr>) SUM returns the sum of values of expr. Examples
SELECT SUM(salary) "Total" FROM employees;
Total 62
---------- 691400 MIN MIN (<expr>) MIN returns minimum value of expr. Examples
SELECT MIN(hire_date) "Earliest" FROM employees;
Earliest --------- 17-JUN-87
MAX MAX (<expr>) MAX returns maximum value of expr. Examples
SELECT MAX(salary) "Maximum" FROM employees;
Maximum ---------- 24000
COUNT COUNT (* | <expr>)
1. COUNT returns the number of rows returned by the query. 63
2. If you specify expr, then COUNT returns the number of rows where expr is not null. 3. If you specify the asterisk (*), then this function returns all rows, including nulls. 4. COUNT never returns null. Examples SELECT COUNT(*) "Total" FROM employees;
Total ---------- 107
SELECT COUNT(*) "Allstars" FROM employees WHERE commission_pct > 0;
Allstars --------- 35
SELECT COUNT(commission_pct) "Count" FROM employees;
Count ---------- 35
SELECT COUNT(DISTINCT manager_id) "Managers" FROM employees;
Managers ---------- 18
SELECT COUNT(empno),COUNT(comm) FROM emp
64
DISTINCT Clause
1. Returns UNIQUE values of the given column(s) 2. Oracle (internally) uses GROUP BY clause to create groups of the values stored in the columns specified in the DISTINCT clause 3. In earlier versions of Oracle (9i and earlier), ORACLE also uses ORDER BY clause
SELECT DISTINCT DEPTNO FROM EMP
SELECT DISTINCT DEPTNO,JOB FROM EMP
GROUP BY Clause
Sequence <WHERE> | <ORDER BY> (implicit only up to ver 9i) | <GROUP BY> | <GROUP FUNCTIONS> | <DISTINCT> (Implicit) | <ORDER BY> (if specified explicitly)
65
1. It is used to create the groups of all duplicate values so that group function can return one results for each group 2. Column specified in SELECT statement should be used in GROUP BY clause, but column used in GROUP BY clause, can be skipped during SELECTion
SELECT deptno,SUM(sal) FROM emp GROUP BY deptno ORDER BY deptno
SELECT deptno,job, SUM(sal),COUNT(empno) FROM emp GROUP BY deptno, job ORDER BY deptno,job / SELECT deptno, SUM(sal), AVG(sal), COUNT(*) FROM emp WHERE job = 'CLERK' GROUP BY deptno / HAVING Clause Sequence <WHERE> | <ORDER BY> (implicit only up to ver 9i) | <GROUP BY> | <GROUP FUNCTIONS> | <HAVING> | <DISTINCT> (Implicit) | <ORDER BY> (if specified explicitly) 1. It is used to filter the groups (created by the GROUP BY c lause), based on the given filter condition 66
SET OPERATORS 1) UNION 2) UNION ALL 3) MINUS 4) INTERSECT
SET Operators can best be understood by the following example:
Considering the Following Table Structure:
Table Name Table Details
T1
SQL> SELECT * FROM T1; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- ---------- --------- ---------- ------- 7782 CLARK MANAGER 7839 09-JUN-81 2450 10 7839 KING PRESIDENT 17-NOV-81 5000 10 7934 MILLER CLERK 7782 23-JAN-82 1300 10 7369 SMITH CLERK 7902 17-DEC-80 800 20 7900 JAMES CLERK 7698 03-DEC-81 950 30 T2
SQL> SELECT * FROM T2;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- --------- ---------- ---------- ---------- 7369 SMITH CLERK 7902 17-DEC-80 800 20 67
7566 JONES MANAGER 7839 02-APR-81 2975 20 7788 SCOTT ANALYST 7566 19-APR-87 3000 20 7876 ADAMS CLERK 7788 23-MAY-87 1100 20 7902 FORD ANALYST 7566 03-DEC-81 3000 20 7782 CLARK MANAGER 7839 09-JUN-81 2450 10 7900 JAMES CLERK 7698 03-DEC-81 950 30
# SET Operator SQL Query Result/Remarks 1 UNION (T1 and T2) SQL> SELECT ENAME,DEPTNO FROM T1 UNION SELECT ENAME,DEPTNO FROM T2; ENAME DEPTNO ---------- ---------- ADAMS 20 CLARK 10 FORD 20 JAMES 30 JONES 20 KING 10 MILLER 10 SCOTT 20 SMITH 20 Note: Union does not retrieve duplicate records. 2 UNION (T2 and T3) SQL> SELECT ENAME,DEPTNO FROM T2 UNION SELECT ENAME,DEPTNO FROM T3; ENAME DEPTNO ---------- ---------- ADAMS 20 ALLEN 30 BLAKE 30 CLARK 10 FORD 20 JAMES 30 JONES 20 MARTIN 30 SCOTT 20 SMITH 20 TURNER 30 WARD 30 69
Note: Union does not retrieve duplicate records. 3 UNION ALL SQL> SELECT ENAME,DEPTNO FROM T1 UNION ALL SELECT ENAME,DEPTNO FROM T3; ENAME DEPTNO ---------- ---------- CLARK 10 KING 10 MILLER 10 SMITH 20 JAMES 30 ALLEN 30 WARD 30 MARTIN 30 BLAKE 30 TURNER 30 JAMES 30
CLARK 10 SMITH 20 Note: Union all retrieves all the records. It retrieves duplicate records as well. 70
4 INTERSECT (T1 and T2) SQL> SELECT ENAME,DEPTNO FROM T1 INTERSECT SELECT ENAME,DEPTNO FROM T2; ENAME DEPTNO ---------- ---------- CLARK 10 JAMES 30 SMITH 20
Note: SET Operator Intersect displays only the common between the two/more tables. 5 MINUS (T1 and T2) SQL> SELECT ENAME,DEPTNO FROM T1 minus SELECT ENAME,DEPTNO FROM T2;
(Expression 1 MINUS Expression 2) ENAME DEPTNO ---------- ---------- KING 10 MILLER 10 Note: Minus Operator returns the records of Expression 1, which are not in Expression 2. It ignores the common records between Expression 1 and Expression 2. 6 MINUS (T2 and T1) SQL> SELECT ENAME,DEPTNO FROM T2 minus SELECT ENAME,DEPTNO FROM T1; ENAME DEPTNO ---------- ---------- ADAMS 20 FORD 20 JONES 20 SCOTT 20 71
7 MINUS (T3 and T1) SQL> SELECT ENAME,DEPTNO FROM T3 minus SELECT ENAME,DEPTNO FROM T1; ENAME DEPTNO ---------- ---------- ALLEN 30 BLAKE 30 MARTIN 30 TURNER 30 WARD 30
72
J OINS A join is a query that combines rows from two or more tables, views, or materialized views. Oracle Database performs a join whenever multiple tables appear in the FROM clause of the query. The select list of the query can select any columns from any of these tables. If any two of these tables have a column name in common, then you must qualify all references to these columns throughout the query with table names to avoid ambiguity. Join Conditions Most join queries contain at least one join condition, either in the FROM clause or in the WHERE clause. The join condition compares two columns, each from a different table. To execute a join, Oracle Database combines pairs of rows, each containing one row from each table, for which the join condition evaluates to TRUE. The columns in the join conditions need not also appear in the select list. To execute a join of three or more tables, Oracle first joins two of the tables based on the join conditions comparing their columns and then joins the result to another table based on join conditions containing columns of the joined tables and the new table. Oracle continues this process until all tables are joined into the result. wHERE clause that contains a join condition can also contain other conditions that refer to columns of only one table. These conditions can further restrict the rows returned by the join query. In the process of joins, oracle uses temporary segment to store the immediate result of the query processing. It compares each record of one table with every record of other table and merges those records if the conditions are satisfied. The results are stored in the temporary segment. 73
Obtaining Data from Multiple Tables
Sometimes you need to use data from more than one table. In the example, the report displays data from two separate tables. Employee IDs exist in the EMPLOYEES table. Department IDs exist in both the EMPLOYEES and DEPARTMENTS tables. Location IDs exist in the DEPARTMENTS table. To produce the report, you need to link the EMPLOYEES and DEPARTMENTS tables and access data from both of them.
Cartesian Products A Cartesian product is formed when: A join condition is omitted A join condition is invalid All rows in the first table are joined to all rows in the second table To avoid a Cartesian product, always include a valid join condition in a WHERE clause. Generating a Cartesian Product
74
Types of Joins Equijoin Non-equijoin Outer join Self join
Joining Tables Using Oracle Syntax
SELECT table1.column, table2.column FROM table1, table2 WHERE table1.column1 = table2.column2;
Write the join condition in the WHERE clause. 75
Prefix the column name with the table name when the same column name appears in more than one table.
Guidelines When writing a SELECT statement that joins tables, precede the column name with the table name for clarity and to enhance database access. If the same column name appears in more than one table, the column name must be prefixed with the table name. To join n tables together, you need a minimum of n-1 join conditions. For example, to join four tables, a minimum of three joins is required. This rule may not apply if your table has a concatenated primary key, in which case more than one column is required to uniquely identify each row. Equi-Join
An equijoin is a join with a join condition containing an equality operator. An equijoin combines rows that have equivalent values for the specified columns. Equijoins are also called simple joins or inner joins. Example
SELECT last_name, job_id, departments.department_id, department_name FROM employees, departments WHERE employees.department_id = departments.department_id;
Using Table Aliases Simplify queries by using table aliases. Improve performance by using table prefixes. Example
SELECT e.employee_id, e.last_name, e.department_id, d.department_id, d.location_id FROM employees e , departments d WHERE e.department_id = d.department_id;
Guidelines Table aliases can be up to 30 characters in length, but shorter is better. If a table alias is used for a particular table name in the FROM clause, then that table alias must be substituted for the table name throughout the SELECT statement. Table aliases should be meaningful. The table alias is valid only for the current SELECT statement. Joining More than Two Tables
77
To join n tables together, you need a minimum of n-1 join conditions. For example, to join three tables, a minimum of two joins is required.
Example
SELECT e.last_name, d.department_name, l.city FROM employees e, departments d, locations l WHERE e.department_id = d.department_id AND d.location_id = l.location_id;
SELECT empno,ename,sal,dname,loc FROM dept,emp WHERE dept.deptno = emp.deptno / SELECT empno,ename,sal,dept.deptno,dname,loc FROM dept,emp WHERE dept.deptno = emp.deptno / SELECT empno,ename,sal,d.deptno,dname,loc FROM dept d,emp e WHERE d.deptno = e.deptno /
78
Non-Equijoins
A non-equijoin is a join condition containing OPERATOR other than an equality operator. The relationship is obtained using an operator other than equals (=). Example
SELECT e.last_name, e.salary, j.grade_level FROM employees e, job_grades j WHERE e.salary BETWEEN j.lowest_sal AND j.highest_sal;
79
SELECT ename,sal,grade FROM emp,salgrade WHERE sal >= losal AND sal <= hisal /
Outer Joins In case of equijoin / non equijoin the records that satisfy the conditions are retrieved. If a row does not satisfy a join condition, the row will not appear in the query result. The missing rows can be returned if an outer join operator is used in the join condition. The operator is a plus sign enclosed in parentheses (+), and it is placed on the side of the join that is deficient in information. This operator has the effect of creating one or more null rows, to which one or more rows from the nondeficient table can be joined. Outer Joins Syntax You use an outer join to also see rows that do not meet the join condition. The Outer join operator is the plus sign (+).
SELECT table1.column, table2.column 80
FROM table1, table2 WHERE table1.column(+) = table2.column;
SELECT table1.column, table2.column FROM table1, table2 WHERE table1.column = table2.column(+);
Example
81
Outer Join Restrictions The outer join operator can appear on only one side of the expressionthe side that has information missing. It returns those rows from one table that has no direct match in the other table. A condition involving an outer join cannot use the IN operator In one single SELECT statement you can use the (+) operator in only one table and not on both tables.
SELECT empno,ename,sal,d.deptno,dname,loc FROM emp e, dept d WHERE d.deptno = e.deptno (+) /
Retrieve those departments which do not have any employees working in it SELECT d.* FROM dept d, emp e
SELECT e.last_name, e.department_id, d.department_name FROM employees e, departments d WHERE e.department_id(+) = d.department_id ;
82
WHERE d.deptno = e.deptno (+) AND empno IS NULL /
SELECT ename,sal,grade FROM emp,salgrade WHERE sal >= losal (+) AND sal <= hisal (+) /
Self Joins A self join is a join of a table to itself. You need to specify the same table multiple times using different aliases in the FROM clause While you use one copy for selection, other copies must be used for filtration
Example
83
SELECT worker.last_name || works for || manager.last_name FROM employees worker, employees manager WHERE worker.manager_id = manager.employee_id ;
SELECT Y.empno, Y.ename, Y.sal FROM emp X, emp Y WHERE Y.sal > X.sal AND X.ename = 'MARTIN' /
SELECT Y.empno, Y.ename, Y.sal FROM emp X, emp Y WHERE Y.deptno = X.deptno AND X.ename = 'FORD' /
SELECT Y.empno, Y.ename, Y.sal FROM emp X, emp Y 84
WHERE Y.deptno = X.deptno AND Y.ename != 'FORD' AND X.ename = 'FORD' /
SELECT z.empno, z.ename, z.sal FROM emp X, emp Y, emp z WHERE z.deptno = x.deptno AND X.ename = 'FORD' AND z.sal > y.sal AND y.ename = 'ADAMS' /
SELECT z.empno, z.ename, z.sal,z.deptno,d.dname,d.loc FROM emp X, emp Y, emp z,dept d WHERE z.deptno = x.deptno AND X.ename = 'FORD' AND z.sal > y.sal AND y.ename = 'ADAMS' AND z.deptno = d.deptno /
85
Sub-Queries 1. It is a query inside another query 2. A statement that contains sub-query is called as parent statement 3. It can be there in the FROM clause (called as inline view), WHERE clause (called as nested sub- query) 4. There is no limit on number of Sub-queries in the FROM clause but WHERE clause can have 255 levels of sub-queries 5. Sub-Query is executed only once for the entire parent statement, irrespective of # of records processed by the parent statement and they are executed prior to the execution of the parent statement (exception co-related sub-query) 6. Sub-Query can be used in SELECT, INSERT, UPDATE, DELETE, WHERE, HAVING etc.
SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename = 'MARTIN')
Retrieve those employees who are working in the same department and on same job as SMITH
SELECT * FROM emp WHERE (job,deptno) = (SELECT job,deptno FROM emp WHERE ename = 'SMITH') /
Working in same dept as Martin and earning more than Adams SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename = 'ADAMS') AND deptno = (SELECT deptno FROM emp WHERE ename = 'MARTIN') /
Earning more than any of dept 20 employees SELECT * FROM emp 86
WHERE sal >ANY (SELECT sal FROM emp WHERE deptno = 20) / SELECT * FROM emp WHERE sal > (SELECT MIN(sal) FROM emp WHERE deptno = 20) /
Earning more than ALL employees of dept 30 SELECT * FROM emp WHERE sal >ALL (SELECT sal FROM emp WHERE deptno = 30) / SELECT * FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30) /
Ex of FROM clause query
SELECT empno,ename,sal,e.deptno,sum_sal,total_emp,avg_sal FROM emp e, (SELECT deptno, SUM(sal) sum_sal, COUNT(empno) total_emp ,AVG(sal) avg_sal FROM emp GROUP BY deptno) d WHERE e.deptno = d.deptno /
SELECT empno,ename,sal,e.deptno,dname,loc,sum_sal,total_emp,avg_sal FROM emp e, 87
(SELECT deptno, SUM(sal) sum_sal, COUNT(empno) total_emp ,AVG(sal) avg_sal FROM emp GROUP BY deptno) d, dept d1 WHERE e.deptno = d.deptno AND d1.deptno = e.deptno /
UPDATE emp SET (sal, deptno) = (SELECT sal,deptno FROM emp WHERE ename = 'SCOTT') WHERE ename = 'BLAKE' /
INSERT INTO emp (empno,ename,sal,job,deptno) VALUES (1001, 'SACHIN', 10000, (SELECT job FROM emp WHERE ename = 'SCOTT'), (SELECT deptno FROM emp WHERE ename = 'SMITH')) /
Working on the same job as any of the employees of dept 20 SELECT * FROM emp WHERE job IN (SELECT job FROM emp WHERE deptno = 20) /
Select deptno, sum_sal & total no of employees where avg sal is greater than average sal of salesman
SELECT deptno, SUM(sal), COUNT(empno) FROM emp GROUP BY deptno 88
HAVING AVG(sal) > (SELECT AVG(sal) FROM emp WHERE job = 'SALESMAN') /
Display Average sal of deptno 20 as well
SELECT deptno, SUM(sal), COUNT(empno), avg_sal FROM emp, (SELECT AVG(sal) avg_sal FROM emp WHERE job = 'SALESMAN') GROUP BY deptno, avg_sal HAVING AVG(sal) > avg_sal
89
Co-Related Sub-Query 1. Oracle executes sub-query as co-related when Sub-query refers to the column of parent statement table 2. In such cases, execution of sub-query is done in parallel to the execution of parent statement, as well as sub-query is executed once for every record that is being processed in the parent statement
SELECT empno,ename,sal,deptno from emp e WHERE sal > (SELECT AVG(sal) FROM emp WHERE deptno = e.deptno) /
EXISTS Operator It evaluates the condition given in the parent statement to TRUE is sub-query returns one or more records else FALSE
Retrieve those employees who have employees reporting to them SELECT * FROM emp x WHERE EXISTS (SELECT * FROM emp WHERE mgr = x.empno) /
Retrieve those employees who have NO employees reporting to them SELECT * FROM emp x WHERE NOT EXISTS (SELECT * FROM emp WHERE mgr = x.empno) /
Departments which have employees working SELECT * FROM dept d WHERE EXISTS (SELECT 1 FROM emp WHERE deptno = d.deptno) / 90
Creating new table from existing table
Syntax CREATE TABLE <name> [(<column_names>) AS <SELECT statement>
To copy Structure and Data CREATE TABLE temp AS SELECT * FROM emp;
To copy Structure and NO Data
CREATE TABLE TEMP AS SELECT * FROM EMP WHERE 1=2 /
To copy structure with different column names and data CREATE TABLE temp (emp_no, emp_name, emp_sal, dno) AS SELECT empno,ename,sal,deptno FROM emp
91
INTEGRITY CONSTRAINTS
Data Integrity:- Data stored in the Database must be as per business rules. These Business rules guarantees are that Authentic and valid data is stored into the Database.
They are 2 mechanisms that are used to implement the Data Integrity: 1) INTEGRITY CONSTRAINTS 2) DATABASE TRIGGERS
NOTE:- CONSTRAINT means VALIDATION. NORMALIZATION means Reduce the Data Redundancy. CONSTRAINT has 2 attributes 1) CONSTRAINTS must be applied on the column of the TABLE. 2) Every CONSTRAINT must have the NAME and TYPE.
There are 5 types of Data Integrity Constraints. 1) NOT NULL 2) UNIQUE 3) PRIMARY KEY 4) FOREIGN KEY (REFERENCES-Referential Integrity Constraint) 5) CHECK
92
These constraints can be name uniquely and information of these constraints is stored in Data Dictionary. If you dont give you the name to the constraints ORACLE will internally generate the name that starts with sys underscore (SYS_). NOTE: - ORACLE always checks for NOT NULL constraints first. Then TABLE LEVEL and COLUMN LEVEL. DESC USER_CONSTRAINTS;
Can be used to retrieve the information about the constraints.
1. NOT NULL
a) It does not allow inserting NULL values into that column. b) It can be only at column level.
CREATE TABLE my_emp ( empno NUMBER (5) CONSTRAINT nn_myemp_empno NOT NULL, ename VARCHAR2 (30) );
Our own devised standard to provide the name is <type>_<table_name>_<column_name> SELECT * FROM USER_CONSTRAINTS; SELECT constraint_name, constraint_type FROM user_constraints;
nn_myemp_empno
nn ===> constraint type my_emp ===> table_name empno ===> column_name Example: 1 93
SELECT constraint_name, constraint_type FROM user_constraints WHERE table_name = MY_EMP' / INSERT INTO my_emp VALUES (1001,'ABC'); INSERT INTO my_emp VALUES (NULL,'PQR'); INSERT INTO my_emp VALUES (1001,'ABC'); INSERT INTO my_emp (ename) VALUES ('XYZ'); 2. UNIQUE
a) It does not allow duplicate values b) Oracle internally creates an UNIQUE INDEX on that column by the same name as the name on the constraint c) It can be applied at table level as well as column level d) It can be applied on two or more columns (composite UNQIE constraint) e) Composite UNIQUE constraint MUST BE applied at table level f) You can insert multiple NULLS in such columns
INSERT INTO my_emp VALUES (1001,'ABC'); INSERT INTO my_emp VALUES (NULL,'PQR'); INSERT INTO my_emp VALUES (1001,'ABC'); INSERT INTO my_emp (ename) VALUES ('XYZ');
-- Composite UNIQUE constraint CREATE TABLE order_tran ( ordno NUMBER (5), ino NUMBER (5), qty NUMBER (8), CONSTRAINT cuk_ordertran_ordnoino UNIQUE (ordno, ino) ); INSERT the following values and check which will work and which will not Sr. No Ordno Ino Qty 1 1001 5001 800 2 1001 5002 800 3 1001 5001 800 4 5001 1001 800 5 5001 1002 800 6 NULL NULL 800 7 5001 NULL 800 8 5001 NULL 800 Example: 3 96
9 NULL 5001 800 10 NULL 5001 800 11 NULL NULL 800
3. PRIMARY KEY
a) It is used to uniquely identify the records of the relational table b) There can be only one primary key per table c) Oracle implicitly does the following - Applies NOT NULL - Creates UNIQUE INDEX on the primary key (column(s)) d) Oracle does not allow duplicate values as well as NULLs for PRIMARY KEY e) It can be applied at table level as well as column level f) It can be composite. Oracle does not allow NULLs in any of the columns participating in composite PRIMARY KEY g) Composite Primary key MUST BE applied at Table Level
CREATE TABLE order_tran ( ordno NUMBER (5), ino NUMBER (5), qty NUMBER (8), CONSTRAINT cuk_ordertran_ordino PRIMARY KEY (ordno, ino) ); Try the following
a) FOREINGN KEY is the column(s) that refers to the values of the PARENT KEY. b) PARENT KEY should have either UNIQUE or PRIMARY KEY constraint. c) Referential Integrity rules guarantees that this PARENT/CHILD relationship is preserved. d) It can be applied at table level as well as column level. e) FOREIGN KEY can be composite and should refer to composite parent key having same number of columns and data type. f) Table that contains parent key is called as parent table and the table that contain foreign key is called as child table. g) If foreign key refers to the parent key of the same table then it is called as "self referential integrity". h) Can insert NULLS. i) You need to use CASCADE CONSTRAINTS option along with DROP TABLE to drop the parent table. In this case, Oracle will DROP all foreign keys towards this parent table and then will drop the parent table. Child Table structure and data will remain. DROP TABLE <name> CASCADE CONSTRAINTS; 99
-- Column Level
CREATE TABLE my_dept ( dname VARCHAR2 (15), loc VARCHAR2 (25), deptno NUMBER (5) CONSTRAINT pk_mydept_deptno PRIMARY KEY );
CREATE TABLE my_emp ( empno NUMBER (10), ename VARCHAR2 (25), deptno NUMBER (5) CONSTRAINT fk_myemp_deptno REFERENCES my_dept (deptno) ); -- giving column name is optional. In absence of column name, by default FK will refer to Primary KEY of that table. -- Table Level
Statement Issued against Parent Table Issued against Child Table INSERT Always OK OK. Only if it matches with Parent Key or it is NULL UPDATE [RESTRICT] OK only if parent key is not referred by the FK Same as above DELETE [RESTRICT] Same as above Always OK DELETE CASCADE Always OK Always OK
101
Note: If FK is defined using ON DELETE CASCADE then when you DELETE records from Parent Table, all records from Child Table also will be deleted --Self Referential Integrity
CREATE TABLE my_emp ( empno NUMBER (5) PRIMARY KEY, ename VARCHAR2 (25), deptno NUMBER (2), mgr NUMBER (5) CONSTRAINT fk_myemp_mgr REFERENCES my_emp );
CREATE TABLE my_emp ( empno NUMBER (5) PRIMARY KEY, ename VARCHAR2 (25), deptno NUMBER (2), mgr NUMBER (5) CONSTRAINT fk_myemp_mgr REFERENCES my_emp, CONSTRAINT fk_myemp_deptno FOREIGN KEY (deptno) REFERENCES my_emp Example: 3 Example: 4 T h i s
t a b l e
h a s
2
F O R E I G N
K E Y s
102
);
Assume that you have empno and MGR starting with 1000 and then give following statement. Magic to be researched by students UPDATE my_emp SET empno=empno+4000, mgr =mgr+4000 Try out one example of composite FK? Also find out if one column can have multiple Parent Keys i.e. can you have multiple FK constraints one column? 5. CHECK
a) It allows you to check the conditions given in the CHECK constraint b) If condition is evaluated to TRUE DML operation is allowed else Oracle will return an error c) It can be defined at column level as well as table level d) CHECK constraint can be Multi-Column but all these columns MUST belong to the same table and it should be defined at table level e) SQL functions can be used in CHECK constraint (except for SYSDATE and group functions)
sal NUMBER (6) CONSTRAINT chk_myemp_sal CHECK (sal>1000) ); INSERT INTO my_emp VALUES (1001,'ABC', 5600); INSERT INTO my_emp VALUES (1001,'ABC', 900); INSERT INTO my_emp VALUES (1001,'ABC', NULL); INSERT INTO my_emp VALUES (1001,'ABC', 0);
CREATE TABLE my_emp ( empno NUMBER (5), ename VARCHAR2 (25), sal NUMBER (6) CONSTRAINT chk_myemp_sal CHECK (sal>1000), comm NUMBER (6, 2), CONSTRAINT chk_myemp_salcomm CHECK (sal>comm) Example: 2 104
); INSERT INTO my_emp VALUES (1001,'ABC', 1500, 600); INSERT INTO my_emp VALUES (1001,'ABC', 900, 600); INSERT INTO my_emp VALUES (1001,'ABC', 500,600); INSERT INTO my_emp VALUES (1001,'ABC', NULL, 600); INSERT INTO my_emp VALUES (1001,'ABC', NULL, NULL);
Adding Integrity constraints to existing tables
1. ALTER TABLE statement can be used to add the integrity constraints 2. ADD clause is used to add the table level constraints 3. MODIFY clause is used to add the column level constraints 4. Addition of constraint will result in an error if existing data is violating the same
Syntax
1. to add table level constraints
ALTER TABLE <table_name> ADD (<constraint_details> . . )
105
2. To add column level constraints
ALTER TABLE <table_name> MODIFY (<column_name> <data_type> [(<length>)] < constraint_details> . . ) Create the following table CREATE TABLE temp ( empno NUMBER (5), ename VARCHAR2 (25), sal NUMBER (5), comm NUMBER (5, 2), deptno NUMBER (2) ); Add the following constraints to the above table 1. Empno should be primary key 2. ename should be in upper case 3. sal should not null 4. sal should be greater than comm. 5. deptno should be foreign key referring to the deptno of my_dept table
ALTER TABLE temp ADD (CONSTRAINT chk_temp_ename CHECK (ename = UPPER (ename)), CONSTRAINT chk_temp_sal CHECK (sal > comm)) / ALTER TABLE temp MODIFY (sal NUMBER (5) CONSTRAINT nn_temp_sal NOT NULL) /
ALTER TABLE temp ADD (CONSTRAINT chk_temp_sal CHECK (sal > comm)) / ALTER TABLE temp ADD CONSTRAINT fk_temp_deptno FOREIGN KEY (deptno) REFERENCES my_dept / Note: When you create a table from another table using CREATE TABLE .AS.. Syntax, Oracle will copy only NOT NULL constraint from the source table to the target table with system generated name.
CREATE TABLE t1 AS SELECT * FROM temp;
DESC temp DESC t1
107
SELECT constraint_name, constraint_type FROM user_constraints WHERE table_name = T1 /
How to add a new column having NOT NULL constraint 1. Add a column 2. update the values for the existing rows 3. Add NOT NULL constraint using ALTER TABLE.MODIFY
Enable / Disable and Drop Integrity constraints
Syntax ALTER TABLE <table_name> DISABLE|ENABLE|DROP CONSTRAINT <name>
1. You can disable the Integrity constraints. So that oracle does not check the constraints whenever DML operations are performed. 2. Later on whenever you need you can Enable/Disable Integrity constraints. 3. At that time when youre enabling the constraints all the data of that column will be check against the constraint that we are enabling. 4. If any of the record is violating the Integrity constraint then constraint wont be allow enable/disable. 5. You may want to disable Integrity constraints in the following situations. 108
5.1 When you want to load major chunk of data and you want to save time of checking Integrity constraints. You can disable the constraints and later on enable it when loading of data is complete and monitoring is not required. 5.2 When you know that the data is loading is the transaction on performing is Inserting, Updating or deleting the data which is violating the constraints. But you want allow the data to get loaded or perform the transaction. Later on you want to correct the data and enable the Integrity constraints.
TO DROP PRIMARY KEY ALTER TABLE <name> DROP PRIMARY KEY; Note: o You cannot drop the parent table unless you mention the CASCADE CONSTRAINTS clause. o When you drop the parent table using this clause, Oracle will drop all the referential integrity constraint towards this table and then drop the table
DROP TABLE my_dept CASCADE CONSTRAINTS;
109
INDEX
1. Index is a stores schema object 2. Indexes are used to improve the performance of SELECT statement. 3. When INDEXES are created Oracle allocates INDEX Segment to store the data of that INDEX. 4. INDEX segment stores value of an INDEX KEY along with the ROWID. 5. INDEX KEY can be composite. 6. There can be only one INDEX on one INDEX KEY. 7. INDEXES can be used only when INDEX KEY is used in filter conditions (WHERE Clause). 8. In such cases Oracle loads INDEX segment into Database Buffer Cache and also uses binary search to filter the INDEX KEY. Once the INDEX KEY found it takes the ROWID of that matching INDEX key and loads only those records from the data segment. 9. Thus INDEXES improve the performance by minimizing I/O (input/output) and reducing search time. 10. Oracle recommends creating INDEXES only on those columns that are frequently used in filter conditions. Because having too many INDEXES reduces the performance of DML operations. Since INDEXES are maintained internally by oracle. Oracle has to update underlying INDEXES whenever DML statements are performed on the table. SGA (Shared / System) Global Area Database Buffer Cache Redolog Buffer Cache Shared Pool Session 1 Session 2 Session 3 Data Files (Hard Disk) 110
11. INDEX KEY can store duplicate values. If you dont want INDEX KEY to store duplicate values then you can create UNIQUE INDEXES. 12. Oracle corporation recommends you not to create UNIQUE INDEX instead apply UNIQUE constraint. 13. Information about INDEXES which is stored in the Data dictionary can be retrieved from USER_INDEXES. SELECT index_name, index_type, uniqueness FROM user_indexes WHERE table_name=EMP; SYNTAX : CREATE INDEX <name> ON <table name> (<column name(s)>) Example:- CREATE INDEX ind_empno ON emp (empno);
DROP INDEX <index name>; Examples:- DROP INDEX ind_empno; CREATE UNIQUE INDEX ind_empno ON emp(empno); CREATE INDEX ind_dnodname ON dept(deptno, dname); CREATE INDEX ind_dno ON dept(deptno); CREATE INDEX ind_dnamedno ON dept(deptno, dname); Even if you give unique name for index, for the same columns which are already indexed. I t will give error as such column list already indexed CREATE INDEX ind_dnamedno ON dept(dname, deptno); We can create index by changing the sequence/order of columns
111
Views 1. It is a (schema object) stored query/virtual table 2. It does not contain the data and hence there is no storage space consumed by the views 3. It derives the data from the base table 4. You can perform DML/SELECT operations on the views, which in turn are executed (internally) on the base table of the view (by Oracle) 5. View does have it's own data structure, but you can not alter the same using ALTER statement Syntax
CREATE VIEW <name> AS <SELECT statement> Information of the views can be retrieved from user_views
SELECT text FROM USER_VIEWS WHERE view_name = '<view_name>';
VIEWS BASED ON expressions CREATE VIEW v1 AS SELECT empno, ename, sal+2000 bonus, deptno FROM emp;
Note: Column alias MUST BE used for the expressions else Oracle will give an error
INSERT INTO v1 values (1005,'YUVRAJ',8000,30) / UPDATE v1 SET bonus = bonus + 4000 / The above statements will result in an error because; bonus is a virtual column and not there in the base table emp.
112
VIEWS BASED ON GROUP BY clause CREATE VIEW v1 AS SELECT deptno, SUM(sal) sum_sal, COUNT(empno) total_emp, MIN(sal) min_sal, MAX(sal) max_sal, AVG(sal) avg_sal FROM emp GROUP BY deptno;
VIEWS BASED ON WHERE CLAUSE (Record filters)
CREATE VIEW v1 AS SELECT * FROM emp WHERE deptno = 10 WITH CHECK OPTION / WITH CHECK OPTION can be used if you want Oracle to check the given WHERE clause during INSERT operation as well
READ ONLY VIEWS
Once you create the view as READ ONLY, you can not perform any operations other than SELECT
CREATE VIEW v1 AS SELECT * FROM emp WITH READ ONLY 113
To find out which columns can be used in DML, you can use the following query
SELECT column_name, updatable, insertable, deletable FROM user_updatable_columns WHERE table_name = 'V1' /
VIEWS BASED ON JOINS CREATE VIEW v1 AS SELECT empno, ename, sal, d.deptno, dname, loc FROM my_emp e, my_dept d WHERE e.deptno = d.deptno / 1. When views are having more than one base tables then you can perform the DML operations only on key preserve tables (and their columns) and not on the NON-Key preserved table 2. In the process of join, if the table gets duplicate rows then that is NON key preserved table 3.
VIEWS BASED ON other views CREATE VIEW v1 AS SELECT * FROM emp / CREATE VIEW v2 AS SELECT empno, ename, sal, deptno FROM v1 / 114
CREATE VIEW v3 AS SELECT empno, deptno FROM v2 /
In the above case, you perform DML, SELECT operation on any view, data will be modified/retrieved from single base table
VIEWS BASED ON NON EXISTING OBJECTS
CREATE FORCE VIEW v1 AS SELECT * FROM temp / SQL> SHOW ERROR VIEW V1
1. When you create the view with FORCE option, ORACLE allows you to create a view but then that view is in INVALID state 2. You can not perform any operations on INVALID objects
The following query can be used to find out the state of the object SELECT status FROM user_objects WHERE object_name = 'V1' / 3. These views can be brought to the VALID state only by creating the base tables and compiling those views or by performing any operation on these views 4. To compile the views, you can use a. ALTER VIEW <name> COMPILE 115
b. Perform any operation on that view so that ORACLE will internally compile the same
IMP NOTES 1. When you perform ALTER TABLE statement on the base table of the view, it will go in INVALID state 2. Any new columns added after the view was created successfully will not be available when you recompile the view 3. Changes made to the columns of the table that are SELECTed for the view will be available for the view 4. When you DROP the table, view will go in INVALID state
USE of views 1. Query Simplicity You can write the complex queries only once to create the view and then after simple queries on the view. This way it helps to speed up the development process, improves the quality and also saves the maintenance efforts 2. Security You hide the base table from the user of the view. Also by creating the READ ONLY views or views based on record filters, you can restrict the access to the data based as per the users
116
PL/SQL
1. PL/SQL is a programming language that combines both data manipulation and data processing power. 2. It is used to store the business logic at database server side in the form of PL/SQL stored programs units. 3. It is a block structured programming language.
Declaration Block
Execution Block Notes: All statements must be terminated by semicolon (;) -- For single comment. /* ___________________ _____________________ Multiple comment line */ 4. It supports all SEQUEL data types as well as it has its own 3 data types.
Notes: BINARY_INTEGER just like NUMBER data type in SQL. BOOLEAN like TRUE, FALSE and NULL. Exception handling session is used to handle the runtime errors. DBMS_OUTPUT.PUT_LINE (<string>)It is debug print SET SERVEROUTPUT ONto get output from server. : = For assigning value to Variable. & (Ampersand) execute the before Compilation.
Role of PL/SQL
It is used to implement the business logic in the form of stored sub programs, packages and database triggers. PL/SQL code is used to process and manipulate the data as per the business rules. PL/SQL code is not used to interact with the end users. End user interaction is handled by the application program. When stored in the database PL/SQL code is not executed implicitly by oracle unless you call or execute it. Business logic is stored at the database server side.
118
PL/SQL Engine has 2 parts 1. Compiler 2. Executor Compiler compiles the entire PL/SQL block and generates the object code. Compilation starts from the first line of the declaration session to the last line of the executable session. An executor executes the code as per the compiled object code. Execution always starts from the first line of the executable session and will continue the execution one by one. During execution if it finds the SEQUEL statements it is send to the database engine for execution. And the control will wait for database engine response and executes the next line, if the response is received with out any error. If the response receives with an error then instead of executing the next line control will go to the exception handler.
Programs (Anonymous or no named PL/SQL blocks)
-- This is my first program to learn basics of pl/sql BEGIN DBMS_OUTPUT.PUT_LINE ('Welcome to PLSQL'); END; / -- The below program teaches you to declare the variable, assign value and display that value on screen
DECLARE V_temp NUMBER (5); BEGIN 119
v_temp:= 5000; DBMS_OUTPUT.PUT_LINE ('Value of temp is: '||v_temp); END; -- It will give an error because v_temp is a constant and its value cannot be changed.
DECLARE V_temp CONSTANT NUMBER (5); BEGIN V_temp:= 5000; DBMS_OUTPUT.PUT_LINE ('Value of temp is: '||v_temp); END; /
-- Declaration of a constant v_temp must contain an initialization assignment. Expression v_temp cannot be used as an assignment target because v_temp is a constant. DECLARE v_temp CONSTANT NUMBER (5) := 5000; BEGIN DBMS_OUTPUT.PUT_LINE (v_temp); END;
-- The below program teaches you to declare the variable, accept the value on the prompt and display that value on screen DECLARE v_temp NUMBER (5); BEGIN v_temp:= &temp; DBMS_OUTPUT.PUT_LINE ('Value of Temp is: ' || v_temp); 120
END;
-- Write a program which will accept the emp name on the prompt get the empno and salary of that employee from emp table, and display the empno and sal on the screen DECLARE v_ename VARCHAR2 (25); v_empno NUMBER (5); v_sal NUMBER (5); BEGIN v_ename:= '&Ename'; -- Retrieving the employee details from emp table SELECT empno, sal INTO v_empno, v_sal FROM emp WHERE ename = v_ename; -- displaying those retrieved values DBMS_OUTPUT.PUT_LINE (v_empno || ' ' || v_sal); END; %TYPE
The above code may have to under go a change if there is change in the structure of the table and either data type of length of the column is changed. That is because you are storing the values of those columns into the PL/SQL variables and these variables should be of the same data type and length else storing of the values may result in an error. Use of %TYPE guarantees that the data type and length of such PL/SQL variables can be derived at run time and based on data type and length of the columns 121
To decide the data type and length dynamically by oracle we use %TYPE
-- Write a program which will accept the emp name on the prompt get the empno and salary of that employee from emp table and display the empno and sal on the screen
DECLARE v_ename emp. ename %TYPE; v_empno emp. empno %TYPE; v_sal emp.sal %TYPE; BEGIN v_ename:= '&Ename'; -- Retrieving the employee details from emp table SELECT empno, sal INTO v_empno, v_sal FROM emp WHERE ename = v_ename; -- displaying those retrieved values DBMS_OUTPUT.PUT_LINE (v_empno || ' ' || v_sal); END;
-- Write a program that will accept the emp name and increment amount on the prompt, increases the salary by the given amount and displays the salary after increment
v_ename emp. ename %TYPE; BEGIN v_incr_amt:= &amount; v_ename := '&ename'; UPDATE emp SET sal = sal + v_incr_amt WHERE ename = v_ename; SELECT sal INTO v_sal FROM emp WHERE ename = v_ename; -- displaying those retrieved values DBMS_OUTPUT.PUT_LINE ('Salary after increment: ' || v_sal); COMMIT; END; / RETURNING Clause 1. This is an extension to the DML statement 2. This can be used to get the values of the record manipulated by the DML statement. 3. This eliminates the use of SELECT statement After UPDATE or INSERT and Before DELETE statement 4. Helps to increase the performance of the code by reducing the context switch between database engine and PL/SQL engine as well as reducing the need to process the same tables two times i.e. ones for executing DML and again for SELECT statement.
DECLARE v_incr_amt NUMBER (5); v_sal emp.sal %TYPE; v_ename emp. ename %TYPE; BEGIN v_incr_amt:= &amount; v_ename := '&ename'; UPDATE emp SET sal = sal + v_incr_amt WHERE ename = v_ename RETURNING sal INTO v_sal; -- displaying those retrieved values DBMS_OUTPUT.PUT_LINE ('Salary after increment: ' || v_sal); COMMIT; END;
Example: 1 (UPDATE) 123
DECLARE v_empno emp. empno %TYPE; v_sal emp.sal %TYPE; BEGIN DELETE FROM emp WHERE ename = '&ename' RETURNING empno, sal INTO v_empno, v_sal; -- displaying those retrieved values DBMS_OUTPUT.PUT_LINE ('deleted record values are: ' || v_empno || ' ' || v_sal); END;
DECLARE v_ename emp.ename %TYPE; BEGIN v_ename:='&ename'; INSERT INTO emp (empno, job, mgr, sal, comm) VALUES (1111,'DEVELOPER', 7965, 1000, 20) RETURNING ename INTO v_ename; DBMS_OUTPUT.PUT_LINE (v_ename); COMMIT; END;
Example: 2 (DELETE) Example: 3 (INSERT) 124
%ROWTYPE
1) Variable of %ROWTYPE will be composite and will contain <n> (as many as columns there in the table) number of member variables. 2) To access these member variables you have to precede the name of such variables before their member name <rowtype_variable>.<member_variable>
-- Example to understand use of %ROWTYPE
DECLARE v_row emp %ROWTYPE; BEGIN SELECT * INTO v_row FROM emp WHERE empno = &empno; V_ROW empno ename
deptno job sal
Example: 1 06-Nov-2011 125
-- displaying those retrieved values DBMS_OUTPUT.PUT_LINE ( v_row. Empno || ' '|| v_row. Ename || ' '|| v_row.sal || ' '|| v_row.job || ' '|| v_row. Deptno ); END; In case number of columns selected in the SELECT Statement and number of member variables therein the ROWTYPE variable dont match ORACLE will generate an error. As well as the sequence of columns and member variables should match in terms of datatype and length, if it does not then ORACLE will generate an error. To avoid above errors you need to individually mention the member variables in INTO clause. DECLARE v_row emp %ROWTYPE; BEGIN SELECT empno, ename, sal, deptno INTO v_row. empno, v_row. ename, v_row.sal, v_row. deptno FROM emp WHERE empno = &empno; -- displaying those retrieved values DBMS_OUTPUT.PUT_LINE ( v_row. empno || ' '|| v_row. ename || ' '|| v_row.sal || ' '|| v_row. Deptno ); END;
Example: 2 126
User Defined data types In Oracle there are two types of datatypes 1. Scalar 2. Composite Variable of scalar type store a single value but variable of composite data type will contain the members who will store the value of specific data types. Note: 1. All SQL data types are scalar types 2. Variable of composite types contains other member variables which can contain values of different data types.
RECORD Types
1. Users can create their own data types using RECORD Types. 2. These types can be used in a program to declare the variables etc.
-- Example to understand RECORD Types
DECLARE TYPE emp_ty IS RECORD ( empno emp. empno %TYPE, ename emp. ename %TYPE, sal emp.sal %TYPE, deptno emp. deptno %TYPE ); v_row emp_ty; Example: 1 127
BEGIN SELECT empno, ename, sal, deptno INTO v_row FROM emp WHERE empno = &empno; -- displaying those retrieved values DBMS_OUTPUT.PUT_LINE ( v_row. empno || ' '|| v_row. ename || ' '|| v_row.sal || ' '|| v_row. deptno ); END;
DECLARE TYPE emp_ty IS RECORD ( empno emp.empno %TYPE, ename emp.ename %TYPE, sal emp.sal %TYPE, deptno emp.deptno %TYPE, comm emp.comm %type, gross number (7,2) ); v_row emp_ty; BEGIN SELECT empno, ename, sal, deptno, comm, sal + NVL (comm,0) INTO v_row FROM emp WHERE empno = &empno; Example: 2 128
1. Variable of one record type is declared as member of another record type
-- Example to understand Nested RECORD Types DECLARE TYPE emp_ty IS RECORD ( Empno emp. empno %TYPE, V_ROW dname loc emp_det empno ename sal deptno 129
ename emp. ename %TYPE, sal emp.sal %TYPE, deptno emp. deptno %TYPE ); TYPE dept_ty IS RECORD ( dname dept.dname %TYPE, loc dept.loc %TYPE, emp_det emp_ty ); v_row dept_ty; BEGIN SELECT dname, loc, empno, ename, sal, e.deptno INTO v_row. dname, v_row.loc, v_row.emp_det.empno, v_row.emp_det.ename, v_row.emp_det.sal, v_row.emp_det.deptno FROM emp e, dept d WHERE e.deptno = d.deptno AND empno = &empno; -- displaying those retrieved values
IF <condition> THEN <Pl/sql statements> [ELSIF <condition> THEN <Pl/sql statements>] [ELSE <Pl/sql statements>] END IF; -- Write a program that will accept empno on the prompt, retrieve the job of that given employee, and increment the salary as per the below formula - ANALYST -> 20%, MANAGER -> 21%, CLERK ->16%, SALESMAN ->18%, others -> 15%-- revised salary DECLARE v_job emp.job %TYPE; v_empno emp.empno %TYPE: = &empno; v_sal emp.sal %TYPE; v_percent NUMBER (2); BEGIN SELECT job INTO v_job FROM emp WHERE empno = v_empno; IF v_job = 'ANALYST' THEN v_percent:= 20; ELSIF v_job = 'MANAGER' THEN v_percent:= 21; 131
ELSIF v_job = 'CLERK' THEN v_percent:= 16; ELSIF v_job = 'SALESMAN' THEN v_percent:= 18; ELSE v_percent:= 15; END IF; UPDATE emp SET sal = sal + (sal*v_percent/100) WHERE empno = v_empno RETURNING sal INTO v_sal; DBMS_OUTPUT.PUT_LINE ('Record Updated. Salary is: ' || v_sal); END;
LOOP Structure
1. It is used when you want to execute same set of statements again and again till the condition satisfies 2. The following is the LOOP structure used in Oracle.
Loop .. Syntax: LOOP <Pl/sql statements> END LOOP;
DECLARE Types of LOOPs 1. LOOP 2. WHILE LOOP 3. FOR LOOP 132
v_temp NUMBER (2):= 2; BEGIN DBMS_OUTPUT.PUT_LINE ('Starting of loop'); LOOP DBMS_OUTPUT.PUT_LINE (v_temp); v_temp:= v_temp + 2; IF v_temp > 20 THEN EXIT; END IF; END LOOP; DBMS_OUTPUT.PUT_LINE ('End of Loop'); END;
You can use conditional EXIT instead of IF DECLARE v_temp NUMBER (2):= 2; BEGIN DBMS_OUTPUT.PUT_LINE ('Starting of loop'); LOOP DBMS_OUTPUT.PUT_LINE (v_temp); v_temp:= v_temp + 2; EXIT WHEN v_temp > 20; END LOOP; DBMS_OUTPUT.PUT_LINE ('End of Loop'); END; WHILE LOOPSyntax WHILE <condition> LOOP <pl/sql statement> END LOOP; Example: 1 Example: 2 133
DECLARE v_temp NUMBER (2):= 2; BEGIN DBMS_OUTPUT.PUT_LINE ('Starting of loop'); WHILE v_temp <= 20 LOOP DBMS_OUTPUT.PUT_LINE (v_temp); v_temp:= v_temp + 2; END LOOP; DBMS_OUTPUT.PUT_LINE ('End of Loop'); END; FOR LOOPSyntax
FOR <expr> IN [REVERSE] <val1>...<val2> LOOP <pl/sql statements> END LOOP;
1. <expr> is declared for the scope of FOR LOOP. Outside the body of the loop this expression can not be accessed 2. <expr> is initialized by the value given in <val1> and will continue till it's value is less than equal to the value given in <val2> 3. After each successive execution of the loop body value of <expr> is incremented by 1 BEGIN FOR i IN 1...10 LOOP DBMS_OUTPUT.PUT_LINE (i); END LOOP; DBMS_OUTPUT.PUT_LINE ('End of Loop'); END; Note: You cannot assign value to the expression. It is READ ONLY for you. Example: 1 134
BEGIN FOR i IN 1...10 LOOP DBMS_OUTPUT.PUT_LINE (i); i: = i + 1; END LOOP; DBMS_OUTPUT.PUT_LINE ('End of Loop'); END; Note: You can have same name for <expr> and variable declared in the PL/SQL block. In this case, when you refer to that name inside FOR, local <expr> will take the higher precedence. To override this, you can use the labels. <<main>> DECLARE i NUMBER (3) := 100; BEGIN FOR i IN 1..10 LOOP DBMS_OUTPUT.PUT_LINE (i); main.i:= main.i + 1; END LOOP; DBMS_OUTPUT.PUT_LINE ('End of Loop: ' || i); END; Note: Sub.Iwill create an error as the I (variable) on the for loop can not be accessed out side the loop.
135
<<main>> DECLARE I NUMBER: = 100; BEGIN <<sub>> FOR I IN 1...10 LOOP DBMS_OUTPUT.PUT_LINE (inside loop: '||main.I); END LOOP; DBMS_OUTPUT.PUT_LINE (outside loop: '|| sub.i); END; Use OF reverse <expr> is initialized by the value given in <val2> and will continue till its value is greater than equal to the value given in <val1>. Value is decreased by 1
BEGIN FOR i IN REVERSE 1...5 LOOP DBMS_OUTPUT.PUT_LINE (i); END LOOP; END;
LABELS and GOTO statemements DECLARE V_temp NUMBER (5):= 100; BEGIN DBMS_OUTPUT.PUT_LINE ('In Block'); <<abc>> 136
DBMS_OUTPUT.PUT_LINE ('In Side Label abc'); DBMS_OUTPUT.PUT_LINE ('Value of temp is: '||v_temp); <<pqr>> V_temp:= 500; Goto xyz; <<cab>> DBMS_OUTPUT.PUT_LINE ('Value of temp in cab is: '||v_temp); <<xyz>> DBMS_OUTPUT.PUT_LINE ('In xyz value is: '||v_temp); <<pac>> DBMS_OUTPUT.PUT_LINE ('In pac value is: '||v_temp); END; Dry run the following program and find out the output BEGIN DBMS_OUTPUT.PUT_LINE (before main loop'); <<mainloop>> FOR i IN 1...5 LOOP DBMS_OUTPUT.PUT_LINE (i); DBMS_OUTPUT.PUT_LINE (before sub loop'); <<subloop>> FOR k IN 10...15 LOOP DBMS_OUTPUT.PUT_LINE (k); EXIT mainloop WHEN i > 3; END LOOP; DBMS_OUTPUT.PUT_LINE (after sub loop'); END LOOP; DBMS_OUTPUT.PUT_LINE (after main loop'); END;
Nested PL/SQL blocks
1. It is a block inside another block, In PL/SQL one block can reside in another block. 2. The block that is resides inside another block is called as nested, child or sub block. 137
3. The block that contains another block is called as parent or super block. 4. Nested block can any where between BEGIN and END
The following points are important when nested PL/SQL blocks are used 1) Declaration made inside parent block can be accessed by the statements issued in the nested block. 2) Declaration made inside nested block can not be accessed by the statements given in the parent block 3) If the parent block as well as the nested block has the declaration by the same name then the statements issued in the nested block will access the local nested block declaration (OR) 4) Local declarations will always have higher precedence then the global declaration. In such cases, to access parent block declarations inside nested blocks labels can be used NOTE: Labels can be used to over ride the precedence. Variables declared in the parent block can be accessed by the nested block.
Variables declared in the nested block cannot be accessed by the parent block
1. PL/SQL table is a collection of multiple elements of same data type 2. Each element can be accessed using subscript or index number which is stored along with the actual value 3. First you need to create INDEX by(PL/SQL table type) and then the variable of that is created and this variable is called as PL/SQL table. 4. There is no limit on the number of elements PL/SQL table can contain. DECLARE TYPE tab_marks IS TABLE OF NUMBER (3) INDEX BY BINARY_INTEGER; marks tab_marks; BEGIN FOR i IN 1...10 LOOP 140
marks (i):= i; END LOOP; DBMS_OUTPUT.PUT_LINE ('Printing the Values of PLSQL table ' ||marks.COUNT); FOR i IN 1...marks.COUNT LOOP DBMS_OUTPUT.PUT_LINE (marks (i)); END LOOP; END;
Write a program to retrieve salary of all employees, store into PL/SQL table a then display on the screen from that PL/SQL table
DECLARE TYPE tab_sals IS TABLE OF emp.sal%TYPE INDEX BY BINARY_INTEGER; v_sals tab_sals; CURSOR cur_sal IS SELECT sal FROM emp; i NUMBER: = 1; BEGIN FOR rec_sal IN cur_sal LOOP v_sals (i):= rec_sal.sal; i: = i + 1; END LOOP; DBMS_OUTPUT.PUT_LINE ('Printing the saalry stored in PLSQL table ' ||v_sals.COUNT); FOR k IN 1...v_sals.COUNT LOOP DBMS_OUTPUT.PUT_LINE (v_sals (k)); END LOOP; END;
DECLARE TYPE emp_ty IS RECORD ( empno NUMBER (5), ename VARCHAR2 (25), 141
sal NUMBER (5) ); TYPE emp_tab IS TABLE OF emp_ty INDEX BY BINARY_INTEGER; v_emps emp_tab; CURSOR c1 IS SELECT empno, ename, sal FROM emp; I NUMBER: = 1; BEGIN FOR r1 IN c1 LOOP v_emps (i).empno:= r1.empno; v_emps (i).ename:= r1.ename; v_emps (i).sal := r1.sal; i: = i+1; END LOOP; FOR k IN 1...v_emps.COUNT LOOP DBMS_OUTPUT.PUT_LINE ( v_emps (k).empno||' '|| v_emps (k).ename||' '|| v_emps (k).sal ); END LOOP; END;
142
Cursors
1. It is a handle (pointer) to the work area that stores records (data) 2. It is required when there is a need to process more than one record 3. Using this handle, programmer can write a code to process records one by one 4. There are two types of Cursors a. IMPLICIT b. EXPLICIT
IMPLICIT It is used by Oracle to process DML operations. It stores all those records that are processed by the DML statement. If DML statement has not processed/manipulated any records then work area will be empty
EXPLICIT 1. It has a SELECT statement associated with it 2. Records retrieved by the SELECT statement are stored in the work area pointed by the explicit cursor 3. Using this handle/pointer programmer can process records one by one 4. There are two types of explicit cursors a. STATIC SELECT statement associated with this cursor is fix and does not change at run time b. REF SELECT statement associated with this cursor can change at run time
STATIC Cursor
Syntax CURSOR <name> [(<parameters>)] IS <SELECT statement>
Example -- This program is to learn the syntax and working a Cursor
143
DECLARE CURSOR cur_emp IS SELECT * FROM emp; v_row emp%ROWTYPE; BEGIN OPEN cur_emp; LOOP FETCH cur_emp INTO v_row; EXIT WHEN cur_emp%NOTFOUND; DBMS_OUTPUT.PUT_LINE(v_row.empno || ' '|| v_row.ename || ' '|| v_row.sal || ' '|| v_row.deptno); END LOOP; CLOSE cur_emp; END; /
CURSOR Attributes
1. CURSOR has four attributes a. FOUND Returns TRUE is FETCH is successful (explicit) or there are records in the work area (Implicit) b. NOTFOUND - Returns TRUE is FETCH is NOT successful (explicit) or there are NO records in the work area (Implicit) c. %ROWCOUNT Gives current record number d. %ISOPEN Returns TRUE if CURSOR is opened else returns FALSE
Note: %ROWTYPE can be used for the cursor as well
144
DECLARE CURSOR cur_emp IS SELECT empno,ename,sal,deptno FROM emp; v_row cur_emp%ROWTYPE; BEGIN OPEN cur_emp; LOOP FETCH cur_emp INTO v_row; EXIT WHEN cur_emp%NOTFOUND; DBMS_OUTPUT.PUT_LINE(cur_emp%ROWCOUNT ||' '|| v_row.empno || ' '|| v_row.ename || ' '|| v_row.sal || ' '|| v_row.deptno); END LOOP; CLOSE cur_emp; END; /
CURSOR FOR Loop -- This program is to learn the syntax and working a Cursor using FOR LOOP
DECLARE CURSOR cur_emp IS SELECT empno,ename,sal,deptno FROM emp; BEGIN FOR v_row IN cur_emp LOOP DBMS_OUTPUT.PUT_LINE(v_row.empno || ' '|| 145
v_row.ename || ' '|| v_row.sal || ' '|| v_row.deptno); END LOOP; END; 1. In the above example, CURSOR cur_emp is opened only once at the start of the FOR LOOP irrespective of total number of times loop body is executed 2. Cursor remains OPEN for the entire for LOOP 3. Oracle implicitly closes the cursor when control comes out of the LOOP
Note: You may skip the declaration of Cursor as follow BEGIN FOR v_row IN (SELECT empno,ename,sal,deptno FROM emp) LOOP DBMS_OUTPUT.PUT_LINE(v_row.empno || ' '|| v_row.ename || ' '|| v_row.sal || ' '|| v_row.deptno); END LOOP; END; / Passing parameters to the Cursor DECLARE CURSOR cur_emp (prm_deptno emp.deptno%TYPE) IS SELECT empno,ename,sal,deptno FROM emp WHERE deptno = prm_deptno; BEGIN FOR v_row IN cur_emp(10) LOOP 146
DBMS_OUTPUT.PUT_LINE(v_row.empno || ' '|| v_row.ename || ' '|| v_row.sal || ' '|| v_row.deptno); END LOOP; END; Accepting values on the prompt DECLARE CURSOR cur_emp (prm_deptno emp.deptno%TYPE) IS SELECT empno,ename,sal,deptno FROM emp WHERE deptno = prm_deptno; BEGIN FOR v_row IN cur_emp(&deptno) LOOP DBMS_OUTPUT.PUT_LINE(v_row.empno || ' '|| v_row.ename || ' '|| v_row.sal || ' '|| v_row.deptno); END LOOP; END;
Question to students Please write down the output of the following program assuming empno, ename and sal as below -
Write a program to display following output 1. Department details (deptno, dname, location) of one department 2. All employees working in that department (empno, ename, sal, job)
-- The following program is to understand tht one PL/SQL block can have multiple cursors -- and values of the current record of one cursor can be passed as a paremeter to another -- cursor 149
DECLARE CURSOR cur_dept IS SELECT * FROM dept; CURSOR cur_emp (p_deptno emp.deptno%TYPE) IS SELECT empno, ename, sal, job FROM emp WHERE deptno = p_deptno; BEGIN FOR rec_dept IN cur_dept LOOP DBMS_OUTPUT.PUT_LINE(rec_dept.deptno ||' '|| rec_dept.dname ||' '|| rec_dept.loc);
FOR rec_emp IN cur_emp (rec_dept.deptno) LOOP DBMS_OUTPUT.PUT_LINE(rec_emp.empno ||' '|| rec_emp.ename ||' '|| rec_emp.sal ||' '|| rec_emp.job); END LOOP; DBMS_OUTPUT.PUT_LINE('***************End of department record**********');
END LOOP; END; /
Please modify the above program and display the text "No employees working in this department" in case that department does not have any employees working in it 150
-- The following program is to understand tht one PL/SQL block can have multiple cursors -- and values of the current record of one cursor can be passed as a paremeter to another -- cursor
DECLARE CURSOR cur_dept IS SELECT * FROM dept; CURSOR cur_emp (p_deptno emp.deptno%TYPE) IS SELECT empno, ename, sal, job FROM emp WHERE deptno = p_deptno;
v_flag BOOLEAN; BEGIN FOR rec_dept IN cur_dept LOOP DBMS_OUTPUT.PUT_LINE(rec_dept.deptno ||' '|| rec_dept.dname ||' '|| rec_dept.loc);
v_flag:=FALSE; FOR rec_emp IN cur_emp (rec_dept.deptno) LOOP DBMS_OUTPUT.PUT_LINE(rec_emp.empno ||' '|| rec_emp.ename ||' '|| rec_emp.sal ||' '|| rec_emp.job);
v_flag:=TRUE; 151
END LOOP;
IF v_flag = FALSE THEN DBMS_OUTPUT.PUT_LINE('NO DATA FOR '|| rec_dept.deptno); END IF;
DBMS_OUTPUT.PUT_LINE('***************End of department record**********');
END LOOP; END;
Please achieve the same output using %ROWCOUNT
Requirement Write a PL/SQL block to increase the salary of all employees as follow 1. MANAGER 1500 2. ANALYST 2000 3. CLERK 1200 4. SALESMAN 1000 5. PRESIDENT 3000 6. OTHERS 900
DECLARE CURSOR cur_emp IS SELECT empno, job FROM emp; v_incr_amt NUMBER(6); BEGIN FOR rec_emp IN cur_emp LOOP IF rec_emp.job = 'SALESMAN' THEN 152
v_incr_amt := 1000; ELSIF rec_emp.job = 'CLERK' THEN v_incr_amt := 1200; ELSIF rec_emp.job = 'ANALYST' THEN v_incr_amt := 2000; ELSIF rec_emp.job = 'MANAGER' THEN v_incr_amt := 1500; ELSIF rec_emp.job = 'PRESIDENT' THEN v_incr_amt := 3000; ELSE v_incr_amt := 900; END IF;
UPDATE emp SET sal = sal + v_incr_amt WHERE empno = rec_emp.empno;
FOR UPDATE 1. It is an extension to the SELECT statement 2. It can be used to lock the records retrieved by the SELECT statement 3. These locks will be released only when you issue COMMIT or ROLLBACK 4. If SELECT statement is retrieving data from two or more tables, you have a choice of locking data from specific table(s). To do so you need to use FOR UPDATE OF <column_name>. In this case only that table(s) records will be locked whose <column_name> is mentioned. EX. In the following case it will lock the records of DEPT table SELECT empno,ename,sal,dname,loc from emp e, dept d where e.deptno=d.deptno for update OF dname 153
5. NOWAIT can be specified if you don't want to wait to apply locks if some other session has already locked those records. CURRENT OF 1. It can be used along with the cursor name to manipulate the record that is currently being in process in the cursor. 2. This clause can be used in WHERE clause of DML statement
DECLARE CURSOR cur_emp IS SELECT job FROM emp FOR UPDATE; v_incr_amt NUMBER(6); BEGIN FOR rec_emp IN cur_emp LOOP IF rec_emp.job = 'SALESMAN' THEN v_incr_amt := 1000; ELSIF rec_emp.job = 'CLERK' THEN v_incr_amt := 1200; ELSIF rec_emp.job = 'ANALYST' THEN v_incr_amt := 2000; ELSIF rec_emp.job = 'MANAGER' THEN v_incr_amt := 1500; ELSIF rec_emp.job = 'PRESIDENT' THEN v_incr_amt := 3000; ELSE v_incr_amt := 900; END IF;
UPDATE emp SET sal = sal + v_incr_amt WHERE CURRENT OF cur_emp;
IMP Notes 1. COMMIT/ROLLBACK can be used inside cursor LOOP but only FOR UPDATE is not used to declare the cursor 2. If you try to perform an operation on closed cursor, oracle will return an error "Invalid Cursor" 3. If you try to open the cursor, which is already opened, oracle will return an error " Cursor already open"
Implicit Cursors BEGIN UPDATE emp SET sal = sal+1500 WHERE deptno = &deptno;
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' Records are modified'); END; BEGIN UPDATE emp SET sal = sal+1500 WHERE deptno = &deptno;
IF SQL%ROWCOUNT = 0 THEN DBMS_OUTPUT.PUT_LINE ('Invalid deptno or no employees....please enter correct deptno'); ELSE DBMS_OUTPUT.PUT_LINE (SQL%ROWCOUNT || ' Records modified'); END IF; END;
155
Cursor and Memory Management by Oracle
1. Cursor is a pointer to the private SQL area that is stored in PGA 2. Private SQL area stores the ROWID's of the records retrieved by the SELECT statements associated with the cursor. These ROWIDs provide an access to the actual data 3. Actual data is stored in Database Buffer Cache and only one copy is shared among all connected sessions
156
Exception Handling What is an Exception? 1. It is an error thrown by Oracle while executing a program 2. This error is caused due to PL/SQL program not following the RULE or system defined limits 3. These exceptions can be handles by the programmer by using exception handler names and in EXCEPTION section of a PL/SQL block
Pre-Defined Exceptions PL/SQL declares predefined exceptions globally in package STANDARD, which defines the PL/SQL environment. So, you need not declare them yourself. Following are the pre-defined exceptions. Please note that exceptions marked with * are available with Oracle 8 onwards and # with Oracle 8i onwards. Exception Handler Name Oracle Error SQLCODE Value ACCESS_INTO_NULL * COLLECTION_IS_NULL * CURSOR_ALREADY_OPEN DUP_VAL_ON_INDEX INVALID_CURSOR INVALID_NUMBER LOGIN_DENIED NO_DATA_FOUND NOT_LOGGED_ON PROGRAM_ERROR ROWTYPE_MISMATCH SELF_IS_NULL # STORAGE_ERROR SUBSCRIPT_BEYOND_COUNT * SUBSCRIPT_OUTSIDE_LIMIT * SYS_INVALID_ROWID # TIMEOUT_ON_RESOURCE TOO_MANY_ROWS VALUE_ERROR ZERO_DIVIDE
Brief descriptions of the predefined exceptions follow: Exception Raised when ... ACCESS_INTO_NULL *
Your program attempts to assign values to the attributes of an un initialized (atomically null) object. COLLECTION_IS_NULL *
Your program attempts to apply collection methods other than EXISTS to an un initialized (atomically null) nested table or varray, or the program attempts to assign values to the elements of an un initialized nested table or varray. CURSOR_ALREADY_OPEN
Your program attempts to open an already open cursor. A cursor must be closed before it can be reopened. A cursor FOR loop automatically opens the cursor to which it refers. So, your program cannot open that cursor inside the loop. DUP_VAL_ON_INDEX
Your program attempts to store duplicate values in a database column that is constrained by a unique index. INVALID_CURSOR
Your program attempts an illegal cursor operation such as closing an unopened cursor. INVALID_NUMBER
In a SQL statement, the conversion of a character string into a number fails because the string does not represent a valid number. (In procedural statements, VALUE_ERROR is raised.) LOGIN_DENIED
Your program attempts to log on to Oracle with an invalid username and/or password. NO_DATA_FOUND
A SELECT INTO statement returns no rows, or your program references a deleted element in a nested table or an uninitialized element in an index-by table. SQL aggregate functions such as AVG and SUM always return a value or a null. So, a SELECT INTO statement that calls a aggregate function will never raise NO_DATA_FOUND. The FETCH statement is expected to return no rows eventually, so when that happens, no exception is raised. NOT_LOGGED_ON
Your program issues a database call without being connected to Oracle. PROGRAM_ERROR
PL/SQL has an internal problem. 158
ROWTYPE_MISMATCH
The host cursor variable and PL/SQL cursor variable involved in an assignment have incompatible return types. For example, when an open host cursor variable is passed to a stored subprogram, the return types of the actual and formal parameters must be compatible. SELF_IS_NULL #
Your program attempts to call a MEMBER method on a null instance. That is, the built-in parameter SELF (which is always the first parameter passed to a MEMBER method) is null. STORAGE_ERROR
PL/SQL runs out of memory or memory has been corrupted. SUBSCRIPT_BEYOND_COUNT *
Your program references a nested table or varray element using an index number larger than the number of elements in the collection. SUBSCRIPT_OUTSIDE_LIMIT *
Your program references a nested table or varray element using an index number (-1 for example) that is outside the legal range. SYS_INVALID_ROWID #
The conversion of a character string into a universal rowid fails because the character string does not represent a valid rowid. TIMEOUT_ON_RESOURCE
A time-out occurs while Oracle is waiting for a resource. TOO_MANY_ROWS
A SELECT INTO statement returns more than one row. VALUE_ERROR
An arithmetic, conversion, truncation, or size-constraint error occurs. For example, when your program selects a column value into a character variable, if the value is longer than the declared length of the variable, PL/SQL aborts the assignment and raises VALUE_ERROR. In procedural statements, VALUE_ERROR is raised if the conversion of a character string into a number fails. (In SQL statements, INVALID_NUMBER is raised.) ZERO_DIVIDE
Your program attempts to divide a number by zero.
DECLARE v_sal NUMBER(4); BEGIN SELECT sal INTO v_sal 159
FROM emp WHERE ename = '&ename';
DBMS_OUTPUT.PUT_LINE ('Salary Is: ' || v_sal);
EXCEPTION WHEN no_data_found THEN DBMS_OUTPUT.PUT_LINE ('Invalid employee...Please enter existing employee name'); END; -------------------------------------------------------------------------------------------------------------------------------------------- DECLARE v_sal NUMBER(4); v_ename emp.ename%TYPE := '&ename'; BEGIN SELECT sal INTO v_sal FROM emp WHERE ename = v_ename; DBMS_OUTPUT.PUT_LINE ('Salary Is: ' || v_sal); EXCEPTION WHEN no_data_found THEN DBMS_OUTPUT.PUT_LINE ('Invalid employee...Please enter existing employee name'); WHEN too_many_rows THEN DECLARE CURSOR cur_emp IS SELECT empno,sal FROM emp WHERE ename = v_ename; BEGIN FOR rec_emp IN cur_emp 160
OTHERS EXCEPTION HANDLER 1. This handler can be used for handling all run time errors that are not handled separately 2. This handler MUST BE in the end of exception handlers
DECLARE v_sal NUMBER(4); v_ename emp.ename%TYPE := '&ename'; BEGIN SELECT sal INTO v_sal FROM emp WHERE ename = v_ename;
DBMS_OUTPUT.PUT_LINE ('Salary Is: ' || v_sal);
EXCEPTION WHEN others THEN DBMS_OUTPUT.PUT_LINE ('Error executing program.....please contact support team');
END; /
161
DECLARE v_sal NUMBER(4); v_ename emp.ename%TYPE := '&ename'; BEGIN SELECT sal INTO v_sal FROM emp WHERE ename = v_ename;
DBMS_OUTPUT.PUT_LINE ('Salary Is: ' || v_sal);
EXCEPTION
WHEN no_data_found THEN DBMS_OUTPUT.PUT_LINE ('Employee doesnot exist');
WHEN others THEN DBMS_OUTPUT.PUT_LINE ('Error executing program.....please contact support team');
END;
Use of SQLERRM It can be used in exception handling section to know the Oracle error code and message that is causing an error DECLARE v_sal NUMBER(4); v_ename emp.ename%TYPE := '&ename'; BEGIN SELECT sal 162
INTO v_sal FROM emp WHERE ename = v_ename; DBMS_OUTPUT.PUT_LINE ('Salary Is: ' || v_sal); EXCEPTION WHEN others THEN DBMS_OUTPUT.PUT_LINE ('Error executing program.....please contact support team'); DBMS_OUTPUT.PUT_LINE (SQLERRM); END;
Use of SQLCODE
DECLARE v_sal NUMBER(4); v_ename emp.ename%TYPE := '&ename'; BEGIN SELECT sal INTO v_sal FROM emp WHERE ename = v_ename;
DBMS_OUTPUT.PUT_LINE ('Salary Is: ' || v_sal); EXCEPTION WHEN others THEN IF SQLCODE = 100 THEN DBMS_OUTPUT.PUT_LINE ('Invalid employee...Please enter existing employee name'); END IF; END; 163
User-Defined Exceptions 1. They are declared by the programmers 2. They must be raised explicitly as Oracle will not RAISE them until they are associated with an Oracle error code using EXCEPTION_INIT 3. EXCEPTION_INIT is a pre compiler directive used to map user defined exception to the Oracle error code
DECLARE abcd EXCEPTION; BEGIN DBMS_OUTPUT.PUT_LINE ('In PL/SQL block'); RAISE abcd;
EXCEPTION WHEN abcd THEN DBMS_OUTPUT.PUT_LINE ('In user defined exception'); END;
Imp Points 1. User defined exceptions can have same name as pre-defined exceptions 2. In this case if you want both exception handlers then you can precede pre-defined exception handler name with the keyword STANDARD
DECLARE no_data_found EXCEPTION; v_sal NUMBER(4); BEGIN SELECT sal INTO v_sal FROM emp WHERE ename = '&ename'; 164
DBMS_OUTPUT.PUT_LINE ('Salary Is: ' || v_sal); RAISE no_data_found; EXCEPTION WHEN no_data_found THEN DBMS_OUTPUT.PUT_LINE ('In user defined exception');
WHEN STANDARD.no_data_found THEN DBMS_OUTPUT.PUT_LINE ('Invalid employee...Please enter existing employee name'); END;
NAMING NAMELESS EXCEPTION
Exception_init preprocessor/precompiler directive can be used to name the nameless exception Syntax PRAGMA exception_init(<exception_name>, <error_code>)
Execute the following program when records are already locked from other session DECLARE CURSOR cur_emp IS SELECT job FROM emp FOR UPDATE NOWAIT; v_incr_amt NUMBER(6); record_locked EXCEPTION; PRAGMA exception_init(record_locked, -00054); BEGIN FOR rec_emp IN cur_emp LOOP IF rec_emp.job = 'SALESMAN' THEN v_incr_amt := 1000; ELSIF rec_emp.job = 'CLERK' THEN v_incr_amt := 1200; ELSIF rec_emp.job = 'ANALYST' THEN 165
v_incr_amt := 2000; ELSIF rec_emp.job = 'MANAGER' THEN v_incr_amt := 1500; ELSIF rec_emp.job = 'PRESIDENT' THEN v_incr_amt := 3000; ELSE v_incr_amt := 900; END IF; UPDATE emp SET sal = sal + v_incr_amt WHERE CURRENT OF cur_emp; END LOOP; DBMS_OUTPUT.PUT_LINE ('Salary Increase Done'); EXCEPTION WHEN record_locked THEN DBMS_OUTPUT.PUT_LINE ('Error executing program...pls try after some time. If error continues then report to support team'); END;
Exception handling and nested blocks
1. Can statements of nested block raise an exception handled in parent block? YES
DECLARE v_sal emp.sal%TYPE; BEGIN DBMS_OUTPUT.PUT_LINE ('In Parent Block');
BEGIN 166
SELECT sal INTO v_sal FROM emp WHERE ename = '&ename';
DBMS_OUTPUT.PUT_LINE ('Salary Is: ' || v_sal); END;
EXCEPTION WHEN no_data_found THEN DBMS_OUTPUT.PUT_LINE ('In PARENT no data found');
END; 2. Can statements of parent block raise an exception handled in nested block? NO 3. Can nested block and parent block handle the same exception? If yes then statements of nested block will raise exception handled in nested block, and statements in parent block will raise from parent block
DECLARE v_sal emp.sal%TYPE; BEGIN DBMS_OUTPUT.PUT_LINE ('In Parent Block');
BEGIN SELECT sal 167
INTO v_sal FROM emp WHERE ename = '&ename';
DBMS_OUTPUT.PUT_LINE ('Salary Is: ' || v_sal); EXCEPTION WHEN no_data_found THEN DBMS_OUTPUT.PUT_LINE ('In nested no data found'); END;
EXCEPTION WHEN no_data_found THEN DBMS_OUTPUT.PUT_LINE ('In PARENT no data found');
END;
168
Sub-Programs What is a sub-program? 1. It an unit/routine which is used to club logically related statements 2. In Oracle a sub-program is called as a named PL/SQL block 3. There are two types of sub-program a. FUNCTION MUST have a return statement at the exit point to return a value b. PROCEDURE Does not return a value with RETURN statement 4. They can be stored inside database (called as stored subprograms) or they can be local as well
LOCAL Sub-Programs These sub-programs can be declared and defined inside 1. Anonymous PL/SQL block 2. Stored Procedure 3. Stored Function 4. Package 5. Database Trigger
Syntax of procedure PROCEDURE <name> [(<parameters>)] IS [<local declaration>] BEGIN <pl/sql statements> [EXCEPTION <exception_handler>] END [<name>];
Syntax of function FUNCTION <name> [(<parameters>)] RETURN <data_type> IS [<local declaration>] BEGIN <pl/sql statements> [EXCEPTION 169
<exception_handler>] END [<name>];
And at exit point of function, there MUST BE a RETURN statement returning a value of the <data_type> mentioned in declaration
Examples of Procedures DECLARE PROCEDURE p1 IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1'); END; BEGIN DBMS_OUTPUT.PUT_LINE ('In Block'); p1; DBMS_OUTPUT.PUT_LINE ('Again in block'); END; /
DECLARE PROCEDURE P2; -- Forward Declaration to avoid compilation error PROCEDURE p1 IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1'); p2; DBMS_OUTPUT.PUT_LINE('IN p1 again'); END p1;
170
PROCEDURE p2 IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p2'); END;
Passing parameters to procedures DECLARE PROCEDURE p1 (p_temp number) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || p_temp); END p1; BEGIN DBMS_OUTPUT.PUT_LINE ('In Block'); p1(100); DBMS_OUTPUT.PUT_LINE ('In block again'); END; / Declarations of the main block should be prior to the definition of the local sub-program else Oracle will generate the compilation error
171
DECLARE v_cnt NUMBER := 5000;
PROCEDURE p1 (p_temp number) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || p_temp); END p1; BEGIN DBMS_OUTPUT.PUT_LINE ('In Block'); p1(v_cnt); DBMS_OUTPUT.PUT_LINE ('In block again'); END; /
You can provide DEFAULT value to call sub-program without passing parameter
DECLARE v_cnt NUMBER := 5000;
PROCEDURE p1 (p_temp number DEFAULT 300) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || p_temp); END p1; BEGIN p1(v_cnt); p1; END;
172
Declarations of the block can be accessed by the local sub-programs defined inside that block
DECLARE v_cnt NUMBER := 5000;
PROCEDURE p1 IS BEGIN v_cnt := 7000; END p1; BEGIN DBMS_OUTPUT.PUT_LINE('Before Call :' || v_cnt); p1; DBMS_OUTPUT.PUT_LINE('After Call :' || v_cnt); END; / Example of function DECLARE v_temp NUMBER; FUNCTION add_val (p1 NUMBER, p2 NUMBER) RETURN NUMBER IS BEGIN RETURN p1+p2; END; BEGIN DBMS_OUTPUT.PUT_LINE('Addition is : ' || add_val(100,200) ); v_temp := add_val(500,200); DBMS_OUTPUT.PUT_LINE('Addition is : ' || v_temp); END; 173
/
Two and more sub-programs can have same name as long as signature (total number of parameters or/and data types) differs
DECLARE PROCEDURE p1 (x NUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || x); END p1;
PROCEDURE p1 (x NUMBER, y NUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || x || ' ' ||y); END p1;
PROCEDURE p1(x VARCHAR2) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || x); END p1; BEGIN p1(100,200); p1(200); p1('Sachin'); END; Using association operator (for named parameter passing) DECLARE PROCEDURE p1 (x NUMBER, y NUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || x || ' ' ||y); END p1; BEGIN p1(y=>100,x=>200); END;
174
Parameter Passing Modes
1. There are 3 parameter passing modes. They are IN (Default) OUT IN OUT 2. They determine the behavior of the formal parameter 3. They decide if you can read/write the values of/to the formal parameters
IN OUT IN OUT You can only read the value, can not change the value of the formal parameter You cannot read the value unless you assign the value. After assignment you can read the value (post 8.0.4ver). You can read the value of formal parameter as well as you can assign the value Actual parameter can be a constant, variable or an expression Actual parameter MUST BE a variable Actual parameter MUST BE a variable Call by value Value of actual parameter is copied into formal parameter Call BY Reference Formal parameter and actual parameter, both share the same memory location. But if you don't assign the value to the formal parameter, actual also will have value of NULL. If subprograms return with an error, actual parameters will not have the same value as the formal parameter Call by value Value of actual parameter is copied into formal parameter and then of formal into actual when subprogram returns the control without any error
IMP NOTE: 1. Actual parameters will get the values copied from Formal parameters if CALLED Sub-program is returning a control without any errors, else Actual parameters will be NULL. 175
DECLARE v_temp NUMBER(5) := 100; PROCEDURE p1 (x IN NUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || x);
END; BEGIN
p1(v_temp + 200);
END; / DECLARE v_temp NUMBER(5) := 100; PROCEDURE p1 (x IN NUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || x); x:=7000; END; BEGIN
p1(v_temp + 200);
END; DECLARE v_temp NUMBER := 9000; 176
PROCEDURE p1 (x OUT NUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || x); x := 7000; DBMS_OUTPUT.PUT_LINE('IN p1 :' || x); END; BEGIN DBMS_OUTPUT.PUT_LINE('Before P1: ' || v_temp); p1(v_temp); DBMS_OUTPUT.PUT_LINE('After P1: ' || v_temp); END; / DECLARE v_temp NUMBER := 9000; PROCEDURE p1 (x OUT NUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1'); --x := 7000; END; BEGIN DBMS_OUTPUT.PUT_LINE('Before P1: ' || v_temp); p1(v_temp); DBMS_OUTPUT.PUT_LINE('After P1: ' || v_temp); END; / DECLARE v_temp CONSTANT NUMBER := 9000; PROCEDURE p1 (x OUT NUMBER) IS 177
BEGIN DBMS_OUTPUT.PUT_LINE('IN p1'); x := 7000; END; BEGIN p1(v_temp); END; /
DECLARE v_temp NUMBER := 9000; PROCEDURE p1 (x IN OUT NUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('IN p1 :' || x); x := 7000; DBMS_OUTPUT.PUT_LINE('IN p1 :' || x); END; BEGIN DBMS_OUTPUT.PUT_LINE('Before P1: ' || v_temp); p1(v_temp); DBMS_OUTPUT.PUT_LINE('After P1: ' || v_temp); END; /
DECLARE v_temp NUMBER := 9000; PROCEDURE p1 (x IN OUT NUMBER) IS BEGIN 178
1. They are schema objects that are stored in the database 2. The following are the types of stored PL/SQL program unit a. Procedure b. Function c. Package d. Database Trigger
Stored Procedures
CREATE OR REPLACE PROCEDURE <name> [(<parameters>)] IS | AS [<local declaration>] BEGIN <pl/sql statements> [EXCEPTION <exception_handler>] END [<name>];
1. When you get message "Procedure Created" Oracle stores the source code into the data dictionary along with the object code. One copy of object code is also stored in the shared pool 2. When you get message "Procedure Created with compilation error" Oracle stores the source code into the data dictionary along with the compilation errors 3. user_source can be used to retrieve source code and user_errors for retrieving errors
-- Learning Stored Procedures CREATE OR REPLACE PROCEDURE P1 AS BEGIN DBMS_OUTPUT.PUT_LINE('In stored proc P1'); END; /
SELECT text FROM user_source WHERE name = 'P1' /
-- To check errors
180
CREATE OR REPLACE PROCEDURE P1 AS BEGIN DBMS_OUTPUT.PUT_LINE('In stored proc P1); END; /
SELECT text FROM user_errors WHERE name = 'P1' /
Please create the proc successfully for below testing
Note: stored sub-programs can be called from SQL*PLUS, Anonymous PL/SQL block, other subprograms, database trigger, front end program. But for UNIT testing, developer generally writes anonymous PL/SQL block
To call from SQL*PLUS you can use EXECUTE (EXEC) >EXEC P1
Anonymous PL/SQL block BEGIN P1; END; / If there is a local sub-program by the same name then precedence will be given to the local one. <schema_name>. can be used to call the stored sub-program when local is having the same name DECLARE PROCEDURE p1 IS BEGIN DBMS_OUTPUT.PUT_LINE('In LOCAL proc P1'); END; BEGIN HR.p1; p1; END; /
181
Write a procedure get_salary which will accept empno as a parameter and will give you ename, sal, comm and gross sal of the given employee
-- File Name : get_salary.sql -- Procedure Name : get_salary -- Author : abc -- Created On : 16-Jan-2011 -- Description : This procedure accepts employee number as a input and gives ename, sal, comm and gross salary of that employee
CREATE OR REPLACE PROCEDURE get_salary ( pi_empno IN emp.empno%TYPE, po_ename OUT emp.ename%TYPE, pio_sal IN OUT emp.sal%TYPE, pio_comm IN OUT emp.comm%TYPE, po_gross OUT NUMBER ) AS BEGIN SELECT ename, sal, comm INTO po_ename, pio_sal, pio_comm FROM emp WHERE empno = pi_empno;
po_gross := pio_sal + NVL(pio_comm,0);
END; / Calling program to UNIT test the above program
In the above program, exception handling is neither done in called program nor in calling program. Industry practice is that exception handling is done in the called programs. Also in such cases communication between called program and calling program is done using two additional parameters i.e. error_code and error_msg.
-- File Name : get_salary.sql -- File Name : get_salary.sql -- Procedure Name : get_salary -- Author : abc -- Created On : 16-Jan-2011 -- Description : This procedure accepts employee number as a input and gices ename, sal, -- comm and gross salary of that employee
CREATE OR REPLACE PROCEDURE get_salary ( pi_empno IN emp.empno%TYPE, po_ename OUT emp.ename%TYPE, pio_sal IN OUT emp.sal%TYPE, pio_comm IN OUT emp.comm%TYPE, po_gross OUT NUMBER, po_error_code OUT VARCHAR2, po_error_msg OUT VARCHAR2 ) AS BEGIN SELECT ename, sal, comm INTO po_ename, pio_sal, pio_comm FROM emp WHERE empno = pi_empno;
IF v_error_code = '00' THEN DBMS_OUTPUT.PUT_LINE ('Details are : ' || v_ename || ' '|| v_sal || ' '|| v_comm || ' '|| v_gross); ELSE DBMS_OUTPUT.PUT_LINE (v_error_msg); END IF; END; / 184
Stored Functions
CREATE OR REPLACE FUNCTION <name> [(<parameters>)] RETURN <data_type> IS|AS [<local declaration>] BEGIN <pl/sql statements> [EXCEPTION <exception_handler>] END [<name>];
Write a function get_count which accepts job as a parameter and returns total no of employees working on that job CREATE OR REPLACE FUNCTION get_count ( pi_job IN emp.job%TYPE ) RETURN NUMBER AS
v_cnt NUMBER; BEGIN SELECT COUNT(*) INTO v_cnt FROM emp WHERE JOB = PI_JOB;
RETURN v_cnt; END; /
Calling the above program from SQL*PLUS VARIABLE v_temp EXEC :v_temp := get_count('MANAGER') PRINT v_temp
Function also can be called from SQL statements SELECT get_count('MANAGER') FROM dual SELECT empno, ename, job, get_count(job) FROM emp SELECT empno, ename, job, get_count(job) FROM emp WHERE get_count(job) > 2
Calling the above program using Anonymous block DECLARE v_temp NUMBER; BEGIN v_temp := get_count('&job'); 185
DBMS_OUTPUT.PUT_LINE (v_temp); END; /
Create a function chk_deptno which will accept deptno as a parameter and will return TRUE if that dept no exists in DEPT table else returns FALSE CREATE OR REPLACE FUNCTION chk_deptno ( pi_deptno IN dept.deptno%TYPE ) RETURN BOOLEAN AS
v_cnt NUMBER; BEGIN SELECT COUNT(*) INTO v_cnt FROM dept WHERE deptno = pi_deptno;
IF v_cnt > 0 THEN RETURN TRUE; END IF;
RETURN FALSE; END; /
OR CREATE OR REPLACE FUNCTION chk_deptno ( pi_deptno IN dept.deptno%TYPE --90 ) RETURN BOOLEAN AS
v_flag CHAR; BEGIN SELECT 'X' INTO v_flag FROM dept WHERE deptno = pi_deptno; RETURN TRUE;
EXCEPTION WHEN no_data_found THEN RETURN FALSE; END; 186
/
OR CREATE OR REPLACE FUNCTION chk_deptno ( pi_deptno IN dept.deptno%TYPE --90 ) RETURN BOOLEAN AS
CURSOR c1 IS SELECT 'X' FROM dept WHERE deptno = pi_deptno; v_flag CHAR; BEGIN OPEN c1; FETCH c1 INTO v_flag; CLOSE c1;
IF v_flag = 'X' THEN RETURN TRUE; END IF; RETURN FALSE; END; /
NOTE: As per few Oracle books SELECT statement using CURSOR runs faster than SELECT .. INTO .. because For SELECT .. INTO .. Oracle checks for three Exceptions i.e. no_data_found, too_many_rows and value_error but for CURSOR it doesnot check for these errors.
Write a procedure add_employee which accepts 1. Employee name, salary, job and deptno values from calling program, 2. Checks if deptno value is existing in dept table if yes then inserts a record into emp table. While inserting the record, employee number should be automatically generated and should be returned back to the calling program. 3. If deptno does not exists then should raise an user generated error and return the control back to the calling program with that error
Please create the sequence first
187
CREATE OR REPLACE PROCEDURE add_employee ( po_empno OUT emp.empno%TYPE, pi_ename IN emp.ename%TYPE, pi_sal IN emp.sal%TYPE, pi_job IN emp.job%TYPE, pi_deptno IN emp.deptno%TYPE ) AS BEGIN IF chk_deptno(pi_deptno) = TRUE THEN INSERT INTO emp (empno,ename,sal,job,deptno) VALUES (seq_empno.NEXTVAL, pi_ename, pi_sal, pi_job, pi_deptno) RETURNING empno INTO po_empno; ELSE RAISE_APPLICATION_ERROR(-20000,'INVALID DEPTNO....Please enter existing dept'); END IF; END; / -- Calling program for add_employee
DECLARE v_empno emp.empno%TYPE; BEGIN add_employee (v_empno, '&ename', &sal, '&job', &deptno); DBMS_OUTPUT.PUT_LINE ('Record Inserted Successfully...empno is: '||v_empno); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE (SQLERRM); END; /
188
RAISE_APPLICATION_ERROR
1. It is used to generate the user defined run time error 2. It stops an execution of the PL/SQL block and returns the control to calling program with that error (assuming error is not handled in the called program) 3. It accepts two parameters a. Error_code Should be within range of -20000 to -20999 b. Error_message Any string containing the message
Write a procedure increase_sal which will accept empno and amount and will increase the salary of the given employee by the given amount. If empno is not existing then it should return message to the calling program and ask to enter the valid empno else should return the current salary to the calling program
CREATE OR REPLACE PROCEDURE update_salary ( pi_empno IN emp.empno%TYPE, pi_amt IN emp.sal%TYPE, po_sal OUT emp.sal%TYPE, po_error_code OUT VARCHAR2, po_error_msg OUT VARCHAR2 ) AS BEGIN UPDATE emp SET sal = sal + pi_amt WHERE empno = pi_empno RETURNING sal INTO po_sal;
IF SQL%ROWCOUNT > 0 THEN po_error_code := '00'; ELSE RAISE_APPLICATION_ERROR(-20001,'INVALID empno....please enter existng empno'); END IF; EXCEPTION WHEN OTHERS THEN po_error_code := '99'; po_error_msg := SUBSTR(SQLERRM,12); END; /
189
-- Calling program for update_salary
DECLARE v_sal emp.sal%TYPE; v_error_code VARCHAR2(2); v_error_msg VARCHAR2(1000); BEGIN update_salary (&empno, &amount, v_sal, v_error_code, v_error_msg); IF v_error_code = '00' THEN DBMS_OUTPUT.PUT_LINE ('Record Updated Successfully...salary is: '||v_sal); ELSE DBMS_OUTPUT.PUT_LINE (v_error_msg); END IF; END; /
Advantages of stored sub-programs Other than the advantages given in sub-program (local) topic, the following are the advantages of the stored sub-program 1. Performance Improvement a. Since they are stored at DB server side, network traffic and round trips are reduced which helps to improve the performance b. One copy of object code is shared among all connected sessions (having privilege to execute the procedure) 2. Abstraction The implementation details of these sub-programs are hidden from calling programs. So when changes are required in the business logic, only these sub-programs will need a change and not the calling programs 3. Security By creating sub-programs to modify the data of table you can provide security to the table and its data. Instead of granting access of these tables to other users or directly accessing these tables from front end program, you can allow them to call these sub-programs which in turn will manipulate the data from these tables.
190
Packages
1. Package is an unit which encapsulates logically related members 2. Package is created in two parts a. Specification b. Body 3. All members declared in the specification can be accessed from outside programs (front end, stored procedure, functions, Database trigger etc) 4. Package body can be created successfully (w/o any error) only if all sub-programs declared in the specification are defined inside it 5. Members not declared in specification but declared or defined inside body, can not be accessed from outside programs. They can be accessed only within the same package 6. To access the members of the packages you can use <package_name>.<member_name>
Syntax Package Specification CREATE [OR REPLACE] PACKAGE <name> AS <Declaration of members> END <name>;
Package Body CREATE [OR REPLACE] PACKAGE BODY <name> AS <Definition of members> END <name>;
Create a package employee which has get_employees procedure. This procedure must accept deptno and should return empno, ename, sal & job of all employees working in that deptno. In case of non existing deptno, it should send the proper error message
<declaration of variables, constants, exceptions, cursors etc> <declaration of procedures & functions> Specification <MUST have definition for all those procedures and functions declared In the specification> <declaration & definition of procedures & functions NOT declared in spec> <declaration of variables, constants, exceptions, cursors etc>
Body 191
CREATE OR REPLACE PACKAGE employee AS TYPE emp_ty IS RECORD ( empno emp.empno%TYPE, ename emp.ename%TYPE, sal emp.sal%TYPE, job emp.job%TYPE );
TYPE emp_tab IS TABLE OF emp_ty INDEX BY BINARY_INTEGER;
PROCEDURE get_employee ( pi_deptno IN emp.deptno%TYPE, po_emps OUT emp_tab, po_error_code OUT VARCHAR2, po_error_msg OUT VARCHAR2 ); END; /
CREATE OR REPLACE PACKAGE BODY employee AS PROCEDURE get_employee ( pi_deptno IN emp.deptno%TYPE, --40 po_emps OUT emp_tab, po_error_code OUT VARCHAR2, po_error_msg OUT VARCHAR2 ) IS i NUMBER := 1; CURSOR cur_emp IS SELECT empno, ename, sal, job FROM emp WHERE deptno = pi_deptno; BEGIN IF chk_deptno (pi_deptno) THEN FOR rec_emp IN cur_emp LOOP po_emps(i).empno := rec_emp.empno; po_emps(i).ename := rec_emp.ename; po_emps(i).sal := rec_emp.sal; 192
po_emps(i).job := rec_emp.job; i := i + 1; END LOOP; po_error_code := '00'; ELSE po_error_code := '99'; po_error_msg := 'INVALID DEPTNO....please enter existing deptno'; RETURN; END IF;
IF i = 1 THEN po_error_code := '99'; po_error_msg := 'NO Employees are working in this department'; END IF;
END get_employee; -- End of the procedure END employee; -- End of the package /
-- Calling program for get_employee procedure of employee package
DECLARE v_emps employee.emp_tab; v_error_code VARCHAR2(2); v_error_msg VARCHAR2(1000); BEGIN employee.get_employee (&deptno, v_emps,v_error_code,v_error_msg); IF v_error_code = '00' THEN FOR i IN 1..v_emps.COUNT LOOP DBMS_OUTPUT.PUT_LINE (v_emps(i).empno || ' '|| v_emps(i).ename || ' '|| v_emps(i).sal || ' '|| v_emps(i).job); END LOOP; ELSE DBMS_OUTPUT.PUT_LINE (v_error_msg); END IF;
END; / 193
Function chk_deptno also can be a part of package, if it is not called from outside
CREATE OR REPLACE PACKAGE BODY employee AS
FUNCTION chk_deptno ( pi_deptno IN dept.deptno%TYPE --90 ) RETURN BOOLEAN AS
v_flag CHAR; BEGIN SELECT 'X' INTO v_flag FROM dept WHERE deptno = pi_deptno; RETURN TRUE;
EXCEPTION WHEN no_data_found THEN RETURN FALSE; END chk_deptno;
PROCEDURE get_employee ( pi_deptno IN emp.deptno%TYPE, --40 po_emps OUT emp_tab, po_error_code OUT VARCHAR2, po_error_msg OUT VARCHAR2 ) IS i NUMBER := 1; CURSOR cur_emp IS SELECT empno, ename, sal, job FROM emp WHERE deptno = pi_deptno; BEGIN IF chk_deptno (pi_deptno) THEN FOR rec_emp IN cur_emp LOOP po_emps(i).empno := rec_emp.empno; po_emps(i).ename := rec_emp.ename; po_emps(i).sal := rec_emp.sal; po_emps(i).job := rec_emp.job; i := i + 1; 194
END LOOP; po_error_code := '00'; ELSE po_error_code := '99'; po_error_msg := 'INVALID DEPTNO....please enter existing deptno'; RETURN; END IF;
IF i = 1 THEN po_error_code := '99'; po_error_msg := 'NO Employees are working in this department'; END IF;
END get_employee; -- End of the procedure
END employee; -- End of the package /
195
REF Cursor They are used under the following circumstances 1. When SELECT statement to be associated with Cursor is not same and changes based on conditions 2. When SELECT statement is dynamic
There are two types of REF Cursor 1. Strongly Typed Row Type is fixed. SELECT statement used to open this Cursor MUST have same Row Type as of Cursor. If not then opening of cursor will result in an error 2. Weakly Typed No fixed Row Type. So there is no restriction on the SELECT statement Row Type. Weakly Typed Ref Cursor TYPE <type_name> IS REF CURSOR
EX - TYPE cur_ty IS REF CURSOR;
Strongly Typed Ref Cursor TYPE <type_name> IS REF CURSOR RETURN < type>
EX - TYPE cur_ty IS REF CURSOR RETURN emp%ROWTYPE;
In the above examples cur_ty is REF Cursor type and not the actual REF Cursor. Using that type you need to declare the Cursor as below - Cur_emp cur_ty;
To open the Ref Cursor syntax is as below - OPEN <ref cursor> FOR <SELECT statement> EX OPEN cur_emp FOR SELECT * FROM emp;
CREATE OR REPLACE PACKAGE employee AS
TYPE cur_ty is REF CURSOR;
PROCEDURE get_employee ( pi_deptno IN emp.deptno%TYPE, po_emps OUT cur_ty, po_error_code OUT VARCHAR2, po_error_msg OUT VARCHAR2 ); END; 196
/ CREATE OR REPLACE PACKAGE BODY employee AS
FUNCTION chk_deptno ( pi_deptno IN dept.deptno%TYPE --90 ) RETURN BOOLEAN AS
v_flag CHAR; BEGIN SELECT 'X' INTO v_flag FROM dept WHERE deptno = pi_deptno; RETURN TRUE;
EXCEPTION WHEN no_data_found THEN RETURN FALSE; END chk_deptno;
PROCEDURE get_employee ( pi_deptno IN emp.deptno%TYPE, --40 po_emps OUT cur_ty, po_error_code OUT VARCHAR2, po_error_msg OUT VARCHAR2 ) IS BEGIN IF chk_deptno (pi_deptno) THEN OPEN po_emps FOR SELECT empno, ename, sal, job FROM emp WHERE deptno = pi_deptno; po_error_code := '00'; ELSE po_error_code := '99'; po_error_msg := 'INVALID DEPTNO....please enter existing deptno'; END IF; END get_employee; -- End of the procedure
Calling get_employee from anonymous PL/SQL block DECLARE v_emps employee.cur_ty; v_error_code VARCHAR2(2); v_error_msg VARCHAR2(1000); v_empno emp.empno%TYPE; v_ename emp.ename%TYPE; v_sal emp.sal%TYPE; v_job emp.job%TYPE; BEGIN employee.get_employee (&deptno, v_emps,v_error_code,v_error_msg); IF v_error_code = '00' THEN LOOP FETCH v_emps INTO v_empno, v_ename, v_sal, v_job; EXIT WHEN v_emps%NOTFOUND; DBMS_OUTPUT.PUT_LINE (v_empno|| ' '||v_ename||' '|| v_sal || ' '|| v_job); END LOOP; CLOSE v_emps; ELSE DBMS_OUTPUT.PUT_LINE (v_error_msg); END IF;
END; /
Assignment
Please modify the employee package in such a way that get_employee procedure should return '99' as error_code and error_msg as "No employee is working in this department" when valid deptno is passed as a parameter but does not have employees working in it.
Scope and lifetime of declarations (such as variables) made in procedure, function and package
1. Every session has its own copy of these declarations which is stored in PGA of that session. 2. Scope means accessibility and lifetime means the time they retain their values 3. Scope and lifetime of the declarations made in procedures and functions is within the same PL/SQL block. Once control comes out of that procedure or function they cannot be accessed 4. The following is the scope and lifetime of packaged declarations (specification) a. Scope These declarations can be accessed outside the package and in programs like front end program, stored procedure, stored function etc. which is either written by same user or the user who has an EXECUTE privilege on this package b. Lifetime These declarations retain their values as long as session continues or their values are overwritten
Valid procedures, functions, packages, Database Triggers can go in INVALID state under the following circumstances
1. When referenced object is dropped 2. When referenced object is altered 3. When privileges of the referenced objects are revoked by the owner of those objects from the creator of these stored units
What is the difference between DROP and then CREATE and CREATE OR REPLACE option?
When you use combination of DROP and CREATE, ORACLE removes all information about that stored object, like privileges granted on that object to other users, from data dictionary.
CREATE OR REPLACE keeps all such information and replaces only source code and object code
Using ALTER statement
You can use ALTER statement to compile the source code stored in the data dictionary. Generally this is done when object is in INVALID state
199
Syntax
ALTER PROCEDURE <name> COMPILE ALTER FUNCTION <name> COMPILE ALTER PACKAGE <name> COMPILE compiles only package specification ALTER PACKAGE <name> COMPILE BODY compiles package body
Using DROP statement Syntax
DROP PROCEDURE <name> DROP FUNCTION <name> DROP PACKAGE BODY <name> DROP PACKAGE <name> - Drops entire package (spec as well as body)
200
Database Triggers
1. It is a stored PL/SQL block having an event associated to it 2. It is implicitly executed by Oracle, whenever that event takes place 3. You can not execute this block (trigger) like you execute procedure or function 4. Triggers can be applied only on the tables but they are also applicable to the views created on that table
Syntax
CREATE [OR REPLACE] TRIGGER <name> <trigger_timing> <trigger_event> ON <table_name> [FOR EACH ROW] [WHEN <condition>] [DECLARE <local_declarations>] BEGIN <Pl/sql statements> [EXCEPTION <exception handler>] END [<name>];
In the above syntax the lines marked in BOLD are the trigger specification and underlined are trigger body
<trigger_timing> = either BEFORE or AFTER <trigger_event> = either INSERT or UPDATE or DELETE (you can either mention one, two or all of them)
Example CREATE OR REPLACE TRIGGER learn_trig BEFORE INSERT ON my_emp BEGIN DBMS_OUTPUT.PUT_LINE ('In Insert trigger'); END; /
201
1. Up on successful creation of trigger, Oracle stores source code along with one copy of object code into the data dictionary and one copy of object code is stored in shared pool 2. Information about trigger (like trigger event, body etc) can be retrieved from user_triggers 3. If there are any compilation errors (PL/SQL block) then they can be retrieved from user_errors
SELECT triggering_event, trigger_body from user_triggErs where trigger_name = 'LEARN_TRIG' /
INSERT INTO my_emp VALUES (1001,'SACHIN',5000,10); INSERT INTO my_emp SELECT empno, ename, sal, deptno FROM emp; INSERT INTO my_emp SELECT empno, ename, sal, deptno FROM emp WHERE 1=2;
There are two levels of trigger
1. Statement Level a. They are fired only ones for the triggering statement irrespective of total number of records manipulated b. They are fired even when no records are manipulated by the triggering statement 2. Row Level a. Trigger is row level when FOR EACH ROW is added in trigger specification b. They are fired ones for every record manipulated by the triggering statement c. They are NOT fired when no records are manipulated by the triggering statement
CREATE OR REPLACE TRIGGER learn_trig BEFORE INSERT ON my_emp FOR EACH ROW BEGIN DBMS_OUTPUT.PUT_LINE ('In Insert trigger'); END; /
Possible combination of events BEFORE INSERT Statement AFTER UPDATE Row DELETE
1. There are total 12 possible events 2. If you want to handle each event separately then you will need 12 triggers but do handle all events with minimum number of events, you will need 4 triggers
Triggering Statement It is a DML statement that causes a trigger to fire 202
These can be used in the body of database trigger to determine the event causing trigger to fire. CREATE OR REPLACE TRIGGER learn_trig BEFORE INSERT OR UPDATE OR DELETE ON my_emp FOR EACH ROW BEGIN IF INSERTING THEN DBMS_OUTPUT.PUT_LINE ('Inserting Data'); ELSIF UPDATING THEN DBMS_OUTPUT.PUT_LINE ('Updating Data'); ELSE DBMS_OUTPUT.PUT_LINE ('Deleting Data'); END IF;
END; /
Sequence of trigger execution 1. BEFORE Statement trigger 2. LOOP for executing triggering statement and manipulating records a. BEFORE row trigger b. Locks the record and manipulates the same c. AFTER row trigger 3. AFTER statement trigger
Use of NEW and OLD
1. They can be used to refer to the values of the record that is being processed. 2. They have the same ROWTYPE as the table whose values you are referring in the body of database triggers
203
DML Statement NEW OLD INSERT YES NO (will be NULL) UPDATE YES YES DELETE NO (will be NULL) YES
In case of UPDATE values of NEW and OLD will be same unless they are changed.
CREATE OR REPLACE TRIGGER learn_trig BEFORE INSERT OR UPDATE OR DELETE ON my_emp FOR EACH ROW BEGIN DBMS_OUTPUT.PUT_LINE ('OLD Values : '||:OLD.empno|| ' ' || :OLD.ename || ' ' || :OLD.sal || ' ' || :OLD.deptno);
INSERT INTO my_emp VALUES (1007,'SACHIN',70000,20) / UPDATE my_emp SET sal = 9000 WHERE empno = 1007 / DELETE FROM my_emp WHERE empno = 1007 204
Use of Database Triggers 1. TO automatically calculate values for derived columns (either of same table or another table) 2. TO implement referential integrity between the tables belonging to remote databases 3. TO implement complex business rules that are not possible using Integrity Constraints 4. TO prevent invalid transactions 5. To implement security authorizations/audit logs etc
Please create the following table SQL> DESC MY_EMP Name Null? Type ---------------------------------------------------------- ---------------------------------- -------- --------------- ---------------------------------------- EMPNO NUMBER(4) ENAME VARCHAR2(10) SAL NUMBER(7,2) DEPTNO NUMBER(2) JOB VARCHAR2(25) COMM NUMBER(6,2)
Ex1. Please write a database trigger to automatically calculate the value for comm. column as follow 1. It should be 5% of the salary 2. It should be auto calculated only for those employees who are working as SALESMAN
CREATE OR REPLACE TRIGGER comm_mani BEFORE INSERT OR UPDATE OF sal, job ON my_emp FOR EACH ROW WHEN (UPPER(NEW.job) = 'SALESMAN') BEGIN :NEW.comm := :NEW.sal * 0.05; END; /
Execute SELECT * FROM my_emp after each statement below > INSERT INTO my_emp VALUES (1001,'SACHIN',7000,10,'SALESMAN',NULL); 205
> INSERT INTO my_emp VALUES (1002,'SAURAV',8000,20,'MANAGER',NULL); > UPDATE my_emp SET job = 'SALESMAN' WHERE empno = 1002; >UPDATE my_emp SET SAL = 10000 WHERE empno = 1002; Ex-2
Create a table salary as below Column Name Data Type Length Empno NUMBER 4 Da NUMBER 8,2 Hra NUMBER 8,2 Ded NUMBER 6,2 NetSal NUMBER 10,2
Write a database trigger which will be fired when record of my_emp table is manipulated and will do the following 1. When record is inserted or sal column value is updated a. Calculate the values for DA, HRA, DED, NETSAL based on value of sal and comm. b. DA = 25% of sal, hra = 20% of sal, ded = 6% of sal and netsal = sal+da+hra+comm.-ded 2. When empno value is updated from my_emp table, it should update the empno value from the salary table 3. When record is deleted frm my_emp, it should delete the record from salary table
CREATE OR REPLACE TRIGGER salary_dml AFTER INSERT OR UPDATE OF sal, empno OR DELETE ON my_emp FOR EACH ROW DECLARE v_da salary.da%TYPE; v_hra salary.hra%TYPE; v_ded salary.ded%TYPE; v_netsal salary.netsal%TYPE; BEGIN
IF INSERTING OR UPDATING('sal') THEN v_da := :NEW.sal * 0.25; v_hra := :NEW.sal * 0.20; v_ded := :NEW.sal * 0.06; v_netsal := :NEW.sal+NVL(:NEW.comm,0)+v_da+v_hra-v_ded; 206
IF INSERTING THEN INSERT INTO salary(empno,da,hra,ded,netsal) VALUES(:NEW.empno, v_da, v_hra, v_ded,v_netsal); ELSE UPDATE salary SET da = v_da, hra = v_hra, ded = v_ded, netsal = v_netsal WHERE empno = :OLD.empno; END IF; END IF;
IF UPDATING('empno') THEN UPDATE salary SET empno = :NEW.empno WHERE empno = :OLD.empno; END IF;
IF DELETING THEN DELETE FROM salary WHERE empno = :OLD.empno; END IF; END; /
After each statement please execute SELECT on my_emp and salary > INSERT INTO my_emp VALUES (1002,'SAURAV',8000,20,'MANAGER',NULL); > UPDATE my_emp SET SAL = 10000 WHERE empno = 1002; > UPDATE my_emp SET empno = 5001 WHERE empno = 1002; > UPDATE my_emp SET empno = 7001, sal = 15000 WHERE empno = 5001; DELETE FROM my_emp WHERE empno = 7001;
207
Trigger Cascading
When statement given in body of a trigger causes another trigger to fire then that is called as Trigger Cascading
Imp Note AFTER ROW triggers are slightly more efficient than BEFORE ROW triggers because for execution of before row triggers, ORACLE reads affected data twice i.e. Trigger body execution and then again for triggering statement execution. But for after row trigger, it reads affected data only one time i.e. for triggering statement execution
Ex-3 Write a database trigger to STOP DML operation on my_emp table during no working days and non working hours
CREATE OR REPLACE TRIGGER stop_dml BEFORE INSERT OR UPDATE OR DELETE ON my_emp BEGIN IF TO_CHAR(SYSDATE,'DY') = 'SAT' OR TO_CHAR(SYSDATE,'DY') = 'SUN' THEN RAISE_APPLICATION_ERROR(-20000, 'Can not manipulate on non working days'); ELSIF TO_CHAR(SYSDATE,'HH24:MI') < '09:00' OR TO_CHAR(SYSDATE,'HH24:MI') > '18:30' THEN RAISE_APPLICATION_ERROR(-20001, 'Can not manipulate on non working hours'); END IF; END; / Assignment
1. Create a table job_sal which has the following columns
Column Name Data Type Length Job_Code Number 2 Losal Number 5 Hisal Number 5
208
Whenever you are inserting or updating record (job,sal) into my_emp table oracle should check if salary is as per the range specified in job_sal table, if no then that transaction should not be allowed.
2. Write a database trigger on my_emp table it should be execute whenever you perform DML operation on my_emp and should insert username, terminal name, DML statement issued by that user from that terminal & that time into log_table. To get Terminal use:- userenv(terminal)
3. Find out the reason why commit and rollback cannot be used in the body of the trigger (unless they are autonomous transactions).
4. What is Table Mutating Error?
INSTEAD OF Triggers
1. They can be created or applied only on the views 2. There are 3 possible events a. INSTEAD OF INSERT b. INSTEAD OF UPDATE c. INSTEAD OF DELETE 3. In presence of INSTEAD OF trigger on the view, ORACLE executes this trigger when DML operations are performed on the view and skips the execution of DML operation on the base table of the view 4. They are ROW Level triggers 5. They are used to make the unmodified view modifiable
Ex CREATE OR REPLACE view v1 AS SELECT empno, ename, sal+2000 bonus, deptno FROM emp / The following operations are not allowed INSERT INTO v1 VALUES (1001,'SACHIN',7000,10) / UPDATE V1 SET BONUS = BONUS+2000 /
209
CREATE OR REPLACE TRIGGER v1_mani INSTEAD OF INSERT OR UPDATE OR DELETE ON v1 FOR EACH ROW BEGIN IF INSERTING THEN INSERT INTO emp (empno, ename, sal, deptno) VALUES (:NEW.empno, :NEW.ename, :NEW.bonus-2000, :NEW.deptno); ELSIF UPDATING THEN UPDATE emp SET ename = :NEW.ename, sal = sal + (:NEW.BONUS - :OLD.bonus), deptno = :NEW.deptno WHERE empno = :OLD.empno; ELSE DELETE FROM emp WHERE empno = :OLD.empno; END IF; END; Now try DML operation on V1 and see an impact by performing SELECT operation on V1 as well as emp table
210
Autonomous Transaction
P1 P2 -- - - - - - - P2 COMMIT OR ROLLBACK - - - COMMIT OR ROLLBACK
1. In the above case, P1 is a parent transaction and P2 is a child transaction 2. Child transaction shares the COMMIT dependencies with the parent transaction so whenever COMMIT or ROLLBACK is issues from P2, it will not only save or cancel the changes made by itself but also the changes made by Parent Transaction (P1) 3. To avoid this P2 can be marked as Autonomous Transaction 4. To mark the child transaction as Autonomous, you have to use PRAGMA AUTONOMOUS TRANSACTION statement in the DECLARE section of child transaction. 5. Once child transaction is marked as Autonomous, Oracle pauses parent transaction, initiates child transaction, does the changes, commit or rollbacks these changes and then resumes parent transaction 6. You can commit or rollback the parent transaction without impacting the changes made by the autonomous transaction 7. Changes committed by Autonomous transactions are available to parent transaction only when TRANSACTION ISOLATION LEVEL is set to READ COMMITTED (By default). If it is set to SERIALIZABLE then they are not available 8. Changes made by the parent transaction are not available to the Autonomous transaction, unless they are committed 9. The following can be marked as Autonomous a. Stored Procedure b. Stored Function c. Packaged Procedure or function (entire package can't marked as Autonomous. If you want all subprograms of that package as Autonomous then you need to mark all of them individually as Autonomous) d. Database Trigger e. Methods of an object type f. Parent Anonymous Block (Not the nested block)
211
Ex 1. create parts and parts_log table 2. write a database trigger on parts table which will INSERT the record into parts_log table and also commit that
CREATE TABLE parts (pno number(2), pname VARCHAR2(30) ) / Now create parts_log having same structure
CREATE OR REPLACE TRIGGER learn_autonomous AFTER INSERT ON parts FOR EACH ROW DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO parts_log (pno, pname) VALUES (:NEW.pno, :NEW.pname); COMMIT; END; /
> INSERT INTO parts VALUES (1,'ABC'); > COMMIT; > SELECT * FROM parts; > SELECT * FROM parts_log;
> INSERT INTO parts VALUES (2,'PQR'); > SELECT * FROM parts; > SELECT * FROM parts_log; > ROLLBACK; > SELECT * FROM parts; > SELECT * FROM parts_log;
CREATE OR REPLACE PROCEDURE p1 AS BEGIN INSERT INTO emp (empno,ename,sal,deptno) VALUES (1001, 'ABC', 3500, 10); p2; 212
UPDATE emp SET sal = sal + 3500; COMMIT; END; /
Changes made by the parent transaction are not available to the Autonomous transaction, unless they are committed
CREATE OR REPLACE PROCEDURE p2 AS v_sal emp.sal%TYPE; PRAGMA AUTONOMOUS_TRANSACTION; BEGIN SELECT sal INTO v_sal FROM emp WHERE empno = 1001; DBMS_OUTPUT.PUT_LINE('Salary IS :' || v_sal); EXCEPTION WHEN no_data_found THEN DBMS_OUTPUT.PUT_LINE ('parent transaction record not available'); END; / > EXEC P1 Native Dynamic SQL
1. When complete text of the SQL statement is not known at the time of compilation is called as "Dynamic SQL" 2. These statements are formed at runtime and only then their complete text is known 3. This gives you a flexibility to decide upon the schema object NAME, filter conditions and list of columns at runtime 4. This also allows you to execute DDL, DCL, Session and system control statements from PL/SQL block 5. These make software components more flexible and increases their reusability 6. All such statements (except for SELECT statement that returns more than one record) are executed using EXECUTE IMMEDIATE statement. To execute SELECT statement that returns more than one record, you have to use OPEN . FOR .. syntax 7. This feature is available since 8i onwards, prior to this DBMS_SQL package was the only means to execute dynamic SQL statements 8. Now also DBMS_SQL package can be used, but if you want something easier to use, better in performance and support for objects and collections then you should use Native Dynamic SQL
v_sql := 'SELECT * FROM emp WHERE empno = :1'; EXECUTE IMMEDIATE v_sql INTO v_rec_emp USING 1001; DBMS_OUTPUT.PUT_LINE(v_rec_emp.ename || ' '||v_rec_emp.sal);
v_sql := 'SELECT COUNT(*) FROM '||v_tname; EXECUTE IMMEDIATE v_sql INTO v_cnt; DBMS_OUTPUT.PUT_LINE('Total no of records in '||v_tname || ' are : '||v_cnt);
Ex-2 Create a function count_rows which will accept the table_name or view name as a parameter and returns total number of records from that table or view
CREATE OR REPLACE FUNCTION count_rows ( pi_table_name VARCHAR2 ) RETURN NUMBER AS
v_cnt NUMBER;
BEGIN EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' ||pi_table_name INTO v_cnt; 214
RETURN v_cnt; END; /
Ex-2 Create a procedure drop_object which will accept, kind of object and name of the object and will drop that object
CREATE OR REPLACE PROCEDURE drop_object ( pi_kind VARCHAR2, pi_name VARCHAR2 ) AS BEGIN EXECUTE IMMEDIATE 'DROP '|| pi_kind || ' '|| pi_name; DBMS_OUTPUT.PUT_LINE('Object dropped Successfully'); END; /
Imp Note: By default subprograms are mapped to the schema of the owner and not executor. If you want them to be mapped to the schema of executor then you should use AUTHID CURRENT_USER clause as below
CREATE OR REPLACE PROCEDURE drop_object ( pi_kind VARCHAR2, pi_name VARCHAR2 ) AUTHID CURRENT_USER AS BEGIN EXECUTE IMMEDIATE 'DROP '|| pi_kind || ' '|| pi_name; DBMS_OUTPUT.PUT_LINE('Object dropped Successfully'); END; /
Ex-3 Write a procedure delete_rows that accepts Table_name and condition a parameter and deletes the record from the given table using the given condition. If condition is not provided then it should delete all records
215
CREATE OR REPLACE PROCEDURE delete_rows ( pi_tname VARCHAR2, pi_condi VARCHAR2 DEFAULT NULL ) AS v_sql VARCHAR2(1000); v_where VARCHAR2(500); BEGIN IF pi_condi IS NOT NULL THEN v_where := ' WHERE '||pi_condi; END IF; v_sql := 'DELETE FROM ' || pi_tname||v_where; EXECUTE IMMEDIATE v_sql; DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' Records Deleted'); END; /
Ex-4 Write a procedure list_employees that accepts the condition as a parameter and displays empno, ename, sal and job of all employees satisfying that condition. If condition is not passed as a parameter then it should display all employees CREATE OR REPLACE PROCEDURE list_employees ( pi_condi VARCHAR2 DEFAULT NULL ) AS v_sql VARCHAR2(1000); v_where VARCHAR2(500); TYPE cur_ty IS REF CURSOR; cur_emps cur_ty; v_empno emp.empno%TYPE; v_ename emp.ename%TYPE; v_sal emp.sal%TYPE; v_deptno emp.deptno%TYPE; BEGIN IF pi_condi IS NOT NULL THEN v_where := ' WHERE '||pi_condi; END IF; v_sql := 'SELECT empno, ename, sal, deptno FROM emp ' ||v_where; 216
Assignment: Change the above logic and have list_employees returning the cursor to the calling program instead of printing the records inside the procedure
Ex-5
CREATE OR REPLACE PACKAGE sales AS PROCEDURE create_sales ( pi_year VARCHAR2, pi_month VARCHAR2 );
PROCEDURE drop_sales ( pi_year VARCHAR2, pi_month VARCHAR2 ) IS BEGIN v_sql := 'DROP TABLE sales_'||pi_year||'_'||pi_month; EXECUTE IMMEDIATE v_sql; END;
PROCEDURE get_sales ( pi_year VARCHAR2, pi_month VARCHAR2, po_cur_sales OUT cur_ty ) IS
BEGIN v_sql := 'SELECT * FROM sales_'||pi_year||'_'||pi_month; 218
OPEN po_cur_sales FOR v_sql; END; END;
In case you get an error of insufficient privileges while executing the create_sales and drop_sales procedures then do the following 1. conn sys/sys as sysdba 2. GRANT CREATE TABLE TO <user_name>
Assignment: 1. INSERT 10-15 records into the table created by you 2. Write calling program for get_sales
219
Object Oriented Concepts 1. Abstraction hiding of details that are irrelevant is called as an abstraction. One of the good examples is about the car. User/Driver of the car ignores the details of how engine or any other mechanical part functions as it is not relevant. But the same details are not ignored by a mechanic. Oracle supports abstraction in the form of stored PL/SQL program objects. 2. Encapsulation Grouping of Properties and behavior together is called as Encapsulation. 3. Class It is a vehicle to implement the Abstraction and Encapsulation. It is a unit that encapsulates properties and behavior together. In Oracle instead of a class there is an object type 4. Object It is an instance of a class. It contains the properties and behavior defined by the class. These are created at runtime and memory is allocated to store their values 5. Inheritance Not supported by Oracle 6. Containership When an object of one class (object type) is declared as a member of another class (object type) then it is called as containership Object Type 1. It is a stored schema object 2. It is a collection of member attributes (properties] and member methods [behavior] 3. It is created in two parts a. Specification can contain declaration of member attributes and member methods b. Body Required only when specification contains the declaration of member methods 4. At runtime instances of this object type is created and they are called as objects 5. Using these objects, you can access the members declared in the specification. Those members which are part of ONLY BODY and not declared in the specification, cannot be accessed outside that object type body 6. By default Oracle creates NULL objects unless they are initialized using constructor method 7. Constructor method is the by default method available in Oracle which is having the same name as an object type. It also accepts same number of parameters as an object type attributes Syntax CREATE [OR REPLACE] TYPE <name> AS OBJECT ( <member attribute1> [, <member attribute2>] . . . [,<member method>] )
220
CREATE OR REPLACE TYPE address_ty AS OBJECT ( street VARCHAR2(15), city VARCHAR2(15), state VARCHAR2(15), pin VARCHAR2(6) ) /
The following program will result in an error as we are trying to access NULL object attributes DECLARE v_add1 ADDRESS_TY; BEGIN v_add1.city := 'PUNE'; v_add1 := ADDRESS_TY('MG ROAD','MUMBAI','MAHARASHTRA','410210'); DBMS_OUTPUT.PUT_LINE(v_add1.street || ' '|| v_add1.city || ' '|| v_add1.state || ' '|| v_add1.pin); END; / Once object is initialized, you can access its attributes DECLARE v_add1 ADDRESS_TY; BEGIN v_add1 := ADDRESS_TY('MG ROAD','MUMBAI','MAHARASHTRA','410210'); DBMS_OUTPUT.PUT_LINE(v_add1.street || ' '|| 221
INSERT INTO customer VALUES (1001, 'SACHIN', ADDRESS_TY('SHIVAJI ROAD','PUNE','MAHARASHTRA','402190')); INSERT INTO customer VALUES (1002, 'SAURAV', ADDRESS_TY('TAGORE ROAD','CALCUTTA','BENGAL','302450')); INSERT INTO customer VALUES (1003, 'RAHUL', ADDRESS_TY('MG ROAD','BANGLORE','KARNATAKA','205190')); NOTE: In the above case customer table contains the records that has partial relational data as well as object data so this table is called as Object Relational Table. SELECT * FROM customer; will give you data using constructor method. If you need to get the data in normal relational format then use the following SELECT CNO, CNAME, c.address.street street, c.address.city city, c.address.state state, c.address.pin pin FROM customer c;
UPDATE customer c SET c.address.city = 'NAGPUR', c.address.state = 'MAHARASHTRA', c.address.pin = '709876' 222
WHERE cno = 1003;
DELETE FROM customer c WHERE c.address.state = 'MAHARASHTRA'; --------------------------------------------------------------------------------------------------------- Dependencies between the objects can be retrieved from user_dependencies. Desc user_dependencies; To find the objects dependent on ADDRESS_TY, following statement can be issued - SELECT name,type FROM user_dependencies WHERE referenced_name = 'ADDRESS_TY';
- When you try to drop these objects using DROP TYPE statement, ORACLE will generate an error as they have dependencies. DROP TYPE address_t y; - FORCE option can be used to DROP these objects even after having dependencies DROP TYPE address_ty FORCE; - When FORCE option is used, ORACLE will drop all the columns/attributes from dependent tables/types before dropping this type Nested Object Types (Containership) CREATE OR REPLACE TYPE address_ty AS OBJECT ( street VARCHAR2(15), city VARCHAR2(15), state VARCHAR2(15), pin VARCHAR2(6) ) /
CREATE OR REPLACE TYPE person_ty AS OBJECT ( name VARCHAR2(25), address ADDRESS_TY ) / DECLARE v_person PERSON_TY; BEGIN 223
INSERT INTO customer VALUES (1002, PERSON_TY('RAHUL', ADDRESS_TY('SHIVAJI ROAD','PUNE','MAHARASHTRA','430340')));
INSERT INTO customer VALUES (1003, PERSON_TY('SAURAV', ADDRESS_TY('TIGER NAGAR','KOLKATTA','BENGAL','300456')));
- Write a SELECT statement to retrieve cno, name, street, city, state & pin
> SELECT cno, C.person.name name, C.person.address.street street, C.person.address.city city, C.person.address.state state, C.person.address.pin pin FROM customer C; Collector Types 1. There are two collector types a. VARRAY [VARRYING ARRAYS] b. NESTED TABLE 2. Objects of these types are called as collections 3. Collection contains multiple elements of same data type. These elements are accessed using index number or subscript number 4. Collections can store instances (objects) of objects types and they can be members of an object type
1. VARRAY - These types are created with a limit. Meaning, total number of elements collection of these types can contain are fixed - They have fixed lower bound of 1 and extensible upper bound but not beyond the limit Syntax CREATE [OR REPLACE] TYPE <name> AS VARRAY (<limit>) OF <data type / object type> [NOT NULL] CREATE OR REPLACE TYPE marks_va AS VARRAY(6) OF NUMBER(3) /
225
DECLARE v_marks MARKS_VA; v_total NUMBER := 0; BEGIN v_marks := MARKS_VA(75,60,80); FOR i IN 1..v_marks.COUNT LOOP DBMS_OUTPUT.PUT_LINE(v_marks(i)); v_total := v_total + v_marks(i); END LOOP; DBMS_OUTPUT.PUT_LINE ('Total Marks :' || v_total); END; /
- Example to store instances (objects) of an object type CREATE OR REPLACE TYPE marks_ty AS OBJECT ( sub_name VARCHAR2(15), sub_marks NUMBER(3) ) /
CREATE OR REPLACE TYPE marks_va AS VARRAY(6) OF marks_ty /
226
DECLARE v_marks MARKS_VA; v_total NUMBER := 0; BEGIN v_marks := MARKS_VA(MARKS_TY('MATHS',50),MARKS_TY('ENGLISH',60)); FOR i IN 1..v_marks.COUNT LOOP DBMS_OUTPUT.PUT_LINE('Subject: ' || v_marks(i).sub_name || ' Marks: ' || v_marks(i).sub_marks); v_total := v_total + v_marks(i).sub_marks; END LOOP; DBMS_OUTPUT.PUT_LINE ('Total Marks :' || v_total); END; / - Create a table by the name students which has following columns Rollno NUMBER(5) Name VARCHAR2(25) Marks marks_va - Insert 3-4 records in this table CREATE TABLE students ( rollno NUMBER(5), name VARCHAR2(25), marks MARKS_VA );
INSERT INTO students VALUES(1001,'SACHIN', MARKS_VA(MARKS_TY('MATHS',90), MARKS_TY('ENGLISH',80), MARKS_TY('HINDI',65)));
INSERT INTO students VALUES(1002,'RAHUL', MARKS_VA(MARKS_TY('MATHS',90), MARKS_TY('PHYSICS',99), MARKS_TY('BIO',85)));
- Write a PL/SQL block to display all these above records along with subject name and marks. After each student record, it should display the total of that student
227
DECLARE v_total NUMBER := 0; CURSOR cur_stud IS SELECT rollno, name, marks FROM students; BEGIN FOR stud_row IN cur_stud LOOP DBMS_OUTPUT.PUT_LINE (stud_row.rollno ||' '||stud_row.name); FOR i IN 1..stud_row.marks.COUNT LOOP DBMS_OUTPUT.PUT_LINE('Subject: ' || stud_row.marks(i).sub_name || ' Marks: ' || stud_row.marks(i).sub_marks); v_total := v_total + stud_row.marks(i).sub_marks; END LOOP; DBMS_OUTPUT.PUT_LINE (' Total Marks :' || v_total); v_total := 0; END LOOP; END; / Nested Tables 1. Collections of TABLE type are called as Nested Tables 2. They dont have any limit 3. They have no fixed lower bound and have extensible upper bound 4. They can be represented as columns of other table 5. Data of nested tables is stored out of line in different storage table CREATE OR REPLACE TYPE emp_ty AS OBJECT ( empno NUMBER(5), ename VARCHAR2(30), sal NUMBER(5), job VARCHAR2(20) ) /
CREATE OR REPLACE TYPE emp_nt AS TABLE OF emp_ty /
228
CREATE TABLE my_dept ( deptno NUMBER(2), dname VARCHAR2(15), loc VARCHAR2(15), emps emp_nt ) NESTED TABLE emps STORE AS emp_tab;
- In the above example emp_tab is a storage table that stores data of emps nested table. No DML or SELECT operations can be performed on emp_tab. These operations must be performed on emps only. DESC emp_tab INSERT INTO my_dept VALUES(10, 'SALES', 'MUMBAI', EMP_NT(EMP_TY(1001,'SACHIN',7000,'MANAGER'), EMP_TY(1002,'DHONI',5000,'ANALYST'), EMP_TY(1005,'NEHRA',2000,'CLERK'), EMP_TY(1007,'YUVRAJ',5500,'ANALYST') ) );
INSERT INTO my_dept VALUES(20, 'MKTG', 'CHENNAI', EMP_NT(EMP_TY(1003,'SAURAV',5000,'MANAGER'), EMP_TY(1004,'ZAHEER',3000,'SALESMAN') ) );
INSERT INTO my_dept VALUES(30, 'OPERATIONS', 'KOLKATTA',NULL); SELECT deptno, dname, loc, e.* FROM my_dept d, TABLE(d.emps) e; In the above SELECT statement, data of department 30 will not come as, by default Oracle is using equi-join. So to get that additional record, you can use the following statement SELECT deptno, dname, loc, e.* FROM my_dept d, TABLE(d.emps)(+) e; - Please SELECT all emps working in dept =10
SELECT * FROM TABLE (SELECT emps FROM my_dept WHERE deptno=10)
- Please SELECT record of only SACHIN 229
SELECT * FROM TABLE (SELECT emps FROM my_dept WHERE deptno=10) WHERE ename='SACHIN'; - Change job of SACHIN to SR. MANAGER and salary to 9000
UPDATE TABLE (SELECT emps FROM my_dept WHERE deptno=10) SET sal = 9000, job = 'SR. MANAGER' WHERE ename='SACHIN' /
- DELETE record of SACHIN DELETE FROM TABLE (SELECT emps FROM my_dept WHERE deptno=10) WHERE ename='SACHIN';
- You can copy a set of data from one parent record into another as below INSERT INTO my_dept VALUES(40,'HR','MUMBAI', CAST(MULTISET(SELECT * FROM TABLE (SELECT emps FROM my_dept WHERE deptno=10 ) )AS EMP_NT) );
CAST operator allows to convert the output of the SELECT statement to the COLLECTION of COLLECTOR TYPE. MULTISET operator allows CAST query to contain more than one records.
- You can apply constraints to the nested table CREATE TABLE my_dept ( deptno NUMBER(2), dname VARCHAR2(15), loc VARCHAR2(15), emps emp_nt ) NESTED TABLE emps STORE AS emp_tab ( ( CONSTRAINT pk_emps_empno PRIMARY KEY (empno), CONSTRAINT chk_emps_sal CHECK (sal IS NOT NULL AND sal > 1000), CONSTRAINT chk_emps_ename CHECK (ename = UPPER(ename)) 230
) );
Assignment: Create a table order_master which will have the following columns Ordno NUMBER(5) Odate DATE Items items_nt
Items must be a nested table having ino, qty and price columns
The following constraint must be added 1. ORDNO must be a PRIMARY KEY 2. Odate MUST be not NULL 3. Identify the primary key for items table (ino alone cant be primary key) 4. Qty should be greater than 0 5. Price should be NOT NULL Collector Methods 1. These are pre-defines functions or procedures which can be used only inside PL/SQL block 2. They can be invoked using collection (<collection>.<method_name>) The following are the methods 1. EXISTS (<n>) - It returns TRUE if nth element exists else returns FALSE 2. FIRST a. It returns an index number of the first element of the given collection b. For VARRAY collection it will be always 1, but for nested table it may be greater than 1 if elements are deleted in the beginning 3. LAST It returns an index number of the last element of the given collection 4. COUNT a. It returns the total number of elements collection currently contains b. Value of COUNT may be less than LAST if elements are deleted from the given collection 5. PRIOR (<n>) a. It returns an index number of an element that precedes given nth element b. Returns NULL if there is no element that precedes given nth element 6. NEXT (<n>) a. It returns an index number of an element that succeeds given nth element b. Returns NULL if there is no element that succeeds given nth element 7. EXTEND 231
a. It is used to append elements to the collection b. EXTEND - It appends one NULL element to the given collection c. EXTEND(<n>) It appends n number of NULL elements to the given collection d. EXTEND (<n>, <i>) It appends n copies of ith element to the given collection 8. LIMIT It returns the total number of elements that collection of VARRAY can contain 9. DELETE a. It is used to DELETE all of specific elements from the given collection b. DELETE keeps the place holders c. DELETE All elements will be deleted d. DELETE(<n>) nth element from collection of nested table will be deleted e. DELETE (<m>,<n>) It deletes elements between mth to nth from the collection of nested table 10. TRIM a. It removes the elements from the end of the collection b. It does not keep place holders c. TRIM Removes one element d. TRIM (<n>) It removes n number of elements from the collection BULK Binding 1. Assigning of values to/from PL/SQL variables is called as binding 2. When collections are used, instead of binding individual elements, you can bind entire collection at once 3. This will help to reduce the context switches between database engine and PLSQL engine and improve the performance For an example depts Is a collection as below - Depts 50 30 40 20 10
FOR I IN depts.FIRST..depts.LAST LOOP DELETE FROM emp WHERE deptno = depts.(i); END LOOP;
As mentioned above, using FOR LOOP, each element is bound and hence there will be 5 number of context switches between database engine and pl/sql engine 232
To avoid this you can use FORALL statement as below which will help in binding entire collection at once FORALL I IN depts.FIRST..depts.LAST DELETE FROM emp WHERE deptno = depts.(i); FORALL 1. It is used to bulk bind the collection which is used inside the DML statement 2. Though entire collection is bound, DML statements will be still executed once for every element inside the collection 3. In above case, all 5 elements are bound at once, but still DELETE statement will be executed 5 times i.e. once for every element 4. You can bulk bind the elements in the given range if not entire collection a. Assuming depts Has 1000 elements, instead of binding all 1000 elements, only 200+ elements are bound. Please see below FORALL i IN 300..500 DELETE FROM emp WHERE deptno = depts.(i); Example to show the time difference - CREATE TABLE parts ( pno NUMBER(10), pname VARCHAR2(100) );
DECLARE TYPE numtab IS TABLE OF NUMBER(10) INDEX BY BINARY_INTEGER; TYPE nametab IS TABLE OF VARCHAR2(50) INDEX BY BINARY_INTEGER; pnos numtab; pnames nametab; t1 CHAR(5); t2 CHAR(5); t3 CHAR(5);
PROCEDURE get_time (t OUT NUMBER) IS BEGIN SELECT TO_CHAR(SYSDATE,'SSSSS') INTO t from DUAL; END;
BEGIN 233
-- creating a collection FOR i IN 1..100000 LOOP pnos(i) := i; pnames(i) := 'Part ' || i; END LOOP;
-- Storing the current time in T1 and then using FOR LOOP to INSERT values into parts table -- Context switches will be more as entire collection is not bound get_time(t1); FOR i IN 1..pnos.COUNT LOOP INSERT INTO parts VALUES(pnos(i), pnames(i)); END LOOP; get_time(t2); -- t2 - t1 will give the total time taken to INSERT 50000 records without bulk binding -- Now using FORALL FORALL i IN 1..pnos.COUNT INSERT INTO parts VALUES(pnos(i), pnames(i)); get_time(t3); -- t3 - t2 will give the total time taken to INSERT 50000 records with bulk binding DBMS_OUTPUT.PUT_LINE('Without Bulk Binding : ' ||TO_CHAR(t2-t1)); DBMS_OUTPUT.PUT_LINE('With Bulk Binding : ' ||TO_CHAR(t3-t2)); END; /
BULK_ROWCOUNT 1. It is a cursor attribute which can be used when bulk binding is used (FORALL) 2. It is like a collection which has multiple elements. Total no of elements are determined by the number of times DML statement given in FORALL is executed 3. It stores the no of records manipulated by DML statement as value of each element DECLARE TYPE numtab IS TABLE OF NUMBER(2); depts numtab := numtab(40,30,20,10); BEGIN FORALL i IN 1..depts.COUNT DELETE FROM emp WHERE deptno = depts(i);
-- Checking total number of records deleted by each execution of DELETE 234
-- To do this you can use BULK_ROWCOUNT FOR i IN 1..depts.COUNT LOOP DBMS_OUTPUT.PUT_LINE(i || ' Execution has Deleted ' || SQL%BULK_ROWCOUNT(i) || ' Records'); END LOOP; END; /
The following example shows the dependencies amongst the executions DECLARE TYPE numtab IS TABLE OF NUMBER(2); depts numtab := numtab(40,30,20,10); BEGIN depts.DELETE(3); FORALL i IN 1..depts.COUNT DELETE FROM emp WHERE deptno = depts(i); END; /
As specified above, 1 st and 2 nd execution of DELETE is successful but 3 rd will result in an error as element does not exists. If you handle this in an exception then Oracle will allow you to commit those changes done by first two executions. DECLARE TYPE numtab IS TABLE OF NUMBER(2); depts numtab := numtab(40,30,20,10); BEGIN depts.DELETE(3); FORALL i IN 1..depts.COUNT DELETE FROM emp WHERE deptno = depts(i);
EXCEPTION WHEN others THEN COMMIT; END; /
235
Using BULK COLLECT clause 1. This clause can be used to bulk bind the values from database engine to pl/sql engine 2. It can be used in SELECT, FETCH and RETURNING clause 3. Using this you can BULK fetch the values into collections
Example with SELECT statement DECLARE TYPE empnotab IS TABLE OF emp.empno%TYPE; TYPE enametab IS TABLE OF emp.ename%TYPE; TYPE saltab IS TABLE OF emp.sal%TYPE; empnos empnotab; enames enametab; sals saltab; BEGIN SELECT empno, ename, sal BULK COLLECT INTO empnos, enames, sals FROM emp; FOR i IN 1..empnos.COUNT LOOP DBMS_OUTPUT.PUT_LINE(empnos(i) ||' '|| enames(i) ||' ' ||sals(i) ); END LOOP; END; / Example with FETCH DECLARE TYPE empnotab IS TABLE OF emp.empno%TYPE; TYPE enametab IS TABLE OF emp.ename%TYPE; TYPE saltab IS TABLE OF emp.sal%TYPE; empnos empnotab; enames enametab; sals saltab; CURSOR c1 IS SELECT empno, ename, sal FROM emp; BEGIN OPEN c1; 236
FETCH c1 BULK COLLECT INTO empnos, enames, sals; CLOSE c1;
FOR i IN 1..empnos.COUNT LOOP DBMS_OUTPUT.PUT_LINE(empnos(i) ||' '|| enames(i) ||' ' ||sals(i) ); END LOOP;
END; /
Example with RETURNING DECLARE TYPE empnotab IS TABLE OF emp.empno%TYPE; TYPE enametab IS TABLE OF emp.ename%TYPE; TYPE saltab IS TABLE OF emp.sal%TYPE; empnos empnotab; enames enametab; sals saltab; BEGIN
DELETE FROM emp WHERE deptno = &deptno RETURNING empno, ename, sal BULK COLLECT INTO empnos, enames, sals;
DBMS_OUTPUT.PUT_LINE(' Following employees are deleted'); FOR i IN 1..empnos.COUNT LOOP DBMS_OUTPUT.PUT_LINE(empnos(i) ||' '|| enames(i) ||' ' ||sals(i) ); END LOOP;
END; /
Using FORALL and BULK COLLECT together DECLARE TYPE numtab IS TABLE OF NUMBER(2); depts numtab := numtab(40,30,20,10); TYPE empnotab IS TABLE OF emp.empno%TYPE; 237
TYPE enametab IS TABLE OF emp.ename%TYPE; TYPE saltab IS TABLE OF emp.sal%TYPE; empnos empnotab; enames enametab; sals saltab;
BEGIN FORALL i IN 1..depts.COUNT DELETE FROM emp WHERE deptno = depts(i) RETURNING empno, ename, sal BULK COLLECT INTO empnos, enames, sals;
DBMS_OUTPUT.PUT_LINE(' Following employees are deleted'); FOR i IN 1..empnos.COUNT LOOP DBMS_OUTPUT.PUT_LINE(empnos(i) ||' '|| enames(i) ||' ' ||sals(i) ); END LOOP; END; /
Example with %ROWTYPE DECLARE TYPE numtab IS TABLE OF NUMBER(2); depts numtab := numtab(40,30,20,10); TYPE emptab IS TABLE OF emp%ROWTYPE; emps emptab; BEGIN FORALL i IN 1..depts.COUNT DELETE FROM emp WHERE deptno = depts(i) RETURNING empno,ename,job, mgr, hiredate,sal,comm,deptno BULK COLLECT INTO emps;
DBMS_OUTPUT.PUT_LINE(' Following employees are deleted'); FOR i IN 1..emps.COUNT LOOP DBMS_OUTPUT.PUT_LINE(emps(i).empno||' '|| emps(i).ename ||' ' ||emps(i).sal); END LOOP; END; /
238
DECLARE CURSOR c1 IS SELECT * FROM emp; TYPE emptab IS TABLE OF emp%ROWTYPE; emps emptab; BEGIN OPEN c1; FETCH c1 BULK COLLECT INTO emps; CLOSE c1; FOR i IN 1..emps.COUNT LOOP DBMS_OUTPUT.PUT_LINE(emps(i).empno||' '|| emps(i).ename ||' ' ||emps(i).sal); END LOOP; END; /
239
Database Internal Concept Oracle Database Structure Memory Architecture Processes Roles and Privileges Oracle Parallel Server configuration Distributed Database Configuration
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
Roles and Privileges Privileges: There are two types of privileges 1. System Privileges 2. Object Privileges System Privileges 1. There are over 60 system privileges 2. They allow user to perform a specific database operation 3. Oracle manual says that these system privileges are very powerful and MUST BE cautiously granted to trusted users, roles To create the users following statement can be used
CREATE USER sachin IDENTIFIED BY tiger DEFAULT TABLESPACE accounts TEMPORARY TABLESPACE temp; To grant the privileges GRANT statement used and to revoke REVOKE statement is used Syntax GRANT <privilege(s)> TO <user_name(s)> - With single GRANT statement you can GRANT one or many system privileges to one or many users, roles - System privileges and roles can be granted together with single grant statement - GRANT create session TO sachin WITH ADMIN OPTION; WITH ADMIN OPTION: If any system privilege is granted WITH ADMIN OPTION, then grantee can further grant that system privilege to other users.
257
ROLE: 1. Role is a collection of privileges and other roles 2. Privileges can be granted to roles, Roles can be granted to other roles as well as users. 3. To create the role, you must have CREATE ROLE system privileges 4. To drop the role, you must have DROP ROLE system privileges There can be two types of roles 1. Pre defined role 2. User defined role Few important Pre defined roles: Connect, resource, DBA, etc Example:- GRANT DBA TO user; CREATE ROLE r1; GRANT create session, create table, create procedure TO r1; GRANT r1 TO sachin; Object Privileges 1. They are specific to a particular object 2. They can be granted by the owner or the user who has received these WITH GRANT OPTION 3. They cannot be granted together with system privileges and roles with a single GRANT statement. You have to use separate GRANT statement Privilege Table View Sequence Procedure/ Function/ Package Snapshot INSERT YES YES NO NO NO UPDATE YES YES NO NO NO DELETE YES YES NO NO NO SELECT YES YES YES NO YES EXECUTE NO NO NO YES NO ALTER YES YES YES YES NO REFERENCES YES NO NO NO NO INDEX YES NO NO NO NO
258
4. ALL keyword can be used in GRANT statement to grant all the privileges that are applicable to that object GRANT ALL ON emp TO Hr; GRANT insert, update, delete ON dept To hr WITH GRANT OPTION; - In the above case HR user has received privileges WITH GRANT OPTION, so HR can further GRANT these privileges to other users WHEN you GRANT the privileges, they are appended to the list of existing privileges and not overwritten So now if I want HR to have an access to only UPDATE values of sal column, I need to first revoke an UPDATE privilege and then GRANT UPDATE (sal) REVOKE update on emp FROM hr; GRANT UPDATE(sal) ON emp TO hr; Synonyms They are schema objects which can be used as reference name to refer objects from remote databases as well from other schemas Syntax CREATE [PUBLIC] SYNONYM <name> FOR <source> Ex CREATE SYNONYM emp FOR sachin.emp; CREATE SYNONYM sales_tran FOR sales_tran@sales; PUBLIC keyword can be used so that it can be accessed by all users in that database
259
DISTRIBUTED DATABASE SYSTEM CREATE DATABASE LINK <name> CONNECT TO <usersname> IDENTIFIED BY <password> USING '<hoststring>'
For Eg: You have the database by the name Sales which has Table:sales_trans as well as other objects. So to access them create the following Database Link.
CREATE DATABASE LINK sales CONNECT TO sachin IDENTIFIED BY tiger USING 'INDIA' Now to access the objects stored in sachin schema you can use the following syntax :- 1. SELECT * FROM sales_tran@sales; 2. INSERT into Sales_tran@sales(<column_name>) VALUES (<values>) 3. Exec P1@sales(<parameter name>)
SnapShot:- It is a schema object created in the local database which contains the data of the remote database object. The snapshot can be scheduled to be refreshed at specific time intervals for Eg: In the Marketing database I am creating a snapshot as SNP_ST which will store the database of sales_tran table from sales database, to do the same you need to use the Database Link. CREATE SNAPSHOT snp_st REFRESH START WITH SYSDATE NEXT NEXT_DAY(SYSDATE,'MONDAY') AS SELECT * FROM sales_tran@sales ----------------------------------------------------------------------------------- 260
Clusters 1. It is a collection of tables 2. Data of multiple tables (having common cluster key) can be stored together in a single data segment by using clusters 3. This helps to save disk space as well as improve the performance of joins 4. Each data block stores the cluster key value and data from all the tables having same value of cluster key together in same data block CREATE CLUSTER cl_dept_emp ( deptno NUMBER(2) );
CREATE TABLE my_emp ( empno NUMBER(5) PRIMARY KEY, ename VARCHAR2(50), sal NUMBER(5), deptno NUMBER(2) REFERENCES my_dept ) CLUSTER cl_dept_emp (deptno); If cluster is empty then it can be dropped by using DROP CLUSTER cl_dept_emp but if it contains tables then you have to use INCLUDING TABLES clause. In case one of the tables of this cluster has a parent key that is referred by the foreign key of the table which is not the part of this cluster, you have to use CASCADE CONSTRAINTS clause 261
TEMPORARY TABLES: In Oracle, there is a feature of global temporary tables (So called as Temporary Tables). There are two types of Temporary Tables 1. Transaction Specific Temporary Tables 2. Session Specific Temporary Tables
Structure of the table is permanent like a normal table, but rows (data) are temporary. Oracle uses temporary segment to store the data of temporary tables Alter and Drop operations can be perform only when no session is bound to it Session get bound after issuing an insert statement Data store in the temporary table is private to the session and stored in the separate temporary segment for every session Data is removed for Transaction Specific Temporary Table when commit or rollback or truncate is issued or session is closed, but for Session Specific Temporary Table data is removed when the session is closed or truncate issues USE OF TEMPORARY TABLES: Temporary tables are used for improving the performance of PL/SQL code or for generating the reports
To create temporary table: (Session Specific Temporary Tables) CREATE GLOBAL TEMPORARY TABLE t_emp ( empno NUMBER(5), ename VARCHAR2(25), sal NUMBER(5) ) ON COMMIT PRESERVE ROWS /
To insert data into the table: INSERT INTO t_emp VALUES (1001,ANIL, 5600); SQL> SELECT * FROM t_emp; EMPNO ENAME SAL ---------- ------------------------- ---------- 1001 ANIL 5600 Open another session with same user: 262
SELECT * FROM t_emp; No rows selected DROP TABLE t_emp;
To create temporary table: (Transaction Specific Temporary Tables) CREATE GLOBAL TEMPORARY TABLE t_emp ( empno NUMBER(5), ename VARCHAR2(25), sal NUMBER(5) ) ON COMMIT DELETE ROWS / INSERT INTO t_emp VALUES (1001,ANIL, 5600); SQL> SELECT * FROM t_emp; EMPNO ENAME SAL ---------- ------------------------- ---------- 1001 ANIL 5600 COMMIT; SELECT * FROM t_emp; No rows selected MATERIALIZED VIEW: Materialized view is a schema object consumes the disk space The following are the areas for real time use of materialized vies 1) DWH applications(Decision Support System)
In this case aggregate data of historical tables can be stored in the materialized views, so that you dont need to write the queries on historical tables again and again In state these queries are written against materialized view Materialized view can be said to refresh at the periodic interval
2) Distributed Database System
In this case it can be used as a replacement to the snapshot Snap shot is read only where as materialized view is writeable 263
3) Mobile Computing In mobile computing, it is used to get the data from centralized database into local database of laptop, mobile, etc. As well as changes made to the materialized view, data can be refreshed back to the centralized server
Example of MV CREATE MATERIALIZED VIEW mv_emp REFRESH START WITH SYSDATE NEXT NEXT_DAY(SYSDATE,'MONDAY') AS SELECT e.deptno,dname,loc,sum(sal) sum_sal,avg(sal) avg_sal, max(sal) max_sal,min(sal) min_sal FROM emp e,dept d WHERE e.deptno=d.deptno GROUP BY e.deptno,dname,loc /
SELECT * FROM mv_emp; Pseudo Columns 1) Uid(user id) : It will give you the id given by oracle to that user SELECT uid FROM DUAL; 2) USER : It will give you the name of the user SELECT user FROM DUAL; 3) Rowid : It will give the address of particular row address SELECT ename,rowed FROM emp; 4) Rownum : It will give you the running serial number of that record SELECT rownum,ename FROM emp;
264
LIST OF PREDEFINED PACKAGES 1) UTL_FILE : It is used for input, output operations from/to the flat files It contains the procedures and functions that are used to generate write to the flat file (or) read to the flat file It is used widely for interface programming
2) DBMS_JOBS : It is used to schedule the process 3) DBMS_PIPE : It is used to communicate between the sessions , not widely used 4) DBMS_LOB : It is used to perform read/write operations to perform on large objects 5) DBMS_SQL : It is used to execute dynamic sequel statements 6) DBMS_OUTPUT : It is used to show the output of PL/SQL block 7) UTL_MAIL : It is used to perform email operations 8) OWA_UTIL : The OWA_UTIL package contains utility subprograms for performing operations such as getting the value of CGI environment variables, printing the data that is returned to the client, and printing the results of a query in an HTML table INDEX ORGANIZED TABLE: 1) In this case entire data of the table is stored in an index segment 2) This table must have a primary key 3) Rows of this table are accessed by using primary key 4) You can not create indexes on any of the columns of this table
CREATE TABLE emp ( Empno NUMBER(5) PRIMARY KEY, Ename VARCHAR(25), Sal NUMBER(5) ) ORGANIZATION INDEX /
265
NO COPY Compiler hint: No copy compiler hint is very important with respect to improving the performance Incase of IN mode, formal parameter and actual parameter both share the same memory location i.e., when actual parameter data is not copied ,but incase of OUT and IN OUT value of formal parameter copied to the formal parameter and then when program exit, values of formal parameter is copied into actual parameter All this coping takes time and impacts the performance if the program Generally NO COPY should be used when you are passing collections or big objects as a parameters. DECLARE TYPE EmpTabTyp IS TABLE OF emp%ROWTYPE; emp_tab EmpTabTyp := EmpTabTyp(NULL); -- initialize t1 NUMBER(5); t2 NUMBER(5); t3 NUMBER(5);
PROCEDURE get_time (t OUT NUMBER) IS BEGIN SELECT TO_CHAR(SYSDATE,'SSSSS') INTO t FROM dual; END;
PROCEDURE do_nothing1 (tab IN OUT EmpTabTyp) IS BEGIN NULL; END;
PROCEDURE do_nothing2 (tab IN OUT NOCOPY EmpTabTyp) IS BEGIN NULL; END;
BEGIN SELECT * INTO emp_tab(1) FROM emp WHERE empno = 7788; emp_tab.EXTEND(24999, 1); -- copy element 1 into 2..25000
get_time(t1); do_nothing1(emp_tab); -- pass IN OUT parameter
get_time(t2); do_nothing2(emp_tab); -- pass IN OUT NOCOPY parameter get_time(t3);
BITMAP INDEX : A. Employee Table Rowid Empno Ename Sal Deptno F001 1001 A 4000 20 F002 1002 B 5000 10 F003 1003 C 7720 10 F004 1004 D 8522 20 F005 1005 E 2222 10
B. Binary Search Index C. BITMAP Index Deptno Rowid 10 F002 10 F003 10 F005 20 F001 20 F004
1. When you create the Bitmap index Oracle stores unique values of the index keys as the columns and for every record it stores either one or zero in that corresponding columns based on the value of the column which has bitmap index. As written above (A) one will be stored for the records which has that corresponding column value and for rest of the columns it will store zero. 2. When the filter condition are used on the Indexed columns Oracle will load the Index segment into the database buffer cache and filter all those records whose bits are ON i.e 1 of that corresponding column value, applies a map function to convert that bit to the corresponding Rowid and gets only those records from the data segment. 3. Oracle Corporation recommends you to create bitmap index only on the columns which has large amount of duplicate values. Also create bitmap indexes only on those columns which are not modified frequently.
10 20 30 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0 267
SDLC Stages 1. Plan 2. Define 3. Design 4. Build 5. Test 6. Install & Acceptance Phase Resources Involved Out put Plan Project Manager, Account Manager, Program Manager High Level Project plan with milestones, WBS, Detailed level project plan etc. Define Users, BA, Domain Experts FRS, SRS, Use Cases, Approach Document, GAP document Design Functional experts, technical experts, designers, PL, ML HLD, LLD, Working prototypes, Test scenarios Build PL, ML, Developers Source code, Unit test results Test Testers, Test Leads, PL, ML, Developers Certified source code, System test cases and results. QC certification to release the code on UAT. Install DBA, CIC UAT env. Acceptance User Accepted code and User acceptance cases and results. Finally user acceptance to go live.
PERFORMANCE TUNING
1. Performance tuning can be done at three levels a. Database level b. Code level c. Hardware configuration level Out of the above levels Code level tuning can be done at developer level, even in the code level tuning the tuning can be done at front end code as well as back end code. Tuning the code can be done at three stages : 1.1. Identification 1.2. Analysis and Design 1.3. Fix
1.1. Identification At this stage you have to identify the code that requires tuning and fix. To do so you can use following techniques :- 1.1.1. Find out the queries that are taking time or in other words costly queries that are using maximum hardware and database resources. This can be done by running a select statement on the data dictionary tables. 1.1.2. User of AWR report By using this report you can find out the code and queries that are having problem. 1.1.3. Use of TKPROF utility (Refer Slide for details)
2. Analysis and Design :- 268
2.1. Once code / query for tuning is identified you have to find out the most efficient way to tune the code. At this stage you may have to use Explain plan statement to get the execution plan for further analysis and changes, and if required you have to redesign the code or queries.
2.2. To understand the Execution plan for the given SQL statement you have to use Explain Plan Statement.
2.3. Explain Plan Statement will store the Execution plan of the given SQL statement into the table PLAN_TABLE.
2.4. PLAN_TABLE must be created into you schema and to do so you have to use UTLXPLAN.sql script.
2.5. Oracle Optimizer is responsible for selection of most efficient execution plan for the given statement.
2.6. There are two methods of optimization 2.6.1. Cost based optimization 2.6.2. Rule based optimization In the current version of Oracle, Rule based optimization is not supported and Oracle uses only Cost based optimization. 2.6.2.1. Cost Based Optimizer chooses the most efficient execution plan based on the cost of that plan. Cost is calculated based on the Statistics of the objects referred in that SQL statement. These statistics are stored in the Data dictionary tables and they can be generated either by using ANALYZE statement or by using DBMS_STATS package. Generally on the production environment objects are analyzed either every week or bi-weekly basis.
3. Fixing while fixing you have to consider following points.
3.1. In case of joins identify driving table which has less number of rows. This reduces the time taken for the join. Driving table is the one which is mention in the end of the from clause.
3.2. While writing the queries follow the coding standards accurately so that there will be uniformed way to write the same statements. This will help to use the same shared SQL area.
3.3. User temporary tables wherever necessary.
3.4. User BULK BINDING (FOR ALL/BULK COLLECT)
269
3.5. Use NO COPY Compiler HINT
3.6. When there are multiple conditions in where clauses specify that condition in last which filters maximum numbers of rows.
Normalization is the process of efficiently organizing data in a database. There are two goals of the normalization process: eliminating redundant data (for example, storing the same data in more than one table) and ensuring data dependencies make sense (only storing related data in a table). Both of these are worthy goals as they reduce the amount of space a database consumes and ensure that data is logically stored. The Normal Forms The database community has developed a series of guidelines for ensuring that databases are normalized. These are referred to as normal forms and are numbered from one (the lowest form of normalization, referred to as first normal form or 1NF) through five (fifth normal form or 5NF). In practical applications, you'll often see 1NF, 2NF, and 3NF along with the occasional 4NF. Fifth normal form is very rarely seen and won't be discussed in this article. First Normal Form (1NF) sets the very basic rules for an organized database: Eliminate duplicative columns from the same table. Create separate tables for each group of related data and identify each row with a unique column (the primary key). What do these rules mean when contemplating the practical design of a database? It's actually quite simple. The first rule dictates that we must not duplicate data within the same row of a table. Within the database community, this concept is referred to as the atomicity of a table. Tables that comply with this rule are said to be atomic. Let's explore this principle with a classic example - a table within a human resources database that stores the manager-subordinate relationship. For the purposes of our example, 270
we'll impose the business rule that each manager may have one or more subordinates while each subordinate may have only one manager. Intuitively, when creating a list or spreadsheet to track this information, we might create a table with the following fields: Manager Subordinate1 Subordinate2 Subordinate3 Subordinate4 However, recall the first rule imposed by 1NF: eliminate duplicative columns from the same table. Clearly, the Subordinate1-Subordinate4 columns are duplicative. Take a moment and ponder the problems raised by this scenario. If a manager only has one subordinate - the Subordinate2-Subordinate4 columns are simply wasted storage space (a precious database commodity). Furthermore, imagine the case where a manager already has 4 subordinates - what happens if she takes on another employee? The whole table structure would require modification. At this point, a second bright idea usually occurs to database novices: We don't want to have more than one column and we want to allow for a flexible amount of data storage. Let's try something like this: Manager Subordinates Where the Subordinates field contains multiple entries in the form "Mary, Bill, Joe" This solution is closer, but it also falls short of the mark. The subordinates column is still duplicative and non-atomic. What happens when we need to add or remove a subordinate? We need to read and write the entire contents of the table. That's not a big deal in this situation, but what if one manager had one hundred employees? Also, it complicates the process of selecting data from the database in future queries. Here's a table that satisfies the first rule of 1NF: Manager Subordinate In this case, each subordinate has a single entry, but managers may have multiple entries. Now, what about the second rule: identify each row with a unique column or set of columns (the primary key)? You might take a look at the table above and suggest the use of the subordinate column as a primary key. In fact, the subordinate column is a good candidate for a primary key due to the fact that our business rules specified that each subordinate may have only one manager. However, the data that we've chosen to store in our table makes this a less than ideal solution. What happens if we hire another employee named Jim? How do we store his manager-subordinate relationship in the database? It's best to use a truly unique identifier (such as an employee ID) as a primary key. Our final table would look like this: 271
Manager ID Subordinate ID 2 ND Normal Form Over the past month, we've looked at several aspects of normalizing a database table. First, we discussed the basic principles of database normalization. Last time, we explored the basic requirements laid down by the first normal form (1NF). Now, let's continue our journey and cover the principles of second normal form (2NF).
Recall the general requirements of 2NF: Remove subsets of data that apply to multiple rows of a table and place them in separate tables. Create relationships between these new tables and their predecessors through the use of foreign keys. These rules can be summarized in a simple statement: 2NF attempts to reduce the amount of redundant data in a table by extracting it, placing it in new table(s) and creating relationships between those tables.
Let's look at an example. Imagine an online store that maintains customer information in a database. They might have a single table called Customers with the following elements: CustNum FirstName LastName Address City State ZIP A brief look at this table reveals a small amount of redundant data. We're storing the "Sea Cliff, NY 11579" and "Miami, FL 33157" entries twice each. Now, that might not seem like too much added storage in our simple example, but imagine the wasted space if we had thousands of rows in our table. Additionally, if the ZIP code for Sea Cliff were to change, we'd need to make that change in many places throughout the database.
In a 2NF-compliant database structure, this redundant information is extracted and stored in a separate table. Our new table (let's call it ZIPs) might have the following fields: ZIP City State If we want to be super-efficient, we can even fill this table in advance -- the post office provides a directory of all valid ZIP codes and their city/state relationships. Surely, you've encountered a situation where this type of database was utilized. Someone taking an order might have asked you for your ZIP code first and then knew the city and state you were calling from. This type of arrangement reduces operator error and increases efficiency.
Now that we've removed the duplicative data from the Customers table, we've satisfied the first rule of 272
second normal form. We still need to use a foreign key to tie the two tables together. We'll use the ZIP code (the primary key from the ZIPs table) to create that relationship. Here's our new Customers table: CustNum FirstName LastName Address ZIP We've now minimized the amount of redundant information stored within the database and our structure is in second normal form! 3 RD Normal Form There are two basic requirements for a database to be in third normal form: Already meet the requirements of both 1NF and 2NF Remove columns that are not fully dependent upon the primary key. Imagine that we have a table of widget orders that contains the following attributes: Order Number Customer Number Unit Price Quantity Total Remember, our first requirement is that the table must satisfy the requirements of 1NF and 2NF. Are there any duplicative columns? No. Do we have a primary key? Yes, the order number. Therefore, we satisfy the requirements of 1NF. Are there any subsets of data that apply to multiple rows? No, so we also satisfy the requirements of 2NF. Now, are all of the columns fully dependent upon the primary key? The customer number varies with the order number and it doesn't appear to depend upon any of the other fields. What about the unit price? This field could be dependent upon the customer number in a situation where we charged each customer a set price. However, looking at the data above, it appears we sometimes charge the same customer different prices. Therefore, the unit price is fully dependent upon the order number. The quantity of items also varies from order to order, so we're OK there. What about the total? It looks like we might be in trouble here. The total can be derived by multiplying the unit price by the quantity, therefore it's not fully dependent upon the primary key. We must remove it from the table to comply with the third normal form. Perhaps we use the following attributes: Order Number Customer Number Unit Price Quantity 273
Now our table is in 3NF. But, you might ask, what about the total? This is a derived field and it's best not to store it in the database at all. We can simply compute it "on the fly" when performing database queries. For example, we might have previously used this query to retrieve order numbers and totals : SELECT OrderNumber, Total FROM WidgetOrders We can now use the following query: SELECT OrderNumber, UnitPrice * Quantity AS Total FROM WidgetOrders to achieve the same results without violating normalization rules.
Before we begin our discussion of the normal forms, it's important to point out that they are guidelines and guidelines only. Occasionally, it becomes necessary to stray from them to meet practical business requirements. However, when variations take place, it's extremely important to evaluate any possible ramifications they could have on your system and account for possible inconsistencies Ex. Normalize the below ORDNO ORDDATE CUSTNO CUSTNAME CADD1 CCITY CSTATE CPIN SUPNO SUPNAME SADD1 SCITY SSTATE SPIN ITEMNO ITEMNAME QTY PRICE TOTAL GRANDTOTAL
274
ADDITIONAL POINTS : 1. Normailzation is a process which is used to design the database. It helps to reduce the data redundancy by keeping data integrity. 2. Normalization is a set of guidelines which can be followed to normalize the relations stored in the database 3. There are 3 normal forms with guidelines which are used to normalize the database design. 4. Most complex to complex database designs can be normalized by using these guidelines of 3 normal forms. But still if more normalization is required 4NF and 5NF can be used.