PL/SQL 联合数组与嵌套表

简介:       通常情况下,在PL/SQL中,处理单行单列的数据可以使用标量变量,而处理单行多列的数据则使用PL/SQL记录是不错的选择。单列多行数据则由联合数组或嵌套表来完成,其特点是类似于单列数据库表。

      通常情况下,在PL/SQL中,处理单行单列的数据可以使用标量变量,而处理单行多列的数据则使用PL/SQL记录是不错的选择。单列多行数据
则由联合数组或嵌套表来完成,其特点是类似于单列数据库表。在Oracle 9i 之前称为PL/SQL索引表,9i 之后称之为联合数组。嵌套表也是集合
类型中的一种,下面分别介绍这两种集合数据类型的使用方法。

 

一、联合数组

1、联合数组的特性
	类似于一张简单的SQL表,按照主键进行检索数据
	其数据行并不是按照预定义的顺序存储。当使用变量来检索其数据时,每行数据会分配一个连续的下标且从1开始。
	下标可以为负值,且下标的数据类型支持binary_integer,pls_integer,varchar2
	其数据元素个数无限制
	不能作为表列的数据类型使用,即只能作为PL/SQL复合数据类型使用
	存放的数据类型是临时数据,故不支持insert,select into 等SQL语句,等同于SQL server中的表变量
		
2、语法		
	TYPE type_name IS TABLE OF element_type [NOT NULL]  -->element_type为联合数组元数据指定数据类型(先使用TYPE声明表结构)
	INDEX BY key_type;                                  -->元素下标的数据类型
	table_name TYPE_NAME;                               -->再使用声明的TYPE类型声明实际数组名
		
3、示例
--使用PLS_INTEGE类型联合数组
scott@CNMMBO> DECLARE                                   -->定义游标       
  2     CURSOR name_cur IS
  3        SELECT dname
  4        FROM   dept
  5        WHERE  deptno < 40;
  6  
  7     TYPE name_type IS TABLE OF dept.dname%TYPE      -->定义一个联合数组类型,且其下标的数据类型为PLS_INTEGER
  8                          INDEX BY PLS_INTEGER;
  9  
 10     dname_tab   name_type;                          -->声明类型为name_type的联合数组dname_tab
 11     v_counter   INTEGER := 0;
 12  BEGIN
 13     FOR name_rec IN name_cur
 14     LOOP
 15        v_counter   :=
 16           v_counter
 17           + 1;
 18        dname_tab( v_counter ) := name_rec.dname;      -->对联合数据进行循环赋值
 19        DBMS_OUTPUT.put_line(   'Dname is('
 20                             || v_counter
 21                             || '):'
 22                             || dname_tab( v_counter ) );   -->输出联合数组中的所有元素
 23     END LOOP;
 24  END;
 25  /
Dname is(1):ACCOUNTING
Dname is(2):RESEARCH
Dname is(3):SALES

PL/SQL procedure successfully completed.

--使用VARCHAR2类型联合数组
scott@CNMMBO> DECLARE
  2     TYPE score_type IS TABLE OF NUMBER
  3                           INDEX BY VARCHAR2( 10 );    -->注意此处声明的联合数组的下标数据类型为varchar2
  4  
  5     score_tab   score_type;
  6  BEGIN
  7     score_tab( 'SCOTT' ) := 95;                       -->对不同下标分别进行赋值
  8     score_tab( 'JOHN' ) := 98;
  9     score_tab( 'ROBINSON' ) := 96;
 10     DBMS_OUTPUT.put_line( 'First element is '
 11                          || score_tab.FIRST );        -->输出联合数组score_tab中的第一个元素的下标
 12     DBMS_OUTPUT.put_line( 'last element is '
 13                          || score_tab.LAST );         -->输出联合数组score_tab中的最后一个元素的下标
 14     DBMS_OUTPUT.put_line( 'The score of Scott is '
 15                          || score_tab( 'SCOTT' ) );   -->输出下标为SCOTT的元素的值
 16  END;
 17  /
First element is JOHN                                     -->注意此处输出的是JOHN(第一个和最后一个是按字母排序得到的)
last element is SCOTT
The score of Scott is 95

PL/SQL procedure successfully completed.

--下标超范围的情况
scott@CNMMBO> DECLARE
  2     TYPE score_type IS TABLE OF NUMBER
  3                           INDEX BY VARCHAR2( 10 );
  4  
  5     score_tab   score_type;
  6  BEGIN
  7     score_tab( 'SCOTT' ) := 95;
  8     score_tab( 'JOHN' ) := 98;
  9     score_tab( 'ROBINSON' ) := 96;
 10     DBMS_OUTPUT.put_line( 'The score of Jason is  '
 11                          || score_tab( 'JASON' ) );
 12  END;
 13  /
DECLARE
*
ERROR at line 1:
ORA-01403: no data found                              -->当下标超范围时,将收到ORA-01403错误
ORA-06512: at line 10

