Variables, Constants & Types
PL/SQL is a strongly typed language. Every variable has a data type known at compile time, which Oracle enforces to prevent runtime type surprises.
Declaring Variables
Variables are declared in the DECLARE section, one per line:
DECLARE
v_employee_id NUMBER(6); -- no initial value (NULL)
v_first_name VARCHAR2(20);
v_hire_date DATE;
v_salary NUMBER(8,2) := 0; -- initialized to 0
v_is_active BOOLEAN := TRUE;
v_department VARCHAR2(30) DEFAULT 'Unknown';
BEGIN
NULL;
END;
/
Naming Conventions
Oracle professionals prefix variable names to avoid confusion with column names:
| Prefix | Meaning |
|---|---|
v_ |
Local variable |
p_ |
Parameter |
c_ |
Constant |
g_ |
Package-level global |
l_ |
Loop/local |
Scalar Data Types
| Type | Description | Example |
|---|---|---|
NUMBER(p,s) |
Numeric, precision p, scale s | NUMBER(8,2) for salary |
PLS_INTEGER |
32-bit signed integer, fastest integer type | Loop counters |
BINARY_INTEGER |
Alias for PLS_INTEGER | Legacy code |
VARCHAR2(n) |
Variable-length string, max n bytes | VARCHAR2(100) |
CHAR(n) |
Fixed-length string, padded with spaces | CHAR(1) for flag |
DATE |
Date + time (to the second) | SYSDATE |
TIMESTAMP |
Date + time with fractional seconds | High-precision logging |
BOOLEAN |
TRUE, FALSE, or NULL — PL/SQL only, not a SQL type |
Flags |
CLOB |
Character Large Object, up to 128 TB | Long text |
BLOB |
Binary Large Object | Files, images |
Assignment Operator
PL/SQL uses := for assignment, not = (which is used only for comparison):
DECLARE
v_count PLS_INTEGER := 0;
v_name VARCHAR2(50);
v_today DATE;
BEGIN
v_count := v_count + 1;
v_name := 'Steven King';
v_today := SYSDATE;
-- String concatenation uses ||
DBMS_OUTPUT.PUT_LINE('Employee: ' || v_name || ', Count: ' || v_count);
END;
/
%TYPE — Anchored Declarations
%TYPE anchors a variable's type to a table column or another variable. If the column type changes, the variable automatically adapts — no code change needed:
DECLARE
-- Anchored to the column definition in the data dictionary
v_emp_id employees.employee_id%TYPE;
v_salary employees.salary%TYPE;
v_first_name employees.first_name%TYPE;
v_last_name employees.last_name%TYPE;
BEGIN
SELECT employee_id, salary, first_name, last_name
INTO v_emp_id, v_salary, v_first_name, v_last_name
FROM employees
WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE(
v_first_name || ' ' || v_last_name ||
' earns $' || TO_CHAR(v_salary, 'FM999,999.00')
);
END;
/
Output:
Steven King earns $24,000.00
%TYPE for variables that hold column values. It prevents silent truncation bugs when a VARCHAR2(20) column is later changed to VARCHAR2(50).
%ROWTYPE — Row Anchoring
%ROWTYPE declares a record that matches an entire table or view row. Covered in depth in the Records topic, but worth introducing here:
DECLARE
v_emp employees%ROWTYPE;
BEGIN
SELECT * INTO v_emp
FROM employees
WHERE employee_id = 101;
DBMS_OUTPUT.PUT_LINE(v_emp.first_name || ' — dept ' || v_emp.department_id);
END;
/
Constants
Constants are declared with the CONSTANT keyword and must be initialized. They cannot be modified after declaration:
DECLARE
c_max_salary CONSTANT NUMBER := 250000;
c_company_name CONSTANT VARCHAR2(50) := 'Acme Corp';
c_pi CONSTANT NUMBER := 3.14159265358979;
BEGIN
DBMS_OUTPUT.PUT_LINE('Max allowed: $' || c_max_salary);
-- c_max_salary := 300000; -- PLS-00363: cannot assign to a constant
END;
/
NOT NULL Constraint
Variables can be declared NOT NULL, forcing an initial value:
DECLARE
v_status VARCHAR2(10) NOT NULL := 'ACTIVE';
-- v_code NUMBER NOT NULL; -- PLS-00218: compile error, no default
BEGIN
-- v_status := NULL; -- PLS-00382: expression is of wrong type
DBMS_OUTPUT.PUT_LINE('Status: ' || v_status);
END;
/
Subtypes — User-Defined Type Aliases
SUBTYPE creates an alias for an existing type, optionally with constraints:
DECLARE
SUBTYPE t_name IS VARCHAR2(100);
SUBTYPE t_salary IS NUMBER(10,2) NOT NULL;
SUBTYPE t_percent IS NUMBER(5,2) RANGE 0 .. 100;
v_emp_name t_name := 'Steven King';
v_pay t_salary := 24000;
BEGIN
DBMS_OUTPUT.PUT_LINE(v_emp_name || ': $' || v_pay);
END;
/
Default Values
Both := and DEFAULT are valid for initial values:
DECLARE
v_region VARCHAR2(20) := 'EMEA'; -- := syntax
v_limit NUMBER DEFAULT 100; -- DEFAULT keyword
v_active BOOLEAN DEFAULT TRUE;
BEGIN
DBMS_OUTPUT.PUT_LINE('Region: ' || v_region || ', Limit: ' || v_limit);
END;
/
Multiple Assignments in One Statement
Oracle does not support a := b := 0; chaining. Assign variables individually:
DECLARE
v_a NUMBER;
v_b NUMBER;
v_c NUMBER;
BEGIN
v_a := 10;
v_b := 20;
v_c := v_a + v_b;
DBMS_OUTPUT.PUT_LINE('Sum: ' || v_c);
END;
/
NULL, not zero or empty string. Any arithmetic with NULL propagates NULL: 5 + NULL = NULL. Always initialize numeric counters to 0.
Summary
- Declare variables in the
DECLAREsection; use:=orDEFAULTfor initial values. - Use
%TYPEto anchor a variable to a column — adapts automatically to schema changes. - Use
%ROWTYPEto hold an entire table row. CONSTANTvariables cannot be reassigned after declaration.NOT NULLforces a variable to always have a value.BOOLEAN(TRUE/FALSE/NULL) exists in PL/SQL but not in Oracle SQL columns (pre-Oracle 23ai).PLS_INTEGERis the fastest integer type — prefer it for loop counters and arithmetic.