关联数组构造器

PL/SQL中初始化关联数组时,传统的做法是逐个为键(Key)赋值,当数组元素较多时,这种方式代码冗长且可读性差。为了解决这一问题,PolarDB PostgreSQL版(兼容Oracle)提供了关联数组构造器。它是一种简洁的语法糖,允许您在声明或赋值时,通过单行代码就能完成关联数组的创建和批量初始化,从而显著提高代码的可读性和开发效率。

功能简介

关联数组构造器本质上是一个与关联数组类型同名的函数,它允许以key => value的形式传递一组或多组键值对来初始化数组。该构造器同样可在PL/SQL块的声明部分(DECLARE)或执行部分(BEGIN...END)中使用,也可作为函数的返回值。

前提条件

您的PolarDB PostgreSQL版(兼容Oracle)集群的修订版本需为2.0.14.17.36.0及以上

说明

您可在控制台查看内核小版本号,也可以通过SHOW polardb_version;语句查看。如未满足内核小版本要求,请升级内核小版本

语法说明

array_variable := array_type(key1 => value1, key2 => value2, ...);

参数说明

  • array_variable:已声明的关联数组变量。

  • array_type:关联数组的类型名称。

  • key:需与关联数组声明时的索引类型(INDEX BY子句中的类型)匹配。

  • value:需与关联数组声明时的值类型(TABLE OF子句中的类型)匹配。

使用示例

以下示例展示了关联数组构造器在不同场景下的应用。

示例1:在PL/SQL块中初始化关联数组

本示例演示了在DECLARE块中定义一个局部关联数组类型,并在执行块中使用构造器为其赋予初始值。

DECLARE
    -- 声明一个key为VARCHAR,value为INT的局部关联数组类型
    TYPE aarray_type IS TABLE OF INT INDEX BY VARCHAR(10);
    
    -- 声明一个该类型的变量
    aarray aarray_type;
BEGIN
    -- 使用构造器进行初始化
    aarray := aarray_type('first' => 10, 'second' => 20, 'third' => 30);
    
    -- 打印数组内容和元素数量
    RAISE NOTICE '数组内容: %', aarray;
    RAISE NOTICE '元素数量: %', aarray.COUNT;
END;
/

预期输出:

NOTICE: 数组内容: (first=>10,second=>20,third=>30)
NOTICE: 元素数量: 3

示例2:在包(Package)中使用构造器

本示例演示了如何在包中定义全局关联数组类型,并使用构造器初始化一个作为OUT参数的数组。

-- 1. 创建包定义
CREATE OR REPLACE PACKAGE test_package AS
    -- 声明一个全局关联数组类型
    TYPE aarray_type IS TABLE OF INT INDEX BY VARCHAR(10);
    
    -- 声明一个使用构造器初始化数组的过程
    PROCEDURE init_array(aarray OUT aarray_type);
END;
/

-- 2. 创建包体
CREATE OR REPLACE PACKAGE BODY test_package AS
    PROCEDURE init_array(aarray OUT aarray_type) IS
    BEGIN
        aarray := aarray_type('one' => 1, 'two' => 2, 'three' => 3);
    END;
END;
/

-- 3. 调用包中的过程
DECLARE
    my_array test_package.aarray_type;
BEGIN
    test_package.init_array(my_array);
    RAISE NOTICE '数组内容: %', my_array;
    RAISE NOTICE 'key "two" 的值: %', my_array('two');
END;
/

预期输出:

NOTICE: 数组内容: (one=>1,three=>3,two=>2)
NOTICE: key "two" 的值: 2

示例3:使用构造器作为函数返回值

本示例展示了如何让一个函数直接返回一个由构造器创建的关联数组。

DECLARE
    -- 声明关联数组类型
    TYPE aarray_type IS TABLE OF INT INDEX BY VARCHAR(10);
    
    -- 声明一个返回关联数组的函数
    FUNCTION create_array RETURN aarray_type IS
    BEGIN
        -- 直接使用构造器作为返回值
        RETURN aarray_type('alpha' => 100, 'beta' => 200, 'gamma' => 300);
    END;
    
    result_array aarray_type;
BEGIN
    result_array := create_array();
    RAISE NOTICE '返回的数组: %', result_array;
    RAISE NOTICE 'key "gamma" 的值: %', result_array('gamma');
END;
/

预期输出:

NOTICE: 返回的数组: (alpha=>100,beta=>200,gamma=>300)
NOTICE: key "gamma" 的值: 300

示例4:处理特殊情况

关联数组构造器对一些特殊情况有明确的处理规则。

空构造器

您可以创建一个不含任何键值对的空关联数组。

DECLARE
    TYPE aarray_type IS TABLE OF INT INDEX BY VARCHAR(10);
    aarray aarray_type;
BEGIN
    aarray := aarray_type(); -- 使用空构造器
    RAISE NOTICE '空数组的元素数量: %', aarray.COUNT;

    -- 后续可以正常添加元素
    aarray('new_key') := 42;
    RAISE NOTICE '添加元素后: %', aarray;
END;
/

预期输出:

NOTICE: 空数组的元素数量: 0
NOTICE: 添加元素后: (new_key=>42)

重复的键

如果构造器中包含重复的键,后面的值会覆盖前面的值。

DECLARE
    TYPE aarray_type IS TABLE OF INT INDEX BY VARCHAR(10);
    aarray aarray_type;
BEGIN
    aarray := aarray_type('key1' => 10, 'key2' => 20, 'key1' => 30);
    RAISE NOTICE '数组内容: %', aarray;
    RAISE NOTICE 'key1 的最终值: %', aarray('key1');
END;
/

预期输出:

NOTICE: 数组内容: (key1=>30,key2=>20)
NOTICE: key1 的最终值: 30

键的顺序

构造器中键值对的顺序不影响最终存储时键的排序。关联数组会根据其键的数据类型(字符串或数字)进行内部排序。

DECLARE
    TYPE aarray_type IS TABLE OF INT INDEX BY VARCHAR(10);
    aarray aarray_type;
BEGIN
    aarray := aarray_type('zebra' => 1, 'apple' => 2, 'banana' => 3);
    -- 尽管'zebra'在最前面,但存储时会按字母顺序排序
    RAISE NOTICE '数组内容: %', aarray;
    RAISE NOTICE '第一个键: %', aarray.FIRST;
    RAISE NOTICE '最后一个键: %', aarray.LAST;
END;
/

预期输出:

NOTICE: 数组内容: (apple=>2,banana=>3,zebra=>1)
NOTICE: 第一个键: apple
NOTICE: 最后一个键: zebra

示例5:初始化多维关联数组

构造器同样支持嵌套使用,以初始化多维关联数组。

DECLARE
    -- 定义内层和外层关联数组类型
    TYPE aarray_type1 IS TABLE OF INT INDEX BY VARCHAR(10);
    TYPE aarray_type2 IS TABLE OF aarray_type1 INDEX BY VARCHAR(10);
    
    aarray aarray_type2;
BEGIN
    -- 使用嵌套构造器初始化二维数组
    aarray := aarray_type2(
        'row1' => aarray_type1('col1' => 1, 'col2' => 2),
        'row2' => aarray_type1('col1' => 3, 'col2' => 4)
    );
    
    RAISE NOTICE '完整数组: %', aarray;
    RAISE NOTICE '元素 [row2][col1] 的值: %', aarray('row2')('col1');
END;
/

预期输出:

NOTICE: 完整数组: (row1=>"(col1=>1,col2=>2)",row2=>"(col1=>3,col2=>4)")
NOTICE: 元素 [row2][col1] 的值: 3