前言
记录是一个复合的数据结构,能够把各种相关的数据合并为一个逻辑单元。
PL/SQL支持三种记录类型:
- 基于表的记录
- 基于游标的记录
- 用户定义的记录
一、记录类型
记录结构有点类似于数据库表的一行数据。每个数据项都存储在具有自己的名称和数据类型的字段中。
1.1 基于表和基于游标的记录
使用%ROWTYPE属性,可以创建基于表和基于游标的记录。这个属性类似于用定义标量变量的%TYPE属性。
下例基于表的记录
DECLARE
-- ooag_rec记录与ooag_t表中数据行相同的结构。
ooag_rec ooag_t%ROWTYPE;
BEGIN
SELECT *
INTO ooag_rec
FROM ooag_t
WHERE ooagent = 70
AND rownum = 1;
-- 如何使用记录中的数据
DBMS_OUTPUT.PUT_LINE(ooag_rec.ooag011);
END;
下例基于游标的记录
DECLARE
CURSOR ooag_cur IS
SELECT ooag001,ooag011
FROM ooag_t
WHERE ooagent = 70;
-- 这个记录的结构和游标返回的数据行具有相同的结构
ooag_rc ooag_cur%ROWTYPE;
BEGIN
FOR ooag_rc IN ooag_cur LOOP
DBMS_OUTPUT.PUT_LINE(ooag_rc.ooag001||','||ooag_rc.ooag011);
END LOOP;
END;
1.2 用户自定义的记录
语法:
TYPE type_name IS RECORD
(field_name1 datatype1 [NOT NULL] [ := DEFAULT EXPRESSION],
field_name2 datatype2 [NOT NULL] [ := DEFAULT EXPRESSION],
…
field_name3 datatype3 [NOT NULL] [ := DEFAULT EXPRESSION]);
NOT NULL表示NOT NULL约束。
DECLARE
TYPE time_rec_type IS RECORD
(cur_date DATE,
cur_day VARCHAR2(12),
cur_time VARCHAR2(8) := '00:00:00');
time_rec time_rec_type;
BEGIN
SELECT sysdate
INTO time_rec.cur_date
FROM dual;
time_rec.cur_day := TO_CHAR(time_rec.cur_date, 'DAY');
time_rec.cur_time := TO_CHAR(time_rec.cur_date, 'HH24:MI:SS');
DBMS_OUTPUT.PUT_LINE('Date: '||TO_CHAR(time_rec.cur_date,'yyyy/mm/dd'));
DBMS_OUTPUT.PUT_LINE('Day: '||time_rec.cur_day);
DBMS_OUTPUT.PUT_LINE('Time: '||time_rec.cur_time);
END;
上例执行结果如下:
Date: 2022/09/29
Day: 星期四
Time: 09:24:21
当声明记录类型时,如果为单个字段指定NOT NULL约束,必须初始化这种字段。
DECLARE
TYPE rec_type IS RECORD
(field1 VARCHAR2(255),
field2 VARCHAR2(100) NOT NULL = 'hello,world!');
rec_var rec_type;
BEGIN
......
END;
1.3 记录的兼容性
类型不同的记录不能直接赋值。
DECLARE
TYPE name_type1 IS RECORD
(name varchar2(100));
TYPE name_type2 IS RECORD
(name varchar2(100));
name_rec1 name_type1;
name_rec2 name_type2;
BEGIN
name_rec1.name = '张三';
name_rec2.name = '王五';
-- 这样直接给记录赋值就报错
name_rec1 = name_rec2;
-- 需要这样做
name_rec1.name = name_rec2.name;
END;
1.4 嵌套记录
DECLARE
TYPE name_type IS RECORD
(first_name varchar2(50),
last_name varchar2(50));
TYPE person_type IS RECORD
-- 记录中又有一个记录类型name_type
(name name_type,
street varchar2(50),
city varchar2(25));
person_rec person_type;
............
-- 使用 person_rc.name.first_name
1.5 记录的集合
1.5.1 使用索引表
DECLARE
CURSOR ooag_cur IS
SELECT ooag001,ooag011
FROM ooag_t
WHERE ooagent = 70;
-- 这个索引表就相当于记录的集合
TYPE ooag_type IS TABLE OF ooag_cur%ROWTYPE
INDEX BY BINARY_INTEGER;
ooag_tab ooag_type;
v_cnt INTEGER := 0;
BEGIN
FOR ooag_rec IN ooag_cur LOOP
v_cnt := v_cnt + 1;
-- 将ooag_tab这个索引表填上数据
ooag_tab(v_cnt).ooag001 := ooag_rec.ooag001;
ooag_tab(v_cnt).ooag011 := ooag_rec.ooag011;
END LOOP;
FOR i in 1..ooag_tab.count() LOOP
DBMS_OUTPUT.PUT_LINE(ooag_tab(i).ooag001||':'||ooag_tab(i).ooag011);
END LOOP;
END;
1.5.2 使用嵌套表
DECLARE
CURSOR ooag_cur IS
SELECT ooag001,ooag011
FROM ooag_t
WHERE ooagent = 70;
-- 这个嵌套表就相当于记录的集合
TYPE ooag_type IS TABLE OF ooag_cur%ROWTYPE;
-- 嵌套表不索引关键字,必须初始化
ooag_tab ooag_type := ooag_type();
v_cnt INTEGER := 0;
BEGIN
FOR ooag_rec IN ooag_cur LOOP
v_cnt := v_cnt + 1;
-- 用一个扩展一个
ooag_tab.EXTEND;
-- 将ooag_tab这个索引表填上数据
ooag_tab(v_cnt).ooag001 := ooag_rec.ooag001;
ooag_tab(v_cnt).ooag011 := ooag_rec.ooag011;
END LOOP;
FOR i in 1..ooag_tab.count() LOOP
DBMS_OUTPUT.PUT_LINE(ooag_tab(i).ooag001||':'||ooag_tab(i).ooag011);
END LOOP;
END;