数组
MAXIR 支持将表中的列定义为可变长度多维数组。数组内的元素可以是任何内置的或用户自定义的基本类型、枚举类型、复合类型、范围类型等。
一维数组
为了更好的理解数组,我们先从一维数组开始。
如下 SQL 创建一个名为 array_test 的表,表中数据类型为一维数组:
CREATE TABLE array_test (
f1 integer[],
f2 integer ARRAY,
f3 integer ARRAY[1],
f4 double precision[],
f5 double precision ARRAY,
f6 double precision ARRAY[1],
f7 decimal(10, 5)[],
f8 decimal(10, 5) ARRAY,
f9 decimal(10, 5) ARRAY[1],
f10 timestamptz[],
f11 timestamptz ARRAY,
f12 timestamptz ARRAY[1],
f13 text[],
f14 text ARRAY,
f15 text ARRAY[1]
);数组声明方式
如上述示例所示,MAXIR 支持两种数组声明方式:
-
在数组元素的数据类型名称后面加上方括号(
[]),例如示例中的integer[]、double precision[]。 -
也可以通过数据类型名后跟
ARRAY关键字来命名,例如示例中的integer ARRAY、decimal(10,5) ARRAY。
!>在声明数组时,需要注意:
使用 ARRAY 关键字时,如果关键字后跟 [],则 [] 中必须有具体数字。例如,MAXIR 支持 integer ARRAY[1],但是不支持 integer ARRAY[1]。
使用 ARRAY 关键字声明数组类型时,只支持一维数组。
方括号([])中的数字表示当前维度中数组的长度,不过数组长度只做展示用,实际写入长度不受该数字影响。
表格创建好之后,即可插入数据。例如:
INSERT INTO array_test VALUES (
'{1, 2, 3}',
'{1, 2, 3}',
'{1, 2, 3}',
'{1.1, 2.2, 3.3}',
'{1.1, 2.2, 3.3}',
'{1.1, 2.2, 3.3}',
'{4.4, 5.5, 6.6}',
'{4.4, 5.5, 6.6}',
'{4.4, 5.5, 6.6}',
'{"2020-02-02 13:45:56", "2020-03-03 14:15:16"}',
'{"2020-02-02 13:45:56", "2020-03-03 14:15:16"}',
'{"2020-02-02 13:45:56", "2020-03-03 14:15:16"}',
'{"Java", "Rust"}',
'{"Java", "Rust"}',
'{"Java", "Rust"}'
);完成数据插入后,即可对表中数据进行查询。如需对数组中的单个元素进行访问时,通过指定数组下标数字来完成。MAXIR 数组中的元素下标从 1 开始,即 array[1]。
例如,执行 SELECT 语句查询表中 f1 列中的第 1 个和第 3 个元素:
SELECT f1[1], f1[3] FROM array_test;
f1 | f1
----+----
1 | 3
(1 row)如需查询数组中的任意切片,需要选择 Hybrid DPS 集群运行查询。例如:
SELECT f4[2:3] FROM array_test;
f4
-----------
{2.2,3.3}
(1 row)!>注意
当前,Hybrid DPS 暂不支持数据切片访问。
关于数组切片访问的详细说明,请参考 使用 Hybrid DPS 进行切片访问。
多维数组
多维数组的使用方式和一维数组类似。
如下 SQL 示例创建一个名为 array3d_test 表,表中数据类型为 3 维数组:
CREATE TABLE array3d_test (
f1 integer[][][],
f2 double precision[][][],
f3 decimal(10, 5)[][][],
f4 timestamptz[][][],
f5 text[][][]
);创建完成后,即可往表中插入数据,例如:
INSERT INTO array3d_test VALUES (
'{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}',
'{{{1.1, 2.2, 3.3}}, {{4.4, 5.5, 6.6}}}',
'{{{1.1, 2.2, 3.3}}, {{4.4, 5.5, 6.6}}}',
'{{{"2020-02-02 13:45:56"}, {"2020-03-03 14:15:16"}}, {{"2020-10-10 21:45:56"}, {"2020-11-11 22:45:56"}}}',
'{{{"Java"}}, {{"Rust"}}}'
);该 SQL 等价于:
INSERT INTO array3d_test VALUES (
ARRAY[ARRAY[ARRAY[1, 2], ARRAY[3, 4]], ARRAY[ARRAY[4, 5], ARRAY[7, 8]]],
ARRAY[ARRAY[ARRAY[1.1, 2.2, 3.3]], ARRAY[ARRAY[4.4, 5.5, 6.6]]],
ARRAY[ARRAY[ARRAY[1.1, 2.2, 3.3]], ARRAY[ARRAY[4.4, 5.5, 6.6]]],
ARRAY[ARRAY[ARRAY['2020-02-02 13:45:56'::timestamptz], ARRAY['2020-03-03 14:15:16'::timestamptz]], ARRAY[ARRAY['2020-10-10 21:45:56'::timestamptz], ARRAY['2020-11-11 22:45:56'::timestamptz]]],
ARRAY[ARRAY[ARRAY['Java']], ARRAY[ARRAY['Rust']]]
);数据插入完成后,即可对表中数据进行查询。
例如:
查询表中 f1 字段下的所有元素:
SELECT f1 FROM array3d_test;
f1
------------------------------------
{{{1,2},{3,4}},{{5,6},{7,8}}}
(1 row)查询表中 f1 字段下第一维中的第一个元素以及 f2 字段下第一维中的第一个元素,第二维中的第二个元素,以及第三维中的第一个元素:
SELECT f1[1], f2[1][2][1] FROM array3d_test;
f1 | f2
--------------+-----
{{1,2},{3,4}} | 4.4
(1 row)如需查询数组中的任意切片,需要选择 Hybrid DPS 集群运行查询。
例如,执行如下 SQL 获取 f1 字段中第 1 维中前 2 个元素内的第 1 个元素:
SELECT f1[1:2][1:1] FROM array3d_test;
f1
-------------------
{{{1,2}},{{5,6}}}
(1 row)再例如,执行如下 SQL 获取 f3 字段中第 1 维中前 2 个元素内第 3 维中的第 1 个元素:
SELECT f3[1:][1:][3:3] FROM array3d_test;
f3
---------------------------
{{{3.30000}},{{6.60000}}}
(1 row)!>注意
当前,Hybrid DPS 暂不支持数据切片访问。
关于数组切片访问的详细说明,请参考 使用 Hybrid DPS 进行切片访问。
注意事项
在多维数组中,同一条记录中的每一维中的元素必须有一样的长度,不同记录间,相同维度的元素可以有不同的长度。
MAXIR 支持的数组最大维度为 6。如建表时,指定的维度大于 6,建表不会报错。但是在数据写入过程中,会报错。例如:
-- f0 维度为 7,建表成功,不报错
CREATE TABLE test (
f0 int[][][][][][][]
);
-- 写入时报错
INSERT INTO test VALUES ('{{{{{{{1}}}}}}}');
ERROR: number of array dimensions (7) exceeds the maximum allowed (6)
LINE 1: INSERT INTO test VALUES ('{{{{{{{1}}}}}}}');数组值说明
将数组值写成字面常量时,需要用大括号将元素值括起来,并用英文逗号(,)分隔。你可以在任何元素值周围加上双引号(" "),如果某元素值本身包含英文逗号(,)或大括号({ }),则必须使用双引号进行包裹。如下为数组常量的一般格式示例:
'{<val1>, <val2>, ...}'其中,每一个 <val> 可以是一个常量也可以是一个子数组。如下是一个数组示例:
'{{1,2,3},{4,5,6},{7,8,9}}'如上示例数组是一个二维的 3 x 3 数组,包含 3 个整数子数组。
如需设置一个数组元素为 NULL,在该元素值处写 NULL(任何 NULL 的大写或小写变体都有效)。如果需要将该元素设置为字符串值 NULL,则需要将 NULL 用双引号包裹起来,即将元素设置为 "NULL"。
多维数组中,在同一条记录中,每一维中的元素必须有一样的长度,不同记录间,相同维度的元素可以有不同的长度:
CREATE TABLE test (
f0 int[],
f1 int[3],
f2 int[3][],
f3 int ARRAY,
f4 int ARRAY[3]
);
INSERT INTO test VALUES (
'{1,2,3}', -- f0: 一维数组
'{1,2,3}', -- f1: 一维数组,大小为3
'{{1,2},{3,4,5}}', -- f2: 二维数组,内部数组维度不匹配
'{1,2,3,4}', -- f3: 一维数组
'{1,2,3}' -- f4: 一维数组,大小为3
);
ERROR: multidimensional arrays must have array expressions with matching dimensions数组字段在指定 NOT NULL 时,只对最外层的一维生效,内层不生效:
CREATE TABLE test (a int[][] not null);
INSERT INTO test VALUES (NULL);
ERROR: null value in column "a" violates not-null constraint (seg0 192.168.215.2:7005 pid=31718)
DETAIL: Failing row contains (null).
--重新插入数据
INSERT INTO test VALUES ('{{0}, {NULL}}');
INSERT 0 1
SELECT * FROM test;
a
--------------
{{0},{NULL}}
(1 row)使用 Hybrid DPS 进行切片访问
Hybrid DPS 支持访问数组或子数组的任意矩形切片。一个数组切片通过在一个或多个数组维度上写 <lower-bound>:<upper-bound> 来表示。例如 多维数组 中的如下示例:
SELECT f1[1:2][1:1] FROM array3d_test;
f1
-------------------
{{{1,2}},{{5,6}}}
(1 row)该查询中的 f1[1:2][1:1] 表示 f1 字段中第 1 维中前 2 个元素内的第 1 个元素:
在切片中,<lower-bound> 或 <upper-bound> 可以省略,二者分别会数组下标的下限或上限替代。例如,[:]、[1:] 和 [:2] 都是正确的写法。例如 多维数组 中的如下示例:
SELECT f3[1:][1:][3:3] FROM array3d_test;
f3
---------------------------
{{{3.30000}},{{6.60000}}}
(1 row)该查询中的 f3[1:][1:][3:3] 表示 f3 字段中第 1 维中前 2 个元素内第 3 维中的第 1 个元素。
此外,如果任何维度被写成了切片,那么所有维度都会被视为切片。即任何只有一个数字的维度都会被视为从 1 到该数字的切片,即 [2] 会被视为 [1:2]。
与 PostgreSQL 的差异
在 PostgreSQL 中的数组长度只做展示用,实际写入的长度不受其影响。而 MAXIR 要求同一列中的所有行的维度必须与 Schema 中定义的一致。例如:
CREATE TABLE test (
f0 int[], -- 维度为 1
f1 int[][][], -- 维度为 3
f2 int ARRAY, -- 维度为 1
f3 int ARRAY[3] -- 维度为 1
);
-- 维度一致,写入成功
INSERT INTO test VALUES ('{1}', '{{{1}}}', '{1}', '{1}');
-- 维度不一致,写入失败
INSERT INTO test VALUES ('{{1}}', '{{1}}', '{{1}}', '{{1}}');