【Oracle】PL/SQL中的引用数据类型和复合数据类型

一,引用数据类型

1,%type:单行单字段。
2,%rowtype:单行全部字段。

declare
  v_empno emp.empno%TYPE;   
  v_emp emp%ROWTYPE;
BEGIN
 
  -- %type 单行单个字段
  SELECT e.empno INTO v_empno FROM emp e WHERE e.ename = 'YOUNG';
  /*以下查询报错:ORA-01422:实际返回的行数超出请求行数
  --SELECT e.empno INTO v_empno FROM emp e WHERE e.deptno = 10 ; */ 
  dbms_output.put_line('%type:'||v_empno);
  
  -- %rowtype 单行所有字段
  SELECT e.* INTO v_emp FROM emp e WHERE e.ename = 'YOUNG';
  /*以下查询报错:ORA-01422:实际返回的行数超出请求行数
  SELECT e.empno INTO v_empno FROM emp e WHERE e.deptno = 10 ; */
  dbms_output.put_line('%rowtype:'||v_emp.empno||','||v_emp.ename
                     ||','||v_emp.deptno||','||v_emp.HIREDATE);
END;

二,复合数据类型

(一),record:单行记录,可以自定义所包含的字段;

TYPE RECORD_NAME IS RECORD(--声明记录数据类型
V1  DATA_TYPE1 [NOT NULL][:=DEFAULT_VALUE],--定义变量、变量数据类型
V2  DATA_TYPE2 [NOT NULL][:=DEFAULT_VALUE],
VN  DATA_TYPEN [NOT NULL][:=DEFAULT_VALUE]);
declare
  -- record 自定义所需的字段
  TYPE record_emp IS RECORD(
       v_empno emp.empno%TYPE,   --引用emp中empno的类型
       v_ename emp.ename%TYPE,
       v_sal emp.sal%TYPE    
  );
  v_emp_record record_emp;
BEGIN
  -- record 单行自定义的字段
  -- record select中字段顺序与record中定义的顺序一致
  SELECT e.empno,e.ename,e.sal INTO v_emp_record 
                 FROM emp e WHERE e.ename = 'YOUNG';
  dbms_output.put_line('record:'||v_emp_record.v_empno||','||v_emp_record.v_ename
                     ||','||v_emp_record.v_sal);
END;

(二),varray:数组

TYPE varray_type_name IS VARRAY(n) of <element_type>

1,一个VARRAY类型是用TYPE语句创建。必须指定最大长度n,以及元素的数据类element_type。
2,下标从 1 开始算,而不是 0。
3,使用extend申请空间,一次只申请一个空间长度。
4,可以创建一维数组,也可以创建多维数组,这取决于元素类型。

declare
  -- record 自定义所需的字段
  TYPE record_emp IS RECORD(
       v_empno emp.empno%TYPE,
       v_ename emp.ename%TYPE,
       v_sal emp.sal%TYPE    
  );
  --声明最大长度为100,元素类型为record_emp的多维数组
  TYPE emp_array IS VARRAY(100) OF record_emp;  
  -- 声明变量
  v_emp_array emp_array;  
  v_emp_record record_emp;
  
  --定义游标获取数据
  CURSOR cr_emp IS SELECT empno,ename,sal FROM emp;
  posit INT :=0;  --下标
  N_ENTRIES INT;
  ARRAY_CAPACITY INT;
BEGIN
  --构造方法,进行初始化一个空数组
  v_emp_array := emp_array(); 
  
  -- 添加元素 
  FOR e IN cr_emp LOOP
    posit :=posit+1;
    v_emp_array.extend;  --在末端添加一个空元素
    v_emp_array(posit) := e;
  END LOOP;
  
  --数组容量,元素个数
  ARRAY_CAPACITY := v_emp_array.LIMIT();
  dbms_output.put_line('数组最大容量:'||ARRAY_CAPACITY);
    
  N_ENTRIES := v_emp_array.count();
  dbms_output.put_line('数组中元素个数:'||N_ENTRIES);
  
  
  -- 遍历数组
  --first() 返回第一个元素下标,始终返回1
  --last() 返回最后一个元素下标,始终返回count()结果
  dbms_output.put_line('first()和last()遍历数组');
  FOR i IN v_emp_array.first() ..v_emp_array.last() LOOP
    dbms_output.put_line('员工号:'||v_emp_array(i).v_empno||' 员工名:'||v_emp_array(i).v_ename);
    END LOOP;
    
  -- next(x) 返回在第x个元素之后紧挨的元素下标(x+1),若x为最后一个元素,则返回null
  -- prior(x) 返回在第x个元素之前紧挨的元素下标(x-1),若x为第一个元素,则返回null
  dbms_output.put_line('next(x)遍历数组');
  posit :=  v_emp_array.first();
  WHILE posit IS NOT NULL LOOP
    dbms_output.put_line('员工号:'||v_emp_array(posit).v_empno||' 员工名:'||v_emp_array(posit).v_ename);
    posit :=v_emp_array.next(posit);
    END LOOP;
  
  dbms_output.put_line('prior(x)遍历数组');
  posit :=  v_emp_array.last();
  WHILE posit IS NOT NULL LOOP
    dbms_output.put_line('员工号:'||v_emp_array(posit).v_empno||' 员工名:'||v_emp_array(posit).v_ename);
    posit :=v_emp_array.prior(posit);
    END LOOP;
  
  -- 删除元素
  v_emp_array.trim(3);  --从末尾开始删除3个元素,不带参数则删除最后一个元素
  N_ENTRIES := v_emp_array.count();
  dbms_output.put_line('数组中元素个数:'||N_ENTRIES);
  v_emp_array.delete(); --删除所有元素
  N_ENTRIES := v_emp_array.count();
  dbms_output.put_line('数组中元素个数:'||N_ENTRIES);  
