#

| Chapter 9 Records in PL/SQL |

## 9.6 Record Types and Record Compatibility

As we have discussed, PL/SQL supports three types of records: table-based, cursor-based, and programmer-defined. A record is defined by its name, its type, and its structure. Two records can have the same structure but be of a different type. PL/SQL places restrictions on certain operations between different record types. This section explains these restrictions based on the records declared below:

- The table structure against which all the different types of records will be declared:

>     CREATE TABLE cust_sales_roundup
>           (customer_id NUMBER (5),
>            customer_name VARCHAR2 (100),
>            total_sales NUMBER (15,2)
>           );

- The table-based record:

  >     cust_sales_roundup_rec cust_sales_roundup%ROWTYPE;

- The cursor-based record:

  >     CURSOR cust_sales_cur IS SELECT * FROM cust_sales_roundup;
  >     cust_sales_rec cust_sales_cur%ROWTYPE;

- The programmer-defined record:

  >     TYPE customer_sales_rectype IS RECORD
  >        (customer_id NUMBER (5),
  >         customer_name customer.name%TYPE,
  >         total_sales NUMBER (15,2)
  >        );
  >     top_customer_rec  customer_sales_rectype;

- A "manual" record: a collection of individual variables which the programmer can treat as a group by always making changes to and referring to all variables together:

  >     v_customer_id NUMBER (5);
  >     v_customer_name customer_name%TYPE;
  >     v_total_sales NUMBER (15,2);

All three PL/SQL records defined above (cust_sales_roundup_rec, cust_sales_rec, and top_customer_rec) and the "manual" record have exactly the same structure. Each, however, is of a different type. Records of different types are incompatible with each other at the record level. As a result, you can't perform certain kinds of operations between them.

### 9.6.1 Assignment Restrictions

Using the previously defined records, the following sections describe the various restrictions you will encounter due to incompatible record types.

#### 9.6.1.1 Manual records

You cannot assign a manual record to a real record of any type, and vice versa. If you want to assign individual variables to a record, or assign values in fields to individual variables, you must execute a separate assignment for each field in the record:

>     top_customer_rec.customer_id := v_customer_id;
>     top_customer_rec.customer_name := v_customer_name;
>     top_customer_rec.total_sales := v_total_sales;

#### 9.6.1.2 Records of the same type

You can perform aggregate assignments only between records of the same type and same source. All of the aggregate assignments you saw in previous examples were valid because both the source and target records in the assignment were based on the same table, cursor, or TYPE statement.

The two assignments below are invalid and will fail because the record types do not match:

>     cust_sales_roundup_rec := top_customer_rec; /* Incompatible! */
>     cust_sales_rec := cust_sales_roundup_rec ; /* Incompatible! */

Even when both records in an aggregate assignment are the same type and same structure, the assignment can fail. Your assignment must, in addition, conform to these rules:

- Both cursor-based records in an aggregate assignment must be based on the same cursor.

- Both table-based records in an aggregate assignment must be based on the same table.

- Both programmer-defined records in an aggregate assignment must be based on the same TYPE...RECORD statement.

#### 9.6.1.3 Setting records to NULL

In earlier versions of Oracle (7.2 and below), the following assignmentwould cause an erroor:

>     comp_sales_rec := NULL;

NULL was treated as a scalar value, and would not be applied to each of the record's fields.

In Oracle 7.3 and above, the assignment of NULL to a record is allowed, and will set each of the fields back to the default value of NULL.

### 9.6.2 Record Initialization

When you declare a scalar variable (a variable with a scalar or noncomposite datatype), you can provide a default or initial value for that variable. In the following example, I declare the total_sales variable and initialize it to zero using both the DEFAULT syntax and the assignment operator:

>     total_sales NUMBER (15,2) := 0;

As you might expect based on the aggregate assignment discussed above, you can initialize a table or cursor record at the time of declaration only with another record of the same type and source.

If you want to initialize a record at the time of its declaration, you must use a compatible record to the right of the assignment operator (`:=`) or DEFAULT phrase. The following two examples show such initializations:

- Declare a local record with the same type and structure as the parameter and then set the default value of that local record to the incoming record:

  >     PROCEDURE compare_companies
  >        (prev_company_rec IN company%ROWTYPE)
  >     IS
  >        curr_company_rec company%ROWTYPE := prev_company_rec;
  >     BEGIN
  >        ...
  >     END;

- Create a new record type and record. Then create a second record type using the first record type as its single column. Initialize this new record with the previously-defined record:

  >     DECLARE
  >        TYPE first_rectype IS RECORD (var1 VARCHAR2(100));
  >        first_rec first_rectype;

  >        TYPE second_rectype IS RECORD
  >           (nested_rec first_rectype := first_rec);
  >     BEGIN
  >        ...
  >     END;

9.5 Assigning Values to and from Records |  | 9.7 Nested Records

Copyright (c) 2000 O'Reilly & Associates. All rights reserved.