含函数的多维数组
来自 PostgreSQL wiki
跳转到导航跳转到搜索作者:Emanuel Calvo Franco、Alvaro Herrera、Carlos Bazán、Miguel Villa Gomez。
本文基于如下邮件列表主题撰写:http://archives.postgresql.org/message-id/86D81900A3164F978746F096076C5F53@pc13
尽管数组主题理解起来很容易,但可以考虑一些技巧。
以下代码对读者来说似乎既合乎逻辑又实操,但执行此函数会返回以下错误
ERROR: 无效的数组下标 CONTEXT: PL/pgSQL 函数“pepe”第 7 行的赋值
但是,编译不会带来任何错误。
CREATE OR REPLACE FUNCTION pepe(tamano integer) RETURNS integer
AS $_$
declare
matriz integer[][];
i integer;
BEGIN
for i in 1..tamano loop
matriz[i][1] = 1;
matriz[i][2] = 2;
end loop;
return 0;
END;
$_$ LANGUAGE plpgsql;
从其他语言(如 PL/Perl)来看,这是更加简单和实用的一种方式
CREATE OR REPLACE FUNCTION matriz(integer) returns integer language
'plperl' as $_$
$array = ();
my $numero = 0;
for ($numero;$numero < $_[0]; $numero++){
$array[$numero][1] = 1;
$array[$numero][2] = 2;
}
return 0;
$_$;
但出于各种原因,这种语言可能并不适合读者。
以下代码由 Miguel Angel Villa Gomez 提出,其建议创建一个动态函数,将数组维度作为参数传递给它。
CREATE OR REPLACE FUNCTION pepe_master (integer) RETURNS VOID AS $BODY$
DECLARE
nombre_funcion VARCHAR:= 'pepe_child';
notificacion VARCHAR:= $$RAISE NOTICE 'Elemento:%
(%)',elemento,array[elemento];$$;
funcion VARCHAR:=
'
CREATE OR REPLACE FUNCTION ' || nombre_funcion || ' ()
RETURNS VOID AS $$
DECLARE
array INTEGER[' || $1 || '];
elemento INTEGER;
BEGIN
FOR elemento IN 1..' || $1 || ' LOOP
array[elemento]:=elemento;
' || notificacion || '
END LOOP;
END;
$$ LANGUAGE PLPGSQL;
';
garbage VARCHAR;
BEGIN
EXECUTE funcion;
EXECUTE 'SELECT ' || nombre_funcion || '()';
END;
$BODY$ LANGUAGE PLPGSQL;
SELECT pepe_master(10);
此函数由 Alvaro Herrera 提出作为解决方案。
CREATE OR REPLACE FUNCTION pepe(tamano integer) RETURNS integer AS $_$
DECLARE
matriz integer[] = '{{1,2}}';
i integer;
BEGIN
for i in 1 .. tamano loop
matriz := matriz || '{1,2}'::integer[];
-- matriz[i] := 1;
RAISE NOTICE 'matriz: %', matriz[i];
end loop;
return matriz[1];
END;
$_$ LANGUAGE plpgsql;
以下为执行时的结果
ubuntu=# select pepe(8); NOTICE: matriz: NULL NOTICE: matriz: NULL NOTICE: matriz: NULL NOTICE: matriz: NULL NOTICE: matriz: NULL NOTICE: matriz: NULL NOTICE: matriz: NULL NOTICE: matriz: NULL pepe -- (1 row)
是有道理的!尚未为该数组的任何位置分配任何值...
Carlos Bazán 提出了
DECLARE
mi_arreglo TEXT[] := '{}';
BEGIN
...
...
-- y lo alimento con
mi_arreglo := mi_arreglo || ARRAY[[rec.dato1::text, rec.dato2::text]];
...
显然,必须根据数组类型(整数、文本等)关注数据类型。
Alvaro 利用 plpgsql 提出以下解决方案
CREATE OR REPLACE FUNCTION pepe(tamano integer) RETURNS integer AS $_$
declare
matriz integer[] = '{{1,2}}';
i integer;
begin
for i in 1 .. tamano loop
matriz := matriz || '{1,2}'::integer[];
-- matriz[i] := 1;
RAISE NOTICE 'matriz: % %', matriz[i][1], matriz[i][2];
end loop;
return matriz[1];
end;
$_$ LANGUAGE plpgsql;
或者,如果你想查看整个第 i 个元素,
RAISE NOTICE 'matriz: %', matriz[i:i][1:2];
(这被称为数组的“切片”。)
如果你不知道第二个维度的长度,可以使用 array_upper() 查找
RAISE NOTICE 'matriz: %', matriz[i:i][array_upper(matriz, 2)];
请注意,这等效于
RAISE NOTICE 'matriz: %', matriz[i:i][1:array_upper(matriz, 2)];
参考手册
si cada dimensión está escrita en partes (slice), por ejemplo: que contenga un :, entonces todas las dimensiones deben ser tratadas igual. Si alguna dimensión tiene un solo número (no :) será tratado como 1 hasta el número especificado.
通常,元素从 1 开始,但你可以保存起始下标不同的奇数数组,此时你需要的是 array_lower()
RAISE NOTICE 'matriz: %', matriz[i:i][array_lower(matriz, 2):array_upper(matriz, 2)];
如果修改用于初始化数组的字面值,可以进行测试
CREATE OR REPLACE FUNCTION pepe(tamano integer) RETURNS integer AS $_$
declare
matriz integer[] = '[1:1][-1:0]={{1,2}}';
i integer;
begin
for i in 1 .. tamano loop
matriz := matriz || '[-1:0]={1,2}'::integer[];
-- matriz[i] := 1;
RAISE NOTICE 'matriz: %', matriz[i:i][array_lower(matriz, 2):array_upper(matriz, 2)];
end loop;
raise notice 'matriz: %', matriz;
return matriz[1];
end;
$_$ LANGUAGE plpgsql ;
alvherre=# select pepe(10); NOTICE: matriz: {{1,2}} NOTICE: matriz: {{1,2}} NOTICE: matriz: {{1,2}} NOTICE: matriz: {{1,2}} NOTICE: matriz: {{1,2}} NOTICE: matriz: {{1,2}} NOTICE: matriz: {{1,2}} NOTICE: matriz: {{1,2}} NOTICE: matriz: {{1,2}} NOTICE: matriz: {{1,2}} NOTICE: matriz: [1:11][-1:0]={{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2}} pepe -- (1 fila)
感谢所有参与此主题讨论的人员。希望它有所帮助!