首批通过分布式安全可靠测评,为关键业务系统打造
关联数组
更新时间:2026-03-26 17:56:44
关联数组是一组键值对的集合。每个键都是唯一的,用于保存相应数据的元素的下标。
功能适用性
该内容仅适用于 OceanBase 数据库企业版。OceanBase 数据库社区版暂不支持。
可以使用 variable_name(index) 语法,通过其唯一索引访问集合变量的每个元素,而无需知道它们所在的数组位置,也不用遍历整个数组。
键的数据类型可以是 PLS_INTEGER 或 VARCHAR2。说明如下:
如果键的数据类型是
PLS_INTEGER,关联数组是按整数索引(Indexed by Integer)并且是密集型(指元素之间没有空隙),则从第一个元素到最后一个元素之间的每个元素都是有定义的,并且有值(值可以是NULL)。如果键的数据类型是
VARCHAR2,关联数组是按字符串索引(Indexed by String)并且是稀疏型(指元素之间可能有空隙)。说明
当遍历密集的关联数组时,不需要考虑元素之间的空隙;当遍历稀疏的关联数组时,需要留意空隙。
关联数组元素赋值
可以使用如下赋值表达式为一个关联数组元素赋值:
array_name(key) := value
如果键不在数组中,赋值语句就会向数组中添加一个键值对;否则,赋值语句就会更新该键对应的值为新的值。
特别的,关联数组可以用于临时存储数据,它们不需要像表一样占用空间或网络资源,但是因为关联数组只是为了临时存储,所以不可以进行 DML 语句操作。
如果在包里面定义关联数组变量,并在包体里赋值,则关联数组在数据库会话期间都保持可见;否则,只在所在的子程序范围内可见。
声明关联数组
要声明关联数组,需要先声明一个关联数组类型,然后声明这个类型的变量。最简单的语法格式如下:
TYPE array_type IS TABLE OF element_type INDEX BY key_type;
array_name array_type;
示例:声明关联数组
obclient> DECLARE
TYPE TYPE_SALARY IS TABLE OF NUMBER -- 关联数组的类型
INDEX BY VARCHAR2(64); -- 索引的类型是字符串
salary TYPE_SALARY; -- 关联数组变量
n VARCHAR2(64); -- 标量变量
BEGIN
-- 向关联数组中添加键值对
salary('Tom') := 2000;
salary('Mike') := 7500;
salary('Steve') := 10000;
-- 打印关联数组
n :=salary.FIRST; -- 获得关联数组的第一个元素
WHILE n IS NOT NULL
LOOP
DBMS_OUTPUT.PUT_LINE('Salary of ' || n || ' is ' || salary(n));
n := salary.Next(n); -- 获得关联数组的下一个元素
END LOOP;
END;
/
Query OK, 0 rows affected
Salary of Mike is 7500
Salary of Steve is 10000
Salary of Tom is 2000
填充关联数组
填充一个密集型关联数组最有效的方式是使用 SELECT [FETCH] BULK COLLECT INTO 子句。
说明
如果一个密集型关联数组要填充大量的内容,而使用 SELECT 语句返回的结果集会超出内存大小,则可以通过使用游标和 FETCH 语句并结合 BULK COLLECT INTO 和 LIMIT 子句,以代替 SELECT 语句。
填充一个稀疏型关联数组时不能使用 SELECT 语句,可以在 FOR LOOP 循环语句里使用赋值语句。
下面示例是使用 SELECT 语句填充按整型索引的关联数组,然后使用 FOR LOOP 语句填充一个按字符串索引的稀疏型关联数组。
示例:填充关联数组
obclient> CREATE TABLE emp(
emp_id NUMBER NOT NULL);
Query OK, 0 rows affected
obclient>INSERT INTO emp VALUES(101),(102),(103),(103),(102);
Query OK, 5 rows affected
Records: 5 Duplicates: 0 Warnings: 0
obclient>DECLARE
TYPE num_table IS TABLE OF emp.emp_id%TYPE
INDEX BY BINARY_INTEGER; -- 定义关联数组的索引类型是整型
num_list NUM_TABLE; -- 定义关联数组的变量
BEGIN
SELECT emp_id
BULK COLLECT INTO num_list from emp;
DBMS_OUTPUT.PUT_LINE('Bulk Collected:');
FOR i IN num_list.FIRST..num_list.LAST LOOP
IF i <= 3 THEN
DBMS_OUTPUT.PUT_LINE('Number ['||num_list(i)||']');
END IF;
END LOOP;
END;
/
Query OK, 0 rows affected
Bulk Collected:
Number [101]
Number [102]
Number [103]
遍历密集型关联数组
密集型关联数组(按整型索引)的元素之间没有空隙,每个位于第一个和最后一个元素之间的元素都有定义和值(这个值可以是 NULL),可以使用 FOR LOOP 语句遍历一个密集型关联数组。
下面示例使用 FOR LOOP 语句去打印关联数组的每个元素值。其中,FOR LOOP 语句的上限 tab _wares.COUNT 调用了集合的方法 COUNT 返回数组中元素数目。
示例:遍历密集型关联数组
obclient> CREATE TABLE ware (
w_id INT NOT NULL,
w_name VARCHAR(10),
w_city VARCHAR(20),
w_state VARCHAR(20),
PRIMARY KEY(w_id)
);
Query OK, 0 rows affected
obclient>INSERT INTO ware VALUES(1,'KING','BeiJing','China');
Query OK, 1 row affected
obclient>INSERT INTO ware VALUES(2,'ALLEN','ShangHai','China');
Query OK, 1 row affected
obclient>INSERT INTO ware VALUES(3,'CLARK','ShangHai','China');
Query OK, 1 row affected
obclient>SET SERVEROUTPUT ON;
Query OK, 0 rows affected
obclient>DECLARE
-- 声明关联数组,不带游标
TYPE type_ware IS TABLE OF ware%ROWTYPE INDEX BY PLS_INTEGER ;
tab_wares TYPE_WARE;
TYPE type_ware_city IS TABLE OF ware.w_city%TYPE INDEX BY VARCHAR(20);
tab_ware_cities TYPE_WARE_CITY;
TYPE type_ware_name IS TABLE OF ware.w_name%TYPE INDEX BY VARCHAR(20);
ware_names TYPE_WARE_NAME;
BEGIN
SELECT w_id,w_name,w_city,w_state BULK COLLECT INTO tab_wares FROM ware;
FOR i IN 1..tab_wares.COUNT LOOP
dbms_output.put_line(
rpad( tab_wares(i).w_id, 23)
|| rpad( tab_wares(i).w_name, 23)
|| rpad(tab_wares(i).w_city, 23 )
);
END LOOP;
END;
/
Query OK, 0 rows affected
1 KING BeiJing
2 ALLEN ShangHai
3 CLARK ShangHai
遍历稀疏型关联数组
稀疏型关联矩阵(按字符串索引)在元素之间可能存在空隙,需要使用 WHILE LOOP 语句结合集合的方法 FIRST 和 NEXT 来遍历稀疏型关联数组。示例如下:
DECLARE
-- 声明关联数组,不带游标
TYPE type_ware IS TABLE OF ware%ROWTYPE INDEX BY PLS_INTEGER ;
tab_wares TYPE_WARE;
TYPE type_ware_city IS TABLE OF ware.w_city%TYPE INDEX BY VARCHAR(20);
tab_ware_cities TYPE_WARE_CITY;
TYPE type_ware_name IS TABLE OF ware.w_name%TYPE INDEX BY VARCHAR(20);
-- 在声明部分增加:
i_name ware.w_name%TYPE;
BEGIN
SELECT w_id,w_name,w_city,w_state
BULK COLLECT INTO tab_wares FROM ware;
FOR i IN 1..tab_wares.COUNT LOOP
dbms_output.put_line(
rpad( tab_wares(i).w_id, 23)
|| rpad( tab_wares(i).w_name, 23)
|| rpad(tab_wares(i).w_city, 23 )
);
END LOOP;
-- 在执行部分增加:
i_name := tab_ware_cities.FIRST ;
WHILE i_name IS NOT NULL LOOP
dbms_output.put_line(rpad(i_name,12) || tab_ware_cities(i_name) );
i_name := tab_ware_cities.NEXT(i_name);
END LOOP;
END;
/
Query OK, 0 rows affected
1 KING BeiJing
2 ALLEN ShangHai
3 CLARK ShangHai