END;

(三),table:表

type table_name is table of element_type[not null]
[index by [binary_integer|pls_integer]];

index by : 创建一个主键索引,以便引用记录表变量中的特定行.
-- 下列参数下标自增(无需 显示初始化:extend)
binary_integer :  由 Oracle来 执行,不会出现溢出,但是执行速度较慢,
                  因为它是由 Oracle 模拟执行。
pls_integer    :  由硬件即直接由 CPU 来运算,因而会出现溢出,但其执行速度
                  较前者快许多,一般使用 pls_integer 就可以,除非批次处理业务量大于 21,4748,3647 ,才考虑使用 binary_integer

1,table与varray用法和功能上相似,除了对index by的使用
2,index by是可选的,但是会影响使用。

声明table时,使用index by

DECLARE
  -- record 自定义所需的字段
  TYPE record_emp IS RECORD(
       v_empno emp.empno%TYPE,
       v_ename emp.ename%TYPE,
       v_sal emp.sal%TYPE    
  );
  
  -- 声明类型为record_emp的table
  TYPE emp_array IS TABLE OF record_emp INDEX BY PLS_INTEGER;
  
  -- 声明变量
  v_emp_array emp_array;  
  v_emp_record record_emp;
  new_emp_record record_emp;
 
 --定义游标获取数据
  CURSOR cr_emp IS SELECT empno,ename,sal FROM emp WHERE deptno =20;
  posit INT :=0;

BEGIN
  -- 此时不需要构造函数 进行初始化
  -- 添加元素 
  FOR e IN cr_emp LOOP
    v_emp_array(posit) := e;
   -- dbms_output.put_line(posit||'员工号:'||v_emp_array(posit).v_empno||' 员工名:'||v_emp_array(posit).v_ename);
    posit :=posit+1;   -- 下标既可以从0开始,又可以从1开始 
    
  END LOOP;
 
  -- 新增元素时,直接插入
  SELECT '1111','new',9999 INTO new_emp_record FROM dual;
  v_emp_array(v_emp_array.last+1) := new_emp_record;
  
  -- 遍历数组
  --first() 返回第一个元素下标,始终返回1
  --last() 返回最后一个元素下标,始终返回count()结果
  dbms_output.put_line('first()和last()遍历数组');
  FOR i IN v_emp_array.first ..v_emp_array.last() LOOP
    dbms_output.put_line(i||'员工号:'||v_emp_array(i).v_empno||' 员工名:'||v_emp_array(i).v_ename);
    END LOOP;

声明table时,不使用index by

**DECLARE
  -- record 自定义所需的字段
  TYPE record_emp IS RECORD(
       v_empno emp.empno%TYPE,
       v_ename emp.ename%TYPE,
       v_sal emp.sal%TYPE    
  );
  
  -- 声明类型为record_emp的table
  TYPE emp_array IS TABLE OF record_emp ;
   -- 声明变量
  v_emp_array emp_array; 
  v_emp_record record_emp;
  new_emp_record record_emp;
 
 --定义游标获取数据
  CURSOR cr_emp IS SELECT empno,ename,sal FROM emp WHERE deptno =20;
  posit INT :=0;

BEGIN
  -- 此时需要构造函数 进行初始化
  v_emp_array := emp_array(); 
  -- 添加元素 
  FOR e IN cr_emp LOOP
    posit :=posit+1;      --下标需要从1开始
    v_emp_array.extend;  --在末端添加一个空元素
    v_emp_array(posit) := e;
  END LOOP;
 
  --新增元素是需要使用extend()在末尾增加一个空元素,再赋值
  SELECT '1111','new',9999 INTO new_emp_record FROM dual;
  v_emp_array.extend();
  v_emp_array(v_emp_array.last) := new_emp_record;
  
    -- 遍历数组
  --first() 返回第一个元素下标,始终返回1
  --last() 返回最后一个元素下标,始终返回count()结果
  dbms_output.put_line('first()和last()遍历数组');
  FOR i IN v_emp_array.first ..v_emp_array.last() LOOP
    dbms_output.put_line(i||'员工号:'||v_emp_array(i).v_empno||' 员工名:'||v_emp_array(i).v_ename);
    END LOOP;
  END;**

有无index by的区别在于
1,使用table前是否需要进行初始化,带index by不用初始化,不带则需要。
2,索引能否从0开始,带index by的既可以从0开始,又可以从1开始,不带则必须从1开始,这与varray一样。
3,新增元素时是否需要收到申请空间,带index by可以在末尾直接添加,不带则需要用extend()申请,再进行添加,这与varray一样。

参考:
https://blog.csdn.net/qq_34745941/article/details/81368648
数据来源:使用scott用户的emp表

若有错误,可以评论拍砖!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章