Documente Academic
Documente Profesional
Documente Cultură
PL/SQL
5-1
User-Defined Records
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 3
User-Defined Records
Self-reading
Purpose
• Up to this point, our SELECT statements (inside our
PL/SQL blocks) have been fairly simple, generally storing
one or two columns from a table INTO one or two
variables.
• What if you want to create and use a variable structure
(called a record) that corresponds to an entire row in a
table, or a view, or a join of several tables, rather than
using just one or two columns?
• Or maybe you need a record structure which does not
correspond to any object(s) in the database.
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 4
User-Defined Records
Self-reading
PL/SQL Records
• A PL/SQL record is a composite data type consisting of a
group of related data items stored as fields, each with
its own name and data type.
• You can refer to the whole record by its name and/or to
individual fields by their names.
• Typical syntax for defining a record is shown below. This
code defines a record based on the structure of a row
within the named table.
record_name table_name%ROWTYPE;
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 5
User-Defined Records
Self-reading
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 6
User-Defined Records
Self-reading
The Problem
• The EMPLOYEES table contains eleven columns:
EMPLOYEE_ID, FIRST_NAME,...., MANAGER_ID,
DEPARTMENT_ID.
• You need to code a SELECT * INTO variable names
FROM EMPLOYEES WHERE… in your PL/SQL
subprogram.
• How many scalar variables must you DECLARE to hold
the column values?
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 7
User-Defined Records
Self-reading
The Problem
• That is a lot of coding, and some tables will have even more
columns.
• Plus, what do you do if a new column is added to the table?
• Or an existing column is dropped?
DECLARE
v_employee_id employees.employee_id%TYPE;
v_first_name employees.first_name%TYPE;
v_last_name employees.last_name%TYPE;
v_email employees.email%TYPE;
... FIVE MORE SCALAR VARIABLES REQUIRED TO MATCH THE TABLE
v_manager_id employees.manager_id%TYPE;
v_department_id employees.department_id%TYPE;
BEGIN
SELECT employee_id, first_name, ... EIGHT MORE HERE, department_id
INTO v_employee_id, v_first_name, ... AND HERE, v_department_id
FROM employees
WHERE employee_id = 100;
END;
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 8
User-Defined Records
Self-reading
The Problem
• Look at the code again. Wouldn’t it be easier to declare
one variable instead of eleven?
• %ROWTYPE allows us to declare a variable as a record
based on a particular table's structure.
• Each field or component within the record will have its
own name and data type based on the table's structure.
• You can refer to the whole record by its name
and to individual fields by their names.
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 9
User-Defined Records
Self-reading
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 10
User-Defined Records
Self-reading
DBMS_OUTPUT.PUT_LINE(v_emp_record.first_name ||
' ' || v_emp_record.last_name || ': Old Salary - ' ||
v_emp_record.salary || ', Proposed New Salary - ' ||
v_emp_copy_record.salary || '.');
END;
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 11
User-Defined Records
Defining Your Own Records
• What if you need data from a join of multiple tables?
• You can declare your own record structures containing
any fields you like.
• PL/SQL records:
– Must contain one or more components/fields of any scalar or
composite type
– Are not the same as rows in a database table
– Can be assigned initial values and can be defined as NOT NULL
– Can be components of other records (nested records).
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 12
User-Defined Records
Syntax for User-Defined Records
• Start with the TYPE keyword to define your record
structure.
• It must include at least one field and the fields may be
defined using scalar data types such as DATE,
VARCHAR2, or NUMBER, or using attributes such as
%TYPE and %ROWTYPE.
• After declaring the type, use the type_name to declare
a variable of that type.
TYPE type_name IS RECORD
(field_declaration[,field_declaration]...);
identifier type_name;
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 13
User-Defined Records
User-Defined Records: Example 1
• First, declare/define the type and a variable of that
type.
• Then use the variable and its components.
DECLARE
TYPE person_dept IS RECORD
(first_name employees.first_name%TYPE,
last_name employees.last_name%TYPE,
department_name departments.department_name%TYPE);
v_person_dept_rec person_dept;
BEGIN
SELECT e.first_name, e.last_name, d.department_name
INTO v_person_dept_rec
FROM employees e JOIN departments d
ON e.department_id = d.department_id
WHERE employee_id = 200;
DBMS_OUTPUT.PUT_LINE(v_person_dept_rec.first_name ||
' ' || v_person_dept_rec.last_name || ' is in the ' ||
v_person_dept_rec.department_name || ' department.');
END;
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 14
User-Defined Records
User-Defined Records: Example 2
• Here we have two custom data types, one nested within
the other.
• How many fields can be addressed in
v_emp_dept_rec?
DECLARE
TYPE dept_info_type IS RECORD
(department_id departments.department_id%TYPE,
department_name departments.department_name%TYPE);
TYPE emp_dept_type IS RECORD
(first_name employees.first_name%TYPE,
last_name employees.last_name%TYPE,
dept_info dept_info_type);
v_emp_dept_rec emp_dept_type;
BEGIN
...
END;
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 15
User-Defined Records
Declaring and Using Types and Records
• Types and records are composite structures that can be
declared anywhere that scalar variables can be declared
in anonymous blocks, procedures, functions, package
specifications (global), package bodies (local), triggers,
and so on.
• Their scope and visibility follow the same rules as for
scalar variables.
• For example, you can declare a type (and a record based
on the type) in an outer block and reference them
within an inner block.
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 16
User-Defined Records
Visibility and Scope of Types and Records
• The type and the record declared in the outer block are
visible within the outer block and the inner block.
• What will be displayed by each of the PUT_LINEs?
DECLARE -- outer block
TYPE employee_type IS RECORD
(first_name employees.first_name%TYPE := 'Amy');
v_emp_rec_outer employee_type;
BEGIN
DBMS_OUTPUT.PUT_LINE(v_emp_rec_outer.first_name);
DECLARE -- inner block
v_emp_rec_inner employee_type;
BEGIN
v_emp_rec_outer.first_name := 'Clara';
DBMS_OUTPUT.PUT_LINE(v_emp_rec_outer.first_name ||
' and ' || v_emp_rec_inner.first_name);
END;
DBMS_OUTPUT.PUT_LINE(v_emp_rec_outer.first_name);
END;
PLSQL S5L1 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 17
User-Defined Records
Database Programming with
PL/SQL
5-2
Indexing Tables of Records
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 4
Indexing Tables of Records
What is a Collection?
• A PL/SQL collection is a named set of many occurrences
of the same kind of data stored as a variable.
• A collection is a type of composite variable, similar to
user-defined records.
• This lesson discusses INDEX BY tables and INDEX BY
tables of records.
• There are other types of collection variables, for
instance, Nested Tables and Varrays, but they are
outside the scope of this course.
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 5
Indexing Tables of Records
What is a Collection?
• You will see two kinds of collections in this lesson:
– An INDEX BY table, which is based on a single field or
column; for example, the last_name column of the
EMPLOYEES table.
– An INDEX BY table of records, which is based on a composite
record type; for example, the row structure in the
DEPARTMENTS table.
• Because collections are PL/SQL variables, they are
stored in memory like other PL/SQL variables.
• They are not stored on the disk like data in a database
table.
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 6
Indexing Tables of Records
An INDEX BY Table Has a Primary Key
• We need to be able to reference each row in an INDEX
BY table.
• Therefore, every INDEX BY table must have a primary
key which serves as an index to the data.
• The primary key is typically a BINARY_INTEGER, but
it may be a VARCHAR2.
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 7
Indexing Tables of Records
INDEX BY Table Structure
The primary key could be meaningful business data such
as an employee id.
100 Jones
157 Smith
135 Maduro
… …
BINARY_INTEGER Scalar
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 8
Indexing Tables of Records
Declaring an INDEX BY Table
• Like user-defined records, you must first declare a type
and then declare a variable of that type.
• The syntax is:
TYPE type_name IS TABLE OF DATA_TYPE
INDEX BY PRIMARY_KEY_DATA_TYPE;
identifier type_name;
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 9
Indexing Tables of Records
Populating an INDEX BY Table
• The syntax to populate the INDEX BY table is:
DECLARE
TYPE type_name IS TABLE OF DATA_TYPE
INDEX BY PRIMARY_KEY_DATA_TYPE;
identifier type_name;
BEGIN
FOR record IN (SELECT column FROM table)
LOOP
identifier(primary_key) := record.column;
END LOOP;
END;
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 10
Indexing Tables of Records
Populating an INDEX BY Table
This example populates an INDEX BY table with the hire
date of employees using employee_id as the primary
key.
DECLARE
TYPE t_hire_date IS TABLE OF employees.hire_date%TYPE
INDEX BY BINARY_INTEGER;
v_hire_date_tab t_hire_date;
BEGIN
FOR emp_rec IN
(SELECT employee_id, hire_date FROM employees)
LOOP
v_hire_date_tab(emp_rec.employee_id)
:= emp_rec.hire_date;
END LOOP;
END;
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 11
Indexing Tables of Records
Populating an INDEX BY Table
This example populates an INDEX BY table with
employees’ date of hire and sets the primary key using a
sequence derived from incrementing v_count.
DECLARE
TYPE t_hire_date IS TABLE OF employees.hire_date%TYPE
INDEX BY BINARY_INTEGER;
v_hire_date_tab t_hire_date;
v_count BINARY_INTEGER := 0;
BEGIN
FOR emp_rec IN
(SELECT hire_date FROM employees)
LOOP
v_count := v_count + 1;
v_hire_date_tab(v_count) := emp_rec.hire_date;
END LOOP;
END;
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 12
Indexing Tables of Records
Using INDEX BY Table Methods
• You can use built-in procedures and functions (called
methods) to reference single elements of the INDEX
BY table, or to read successive elements.
• The available methods are:
EXISTS PRIOR
COUNT NEXT
FIRST DELETE
LAST TRIM
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 13
Indexing Tables of Records
Using INDEX BY Table Methods
This example demonstrates the method COUNT.
DECLARE
TYPE t_hire_date IS TABLE OF employees.hire_date%TYPE
INDEX BY BINARY_INTEGER;
v_hire_date_tab t_hire_date;
v_hire_date_count NUMBER(4);
BEGIN
FOR emp_rec IN
(SELECT employee_id, hire_date FROM employees)
LOOP
v_hire_date_tab(emp_rec.employee_id)
:= emp_rec.hire_date;
END LOOP;
DBMS_OUTPUT.PUT_LINE(v_hire_date_tab.COUNT);
END;
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 14
Indexing Tables of Records
INDEX BY Table of Records
• Even though an INDEX BY table can have only one data
field, that field can be a composite data type such as a
RECORD.
• This is an INDEX BY table of records.
• The record can be %ROWTYPE or a user-defined record.
• This example declares an INDEX BY table to store
complete rows from the EMPLOYEES table:
DECLARE
TYPE t_emp_rec IS TABLE OF employees%ROWTYPE
INDEX BY BINARY_INTEGER;
v_employees_tab t_emprec;
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 15
Indexing Tables of Records
INDEX BY Table of Records
• Individual fields within a table of records can be
referenced by adding an index value in parentheses after
the table of records name.
• Syntax: table(index).field
• Example: v_employees_tab(index).hire_date
The index value in the example could be an actual value
(ex. 1, 5, 12, etc.) or a reference to a value
(v_emp_rec_tab.LAST).
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 16
Indexing Tables of Records
Using an INDEX BY Table of Records
This example is similar to the earlier INDEX BY table
example, but stores the entire EMPLOYEES row and
displays the salary from each row.
DECLARE
TYPE t_emp_rec IS TABLE OF employees%ROWTYPE
INDEX BY BINARY_INTEGER;
v_emp_rec_tab t_emp_rec;
BEGIN
FOR emp_rec IN (SELECT * FROM employees) LOOP
v_emp_rec_tab(emp_rec.employee_id) := emp_rec;
DBMS_OUTPUT.PUT_LINE(
v_emp_rec_tab(emp_rec.employee_id).salary);
END LOOP;
END;
PLSQL S5L2 Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 17
Indexing Tables of Records