二、嵌套表

1、嵌套表的特点:
	元素下表从1开始,个数没有限制.即元素个数可以动态增长
	嵌套表的数组元素值可以是稀疏的,即可以使得中间的某个元素没有赋值
	嵌套表的语法与联合数组类似,不同的是仅仅是少了index by子句   
	嵌套表必需先初始化,然后才能引用其中的元素。如果初始化为空值,则后续需要使用extend来扩展其大小  
	嵌套表初始化时为密集的,但允许有间隙,即允许使用内置过程delete从嵌套表中删除元素
	嵌套表类型可以作为表列的数据类型来使用

2、语法
		TYPE type_name IS TABLE OF element_type [NOT NULL];   -->element_type为索引表元数据指定数据类型(先使用TYPE声明表结构) 
		table_name TYPE_NAME;                                 -->再使用声明的TYPE类型声明实际嵌套表       

3、示例
--声明嵌套表并输出嵌套表的实际内容   		
scott@CNMMBO> DECLARE
  2     CURSOR name_cur IS
  3        SELECT dname
  4        FROM   dept
  5        WHERE  deptno < 40;
  6  
  7     TYPE name_type IS TABLE OF dept.dname%TYPE;
  8  
  9     dname_tab   name_type := name_type( );   -->需要初始化,否则将收到 ORA-06531:Reference to uninitialized collection.
 10     v_counter   INTEGER := 0;
 11  BEGIN
 12     FOR name_rec IN name_cur
 13     LOOP
 14        v_counter   :=
 15           v_counter
 16           + 1;
 17        dname_tab.EXTEND;         -->需要扩展,否则将收到 ORA-06533: Subscript beyond count
 18        dname_tab( v_counter ) := name_rec.dname;
 19        DBMS_OUTPUT.put_line(   'Dname ('
 20                             || v_counter
 21                             || ') is :'
 22                             || dname_tab( v_counter ) );
 23     END LOOP;
 24  END;
 25  /
Dname (1) is :ACCOUNTING
Dname (2) is :RESEARCH
Dname (3) is :SALES

PL/SQL procedure successfully completed.

--将嵌套表作为表列的数据类型来使用
scott@CNMMBO> CREATE OR REPLACE TYPE mail_type IS TABLE OF VARCHAR2( 100 );
  2  /

Type created.

scott@CNMMBO> CREATE TABLE tb_tmp       -->创建表tb_tmp
  2  (
  3     empno   NUMBER( 4 )
  4   , ename   VARCHAR2( 10 )
  5   , mail    mail_type               -->列mail的类型为mail_type
  6  )
  7  NESTED TABLE mail                 -->注意此处需要指定嵌套表的存储方式
  8     STORE AS mail_tab;

Table created.

--为嵌套表插入数据
scott@CNMMBO> insert into tb_tmp select 8888,'Jack','Jack@yahoo.com,Jack@163.com' from dual;  -->传统方式插入失败
insert into tb_tmp select 8888,'Jack','Jack@yahoo.com,Jack@163.com' from dual
                                      *
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected - got CHAR

scott@CNMMBO> insert into tb_tmp select 8888,'Jack',q'['Jack@yahoo.com','Jack@163.com']' from dual;  -->分割字符串方式插入失败
insert into tb_tmp select 8888,'Jack',q'['Jack@yahoo.com','Jack@163.com']' from dual
                                      *
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected - got CHAR

scott@CNMMBO> insert into tb_tmp select 8888,'Jack',mail_type('Jack@yahoo.com','Jack@163.com') from dual; -->插入时指定嵌套表类型 

1 row created.

scott@CNMMBO> commit;

Commit complete.

--查看存在嵌套表数据类型的表中的记录
scott@CNMMBO> col mail format a30
scott@CNMMBO> select * from tb_tmp;                    -->查询数据时带有嵌套表的类型

     EMPNO ENAME      MAIL
