Character Sets and Lexical Units
PL/SQL supports two character sets: the database character set, which is used for identifiers and source code, and the national character set (NCHAR and NVARCHAR2), which is used for national language data..
PL/SQL keywords are not case-sensitive, so lower-case letters are equivalent to corresponding upper-case letters except within string and character literals.
PL/SQL programs are written as lines of text which contains groups of characters known as lexical units:
- Delimiters (simple and compound symbols)
- Identifiers, which include reserved words
- Literals
- Comments
You must separate adjacent identifiers by a space or punctuation. For example:
IF x > y THEN high := x; END IF; -- correct IF x > y THEN high := x; ENDIF; -- incorrect
You cannot embed spaces inside lexical units (except string literals and comments). For example:
count := count + 1; -- correct count : = count + 1; -- incorrect
PL/SQL Delimiters:
| Symbol | Meaning | Symbol | Meaning |
|---|---|---|---|
+ | addition operator | % | attribute indicator |
' | character string delimiter | . | component selector |
/ | division operator | ( | expression or list delimiter |
) | expression or list delimiter | : | host variable indicator |
, | item separator | * | multiplication operator |
" | quoted identifier delimiter | = | relational operator |
< | relational operator | > | relational operator |
@ | remote access indicator | ; | statement terminator |
- | subtraction/negation operator | := | assignment operator |
=> | association operator | || | concatenation operator |
** | exponentiation operator | .. | range operator |
<< | label delimiter (begin) | >> | label delimiter (end) |
/* | multi-line comment delimiter (begin) | */ | multi-line comment delimiter (end) |
<> | relational operator | != | relational operator |
~= | relational operator | ^= | relational operator |
<= | relational operator | >= | relational operator |
-- | single-line comment indicator |
Identifiers
You use identifiers to name PL/SQL program items and units, which include constants, variables, exceptions, cursors, cursor variables, subprograms, and packages.
The minimum length of an identifier is one character; the maximum length is 30 characters.
The first character must be a letter, but each later character can be either a letter, numeral, dollar sign ($), underscore (_), or number sign (#).
Characters that are not allowed in identifiersare ampersand (&),hyphen (-), lash (/) and space.
Predefined Identifiers globally declared in package STANDARD, such as the exception INVALID_NUMBER, can be redeclared. However, redeclaring predefined identifiers is error prone because your local declaration overrides the global declaration.
Quoted Identifiers lets you enclose identifiers within double quotes. Quoted identifiers are seldom needed, but occasionally they can be useful. They can contain any sequence of printable characters including spaces but excluding double quotes.
Both reserved words and keywords have special meaning in PL/SQL. The difference between reserved words and keywords is that you cannot use reserved words as identifiers. You can use keywords as as identifiers, but it is not recommended.
Literals
Numeric Literals: Two kinds of numeric literals can be used in arithmetic expressions: integers and reals. An integer literal is an optionally signed whole number without a decimal point. For example:
030 6 -14 0 +32767 -1E38 -9.5e-3 -- Integer Literal 6.6667 0.0 -12.0 3.14159 +8300.00 .5 25.0 2.0f 2.0d -- Real Literal
String Literals: A character value can be represented by an identifier or explicitly written as a string literal, which is a sequence of zero or more characters enclosed by single quotes. All string literals except the null string ('') have data type CHAR.. For example:
'Hello, world!' 'XYZ Corporation' '10-NOV-91' 'He said "Life is like licking honey from a thorn."' '$1,000,000' PL/SQL is case sensitive within string literals. For example, PL/SQL considers the following literals to be different: 'baker' 'Baker' To represent an apostrophe within a string, you can write two single quotes, which is not the same as writing a double quote: 'I''m a string, you''re a string.'
Character Literals:A character literal is an individual character enclosed by single quotes ('). Character literals include all the printable characters in the PL/SQL character set: letters, numerals, spaces, and special symbols. For example:
'Z' '%' '7' ' ' 'z' '('
BOOLEAN Literals:BOOLEAN literals are the predefined values TRUE, FALSE, and NULL. NULL stands for a missing, unknown, or inapplicable value. Remember, BOOLEAN literals are values, not strings. For example, TRUE is no less a value than the number 25.
Comments
The PL/SQL compiler ignores comments. Adding comments to your program promotes readability and aids understanding. There are two types of comments.
-- single line comment indicator /* multimple line comment indicator */
Declarations
Your program stores values in variables and constants. As the program executes, the values of variables can change, but the values of constants cannot.
You can declare variables and constants in the declarative part of any PL/SQL block, subprogram, or package. Declarations allocate storage space for a value, specify its data type, and name the storage location so that you can reference it.
Variables:
Variables are initialized every time a block or subprogram is entered. By default, variables are initialized to NULL.
DECLARE birthday DATE; emp_count SMALLINT := 0; pi REAL := 3.14159; radius REAL := 1; area REAL := pi * radius**2; BEGIN NULL; END; /
Constants:
To declare a constant, put the keyword CONSTANT before the type specifier.A constant must be initialized in its declaration. Constants are initialized every time a block or subprogram is entered.
DECLARE credit_limit CONSTANT REAL := 5000.00; max_days_in_year CONSTANT INTEGER := 366; urban_legend CONSTANT BOOLEAN := FALSE; BEGIN NULL; END; /
Using DEFAULT:
You can use the keyword DEFAULT instead of the assignment operator to initialize variables. You can also use DEFAULT to initialize subprogram parameters, cursor parameters, and fields in a user-defined record.
DECLARE blood_type CHAR DEFAULT 'O'; -- Same as blood_type CHAR := 'O'; hours_worked INTEGER DEFAULT 40; -- Typical value employee_count INTEGER := 0; -- No typical value BEGIN NULL; END; /
Using NOT NULL:
A declaration can impose the NOT NULL constraint, which prevents you from assigning a null value to the variable. Because variables are initialized to NULL by default, a declaration that specifies NOT NULL must also specify a default value.
PL/SQL subtypes NATURALN, POSITIVEN, and SIMPLE_INTEGER are predefined as NOT NULL. When declaring a variable of one of these subtypes, you can omit the NOT NULL constraint, and you must specify a default value.
DECLARE acct_id INTEGER(4) NOT NULL := 9999; a NATURALN := 9999; b POSITIVEN := 9999; c SIMPLE_INTEGER := 9999; BEGIN NULL; END; /
Using the %TYPE Attribute:
The %TYPE attribute lets you declare a constant, variable, field, or parameter to be of the same data type a previously declared variable, field, record, nested table, or database column. If the referenced item changes, your declaration is automatically updated.
An item declared with %TYPE (the referencing item) always inherits the data type of the referenced item. The referencing item inherits the constraints only if the referenced item is not a database column. The referencing item inherits the default value only if the referencing item is not a database column and does not have the NOT NULL constraint.
DECLARE
credit PLS_INTEGER RANGE 1000..25000;
debit credit%TYPE; -- inherits data type
name VARCHAR2(20) := 'JoHn SmItH';
upper_name name%TYPE; -- inherits data type and default value
lower_name name%TYPE; -- inherits data type and default value
init_name name%TYPE; -- inherits data type and default value
BEGIN
DBMS_OUTPUT.PUT_LINE ('name: ' || name);
DBMS_OUTPUT.PUT_LINE ('upper_name: ' || UPPER(name));
DBMS_OUTPUT.PUT_LINE ('lower_name: ' || LOWER(name));
DBMS_OUTPUT.PUT_LINE ('init_name: ' || INITCAP(name));
END;
/
If you add a NOT NULL constraint to the variable name in Example 2-10, and declare another variable that references it, you must specify a default value for the new item. For example:
Incorrect Way:
name VARCHAR2(20) NOT NULL := 'JoHn SmItH';
same_name name%TYPE;
Correct Way:
name VARCHAR2(20) NOT NULL := 'JoHn SmItH';
upper_name name%TYPE := UPPER(name);
lower_name name%TYPE := LOWER(name);
init_name name%TYPE := INITCAP(name);
The %TYPE attribute is particularly useful when declaring variables that refer to database columns. When you use table_name.column_name.%TYPE to declare a data item, you need not know the referenced data type or its attributes (such as precision, scale, and length), and if they change, you need not update your code. For example:
CREATE TABLE employees_temp (
empid NUMBER(6) NOT NULL PRIMARY KEY,
deptid NUMBER(6) CONSTRAINT c_employees_temp_deptid
CHECK (deptid BETWEEN 100 AND 200),
deptname VARCHAR2(30) DEFAULT 'Sales'
);
DECLARE
v_empid employees_temp.empid%TYPE;
v_deptid employees_temp.deptid%TYPE;
v_deptname employees_temp.deptname%TYPE;
BEGIN
v_empid := NULL; -- Null constraint not inherited
v_deptid := 50; -- Check constraint not inherited
DBMS_OUTPUT.PUT_LINE
('v_deptname: ' || v_deptname); -- Default value not inherited
END;
/
-- where employees_temp is a table in database
Using the %ROWTYPE Attribute:
The %ROWTYPE attribute lets you declare a record that represents a row in a table or view. For each column in the referenced table or view, the record has a field with the same name and data type. To reference a field in the record, use record_name.field_name.The record fields do not inherit the constraints or default values of the corresponding columns.
DECLARE
emprec employees_temp%ROWTYPE;
BEGIN
emprec.empid := NULL; -- Null constraint not inherited
emprec.deptid := 50; -- Check constraint not inherited
DBMS_OUTPUT.PUT_LINE
('emprec.deptname: ' || emprec.deptname);
-- Default value not inherited
END;
/
-- Declaring a Record that Represents a Subset of Table Columns
DECLARE
CURSOR c1 IS
SELECT department_id, department_name
FROM departments;
dept_rec c1%ROWTYPE; -- includes subset of columns in table
-- Declaring a Record that Represents a Row from a Join
CURSOR c2 IS
SELECT employee_id, email, employees.manager_id, location_id
FROM employees, departments
WHERE employees.department_id = departments.department_id;
join_rec c2%ROWTYPE; -- includes columns from two tables
Aggregate Assignment:
A %ROWTYPE declaration cannot include an initialization clause, but there are two ways to assign values to all fields of a record at once:
- If their declarations refer to the same table or cursor, you can assign one record to another.
DECLARE dept_rec1 departments%ROWTYPE; dept_rec2 departments%ROWTYPE; CURSOR c1 IS SELECT department_id, location_id FROM departments; dept_rec3 c1%ROWTYPE; dept_rec4 c1%ROWTYPE; BEGIN dept_rec1 := dept_rec2; -- declarations refer to same table dept_rec3 := dept_rec4; -- declarations refer to same cursor dept_rec2 := dept_rec3; -- Incorrect way END; /
DECLARE dept_rec departments%ROWTYPE; BEGIN SELECT * INTO dept_rec FROM departments WHERE department_id = 30 AND ROWNUM < 2; END; /
Naming Conventions
The same naming conventions apply to PL/SQL constants, variables, cursors, cursor variables, exceptions, procedures, functions, and packages. Names can be simple, qualified, remote, or both qualified and remote. For example:
- Simple—procedure name only:
raise_salary(employee_id, amount);
Qualified—procedure name preceded by the name of the package that contains it (this is called dot notation because a dot separates the package name from the procedure name):
emp_actions.raise_salary(employee_id, amount);
raise_salary@newyork(employee_id, amount);
emp_actions.raise_salary@newyork(employee_id, amount);
Scope
Within the same scope, all declared identifiers must be unique. Even if their data types differ, variables and parameters cannot share the same name.
DECLARE id BOOLEAN; id VARCHAR2(5); -- duplicate identifier BEGIN id := FALSE; END; / Error report: ORA-06550: line 5, column 3: PLS-00371: at most one declaration for 'ID' is permitted
Case Sensitivity
Like all identifiers, the names of constants, variables, and parameters are not case sensitive.
DECLARE zip_code INTEGER; Zip_Code INTEGER; BEGIN zip_code := 90120; END; / Error report: ORA-06550: line 5, column 3: PLS-00371: at most one declaration for 'ZIP_CODE' is permitted
Scope and Visibility of PL/SQL Identifiers
References to an identifier are resolved according to its scope and visibility. The scope of an identifier is the region of a PL/SQL unit from which you can reference the identifier. The visibility of an identifier is the region of a PL/SQL unit from which you can reference the identifier without qualifying it.
An identifier declared in a PL/SQL unit is local to that unit and global to its subunits. If a subunit redeclares a global identifier, then inside the subunit, both identifiers are in scope, but only the local identifier is visible. To reference the global identifier, the subunit must qualify it.
You cannot declare an identifier twice in the same PL/SQL unit, but you can declare the same identifier in two different units. The two items represented by the identifier are distinct, and changing one does not affect the other.
SET SERVEROUTPUT ON;
DECLARE
a CHAR; -- Scope of a (CHAR) begins
b REAL; -- Scope of b begins
BEGIN
-- Visible: a (CHAR), b
DECLARE
a INTEGER; -- Scope of a (INTEGER) begins
c REAL; -- Scope of c begins
BEGIN
-- Visible: a (INTEGER), b, c
NULL;
END; -- Scopes of a (INTEGER) and c end
DECLARE
d REAL; -- Scope of d begins
BEGIN
-- Visible: a (CHAR), b, d
NULL;
END; -- Scope of d ends
-- Visible: a (CHAR), b
END; -- Scopes of a (CHAR) and b end
/
Qualifying a Redeclared Global Identifier with a Block Label:
SET SERVEROUTPUT ON; <> DECLARE birthdate DATE := '09-AUG-70'; BEGIN DECLARE birthdate DATE; BEGIN birthdate := '29-SEP-70'; IF birthdate = outer.birthdate THEN DBMS_OUTPUT.PUT_LINE ('Same Birthday'); ELSE DBMS_OUTPUT.PUT_LINE ('Different Birthday'); END IF; END; END; /
CASE Expressions
There are two types of expressions used in CASE statements:
- Simple CASE Expression: A simple CASE expression selects a result from one or more alternatives, and returns the result. The CASE expression uses a selector, an expression whose value determines which alternative to return.
SET SERVEROUTPUT ON; DECLARE grade CHAR(1) := 'B'; appraisal VARCHAR2(20); BEGIN appraisal := CASE grade WHEN 'A' THEN 'Excellent' WHEN 'B' THEN 'Very Good' WHEN 'C' THEN 'Good' WHEN 'D' THEN 'Fair' WHEN 'F' THEN 'Poor' ELSE 'No such grade' END; DBMS_OUTPUT.PUT_LINE ('Grade ' || grade || ' is ' || appraisal); END; / - Searched CASE Expression: A searched CASE expression lets you test different conditions instead of comparing a single expression to various values.A searched CASE expression has no selector. Each WHEN clause contains a search condition that yields a BOOLEAN value, so you can test different variables or multiple conditions in a single WHEN clause.
SET SERVEROUTPUT ON; DECLARE grade CHAR(1) := 'B'; appraisal VARCHAR2(120); id NUMBER := 8429862; attendance NUMBER := 150; min_days CONSTANT NUMBER := 200; FUNCTION attends_this_school (id NUMBER) RETURN BOOLEAN IS BEGIN RETURN TRUE; END; BEGIN appraisal := CASE WHEN attends_this_school(id) = FALSE THEN 'Student not enrolled' WHEN grade = 'F' OR attendance < min_days THEN 'Poor (poor performance or bad attendance)' WHEN GRADE = 'A' THEN 'Excellent' WHEN grade = 'B' THEN 'Very Good' WHEN grade = 'C' THEN 'Good' WHEN grade = 'D' THEN 'Fair' ELSE 'No such grade' END; DBMS_OUTPUT.PUT_LINE ('Result for student ' || id || ' is ' || appraisal); END; /
Handling NULL Values in Comparisons and Conditional Statements
- When using NULL values, remember the following rules:
- Comparisons involving NULL values always yield NULL.
- Applying the logical operator NOT to a NULL value yields NULL.
- In conditional control statements, if the condition yields NULL, its associated sequence of statements is not executed.
- If the expression in a simple CASE statement or CASE expression yields NULL, it cannot be matched by using WHEN NULL. Instead, use a searched CASE syntax with WHEN expression IS NULL.
SET SERVEROUTPUT ON;
DECLARE
x NUMBER := 5;
y NUMBER := NULL;
z NUMBER := NULL;
BEGIN
IF x != y THEN -- yields NULL, not TRUE
DBMS_OUTPUT.PUT_LINE('x != y'); -- not executed
ELSIF x = y THEN -- also yields NULL
DBMS_OUTPUT.PUT_LINE('x = y');
ELSE
DBMS_OUTPUT.PUT_LINE
('Can''t tell if x and y are equal or not.');
END IF;
IF y = z THEN -- yields NULL, not TRUE
DBMS_OUTPUT.PUT_LINE('y = z'); -- not executed
ELSIF y != z THEN -- yields NULL, not TRUE
DBMS_OUTPUT.PUT_LINE('y != z'); -- not executed
ELSE
DBMS_OUTPUT.PUT_LINE('Can''t tell if two NULLs are equal');
END IF;
END;
/
Next Article: PL/SQL Datatypes
For any questions, suggestions or feedback, Please write to us. Thanks for Reading :)
No comments:
Post a Comment