PL/SQL by Example / Scalar Data Types
Data types in PL/SQL are divided into three basic categories: scalar, composite, and reference. Scalar types typically store only a single value, composite types hold arrays of values, or they can be more complex structures like records or objects. A reference data type serves as a pointer.
Boolean and Number
The previous part, in addition to code structure and control flow, introduced two basic data types in a simplified way – number and boolean. The following example demonstrates two, or rather three, methods of assigning a value to a variable: default initialization in the declarative part, assignment in the execution part, and assignment using an SQL query with the INTO
keyword.
DECLARE l_Bool BOOLEAN; -- boolean data type, cannot be used in SQL l_Number NUMBER:=100; -- number type BEGIN l_Number:=200; SELECT 300 INTO l_Number FROM dual -- auxiliary system table ; IF (l_Bool IS NULL) THEN -- default value of a variable is always NULL dbms_output.put_line(l_Number); -- 300 END IF; END;
The NUMBER
data type can store both integer values and floating-point values. Precision (total number of digits) and scale (number of digits after the decimal point) can be specified manually. If not specified, the maximum precision and scale are used. In PL/SQL, we can also work with various numeric subtypes, such as INT
, which internally maps to NUMBER(38,0)
. For maximum simplification, I will only use NUMBER
from now on; more information about numeric data types can be found in the documentation.
Character and String
The CHAR
type is used for working with strings of a predetermined fixed length, while VARCHAR2
is used for variable-length strings. The maximum size depends on the configuration and the chosen character set, and again, can be found in the documentation. However, it generally holds that for very long text, using the CLOB
(“Character Large Object”) data type is more appropriate. String concatenation and basic functions for working with them are described in the following example.
DECLARE l_Character CHAR(1):='A'; -- fixed size l_String VARCHAR2(4000):='apple'; -- maximum size BEGIN -- string concatenation using double pipes dbms_output.put_line(l_String||' '||l_Character); -- apple A -- substring extraction dbms_output.put_line(SUBSTR(l_String, 1, 3)); -- app -- position within the string dbms_output.put_line(INSTR(l_String, 'pl')); -- 3 -- replacement dbms_output.put_line(REPLACE(l_String, 'p', 'P')); -- aPPle END;
Date
For storing dates, Oracle uses the DATE
type, which includes the year, month, day, hour, minute, and second. Assignment is done using the TO_DATE()
function, and conversion to a human-readable string is done with the TO_CHAR()
function. Both functions accept a format as their second parameter.
DECLARE l_Date DATE; l_String VARCHAR2(20); BEGIN l_Date:=TO_DATE('1.1.2016', 'DD.MM.YYYY'); -- assignment -- implicit conversion according to database settings l_String:=l_Date; dbms_output.put_line(l_String); -- 01.01.16 -- explicit conversion using format l_String:=TO_CHAR(l_Date, 'DD.MM.YYYY'); dbms_output.put_line(l_String); -- 01.01.2016 -- retrieving and converting the current date l_String:=TO_CHAR(SYSDATE, 'HH24:MI:SS DD.MON.YY'); dbms_output.put_line(l_String); -- 17:30:12 21.MAR.16 -- retrieving and converting to the name of the day of the week l_String:=TO_CHAR(SYSDATE, 'DAY'); dbms_output.put_line(l_String); -- MONDAY -- overriding the database language setting l_String:=TO_CHAR(SYSDATE, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH'); dbms_output.put_line(l_String); -- MON END;
Basic date operations like adding an hour, day, or month are summarized in the following example.
DECLARE l_Date DATE:=TO_DATE('01.01.2016', 'DD.MM.YYYY'); BEGIN -- adding a day dbms_output.put_line(l_Date+1); -- 02.01.16 -- adding an hour dbms_output.put_line(TO_CHAR(l_Date+1/24, 'HH24:MI')); -- 01:00 -- adding a month dbms_output.put_line(ADD_MONTHS(l_Date, 1)); -- 01.02.16 -- subtracting a year dbms_output.put_line(ADD_MONTHS(l_Date, -12)); -- 01.01.15 -- last day of the month dbms_output.put_line(LAST_DAY(l_Date)); -- 31.01.16 -- rounded difference in months dbms_output.put_line(ROUND(MONTHS_BETWEEN(l_Date+80, l_Date))); -- 3 END;
%TYPE
If we are unsure about the data type or if it might change over time, we can choose to declare it based on another variable or a table column.
DECLARE l_Number NUMBER; l_Employee_ID l_Number%TYPE; -- NUMBER l_FirstName employees.first_name%TYPE; -- VARCHAR2(20) BEGIN l_Employee_ID:=100; l_FirstName:='Steven'; dbms_output.put_line(l_Employee_ID||' '||l_FirstName); -- 100 Steven END;
Constant and NOT NULL Clause
The PL/SQL language also supports constants, which cannot be overwritten with another value within the block’s body. The NOT NULL
clause, which checks if a given variable is initialized, is also very useful.
DECLARE L_NUMBER CONSTANT NUMBER:=100; -- constant l_Bool BOOLEAN NOT NULL:=FALSE; -- non-NULL type BEGIN -- CANNOT DO L_NUMBER:=200; -- CANNOT DO l_Bool:=NULL; IF (NOT l_Bool) THEN dbms_output.put_line(L_NUMBER); -- 100 END IF; END;
Maximum Size of Basic Data Types
Data Type | Size in SQL | Size in PL/SQL |
---|---|---|
NUMBER |
± 999…(38 “nines”) | ± 999…(38 “nines”) |
CHAR |
2000 bytes * | 32767 bytes * |
VARCHAR2 |
4000 bytes * | 32767 bytes * |
CLOB |
8 TB to 128 TB ** | 128 TB |
* note that different characters have different sizes in UTF-8
** depends on the database block size setting