---------- ---------- ------------------------------
      8888 Jack       MAIL_TYPE('Jack@yahoo.com', 'J
                      ack@163.com')

scott@CNMMBO> DECLARE
  2     mail_tab   mail_type;    -->声明一个mail_type数据类型
  3  BEGIN
  4     SELECT mail
  5     INTO   mail_tab          -->将数据保存到 mail_tab 变量中
  6     FROM   tb_tmp
  7     WHERE  empno = 8888;
  8  
  9     FOR i IN 1 .. mail_tab.COUNT   -->轮循输出嵌套表类型中的值
 10     LOOP
 11        DBMS_OUTPUT.put_line( 'Jack mail address is '
 12                             || mail_tab( i ) );
 13     END LOOP;
 14  END;
 15  /
Jack mail address is Jack@yahoo.com
Jack mail address is Jack@163.com

PL/SQL procedure successfully completed.

--更新表中含有嵌套表类型中的值
scott@CNMMBO> DECLARE
  2     mail_tab   mail_type := mail_type( 'Jackson@yahoo.com', 'Jackson@163.com' );
  3  BEGIN
  4     UPDATE tb_tmp
  5     SET    mail         = mail_tab;
  6  
  7     COMMIT;
  8     DBMS_OUTPUT.put_line( 'Jack mail address was updated' );
  9  END;
 10  /
Jack mail address was updated

PL/SQL procedure successfully completed.

scott@CNMMBO> select * from tb_tmp;

     EMPNO ENAME      MAIL
---------- ---------- ------------------------------
      8888 Jack       MAIL_TYPE('Jackson@yahoo.com',
                       'Jackson@163.com')

--删除表中存在嵌套表类型的记录
scott@CNMMBO> delete from tb_tmp where empno=8888;

1 row deleted.

scott@CNMMBO> commit;

Commit complete.

scott@CNMMBO> select * from tb_tmp;

no rows selected                       
--> Author: Robinson Cheng
--> Blog: http://blog.csdn.net/robinson_0612

三、总结
1、不论是联合数组还是嵌套表,应当以集合的方式来看待与处理
2、联合数组在声明其类型时需要指定index by子句,而嵌套表则不需要
3、联合数组和嵌套表两者元素个数无限制   
4、联合数组不需要初始化,而嵌套表则需要对其进行初始化。其次是嵌套表初始化赋空值的情形则后续需要使用extend方式来扩展集合尺寸的大小
5、联合数组不能作为表上列的数据类型,而嵌套表无此限制

 

四、更多参考

启用用户进程跟踪

父游标、子游标及共享游标

绑定变量及其优缺点

dbms_xplan之display_cursor函数的使用

dbms_xplan之display函数的使用

执行计划中各字段各模块描述

使用 EXPLAIN PLAN 获取SQL语句执行计划

启用 AUTOTRACE 功能

函数使得索引列失效

Oracle 绑定变量窥探


 

                 

 

目录
相关文章
|
2月前
|
SQL 数据采集 监控
局域网监控电脑屏幕软件:PL/SQL 实现的数据库关联监控
在当今网络环境中,基于PL/SQL的局域网监控系统对于企业和机构的信息安全至关重要。该系统包括屏幕数据采集、数据处理与分析、数据库关联与存储三个核心模块,能够提供全面而准确的监控信息,帮助管理者有效监督局域网内的电脑使用情况。
40 2
|
3月前
|
SQL
使用SQL进行内外连接和嵌套查询
使用SQL进行内外连接和嵌套查询
54 0
|
3月前
|
SQL 数据库
SQl查询之单表查询,连接与嵌套查询
SQl查询之单表查询,连接与嵌套查询
46 0
|
5月前
|
SQL Oracle 关系型数据库
SQL与PL/SQL:数据库编程语言的比较
【8月更文挑战第31天】
104 0
|
5月前
|
SQL 数据库 开发者
SQL中的子查询:嵌套查询的深度解析
【8月更文挑战第31天】
650 0
|
5月前
|
SQL 数据挖掘 数据库
SQL 子查询深度剖析来袭!嵌套查询竟有如此无限可能,带你轻松玩转复杂数据检索与操作!
【8月更文挑战第31天】在 SQL 中,子查询是一种强大的工具,允许在一个查询内嵌套另一个查询,从而实现复杂的数据检索和操作。子查询分为标量子查询、列子查询和行子查询,可用于 SELECT、FROM、WHERE 和 HAVING 子句中。例如,查找年龄大于平均年龄的学生或每个课程中成绩最高的学生。子查询具有灵活性、可重用性和潜在的性能优化优势,但需注意性能问题、可读性和数据库支持。合理使用子查询能够显著提升查询效率和代码维护性。
139 0
|
6月前
|
SQL 监控 关系型数据库
PolarDB产品使用问题之SQL防火墙怎么拦截没有指定WHERE条件的特定表的SQL语
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
5月前
|
SQL JSON 关系型数据库
"SQL老司机大揭秘:如何在数据库中玩转数组、映射与JSON,解锁数据处理的无限可能,一场数据与技术的激情碰撞!"
【8月更文挑战第21天】SQL作为数据库语言,其能力不断进化,尤其是在处理复杂数据类型如数组、映射及JSON方面。例如,PostgreSQL自8.2版起支持数组类型,并提供`unnest()`和`array_agg()`等函数用于数组的操作。对于映射类型,虽然SQL标准未直接支持,但通过JSON数据类型间接实现了键值对的存储与查询。如在PostgreSQL中创建含JSONB类型的表,并使用`-&gt;&gt;`提取特定字段或`@&gt;`进行复杂条件筛选。掌握这些技巧对于高效管理现代数据至关重要,并预示着SQL在未来数据处理领域将持续扮演核心角色。
71 0
|
6月前
|
SQL 分布式计算 DataWorks
MaxCompute操作报错合集之使用sql查询一个表的分区数据时遇到报错,该如何解决
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
7月前
|
SQL 存储 测试技术