PL/pgSQL: 访问自定义类型数组元素的字段
PL/pgSQL: accessing fields of an element of an array of custom type
我定义了一个自定义类型:
create type pg_temp.MYTYPE as (f1 int, f2 text);
然后,在一个函数或块中,我声明了一个这样类型的数组:
declare ax MYTYPE[];
我可以通过熟悉的语法访问元素 ax[1].f1
,但只是为了阅读。
当我使用相同的语法设置字段时,出现语法错误。
create type pg_temp.MYTYPE as (f1 int, f2 text);
do $$
declare x MYTYPE;
declare ax MYTYPE[];
declare f int;
begin
x.f1 = 10;
x.f2 = 'hello';
--assigning an element: OK
ax[1] = x;
--reading an element's field: OK
f = ax[1].f1;
--writing an elememt's field: SYNTAX ERROR:
ax[1].f1 = f;
end; $$
错误如下:
psql:test.sql:28: ERROR: syntax error at or near "."
LINE 20: ax[1].f1 = f;
^
我也试过语法 (ax[1]).f1
得到了同样的结果。
执行此操作的正确语法是什么?
Postgres 服务器版本:9.2.2
PLpgSQL有时很简单,也许是太简单了。赋值语句的左边部分是一个例子——左边只能是变量、记录字段或数组字段。不支持任何复杂的左半部分表达式。
您需要一个数组元素类型的辅助变量。
DECLARE aux MTYPE;
aux := ax[1];
aux.f := 100000;
ax[1] := aux;
这对 plpgsql 来说似乎特别不合理,因为 SQL 本身 可以 很好地更新一个复合类型的字段数组。
演示:
CREATE TEMP TABLE mytype (f1 int, f2 text);
CREATE TEMP TABLE mycomp (c mytype);
INSERT INTO mycomp VALUES ('(10,hello)');
UPDATE mycomp
SET c.f1 = 12 -- note: without parentheses
WHERE (c).f1 = 10; -- note: with parentheses
TABLE mycomp;
c
------------
(12,hello)
CREATE TEMP TABLE mycomparr (ca mytype[]);
INSERT INTO mycomparr VALUES ('{"(10,hello)"}');
UPDATE mycomparr
SET ca[1].f1 = 12 -- works!
WHERE (ca[1]).f1 = 10;
TABLE mycomparr;
ca
----------------
{"(12,hello)"}
我想知道为什么 plpgsql 没有实现相同的功能?
尽管如此,另一种可能的解决方法是在临时 table:
上使用 UPDATE
DO
$$
DECLARE
ax mytype[] := '{"(10,hello)"}';
BEGIN
CREATE TEMP TABLE tmp_ax ON COMMIT DROP AS SELECT ax;
UPDATE tmp_ax SET ax[1].f1 = 12;
-- WHERE (ax[1]).f1 = 10; -- not necessary while only 1 row.
SELECT t.ax INTO ax FROM tmp_ax t; -- table-qualify column!
RAISE NOTICE '%', ax;
END
$$;
这比 的开销要多。我不会将它用于简单的情况。但是,如果您有很多作业,使用临时 table.
可能仍然值得
我定义了一个自定义类型:
create type pg_temp.MYTYPE as (f1 int, f2 text);
然后,在一个函数或块中,我声明了一个这样类型的数组:
declare ax MYTYPE[];
我可以通过熟悉的语法访问元素 ax[1].f1
,但只是为了阅读。
当我使用相同的语法设置字段时,出现语法错误。
create type pg_temp.MYTYPE as (f1 int, f2 text);
do $$
declare x MYTYPE;
declare ax MYTYPE[];
declare f int;
begin
x.f1 = 10;
x.f2 = 'hello';
--assigning an element: OK
ax[1] = x;
--reading an element's field: OK
f = ax[1].f1;
--writing an elememt's field: SYNTAX ERROR:
ax[1].f1 = f;
end; $$
错误如下:
psql:test.sql:28: ERROR: syntax error at or near "."
LINE 20: ax[1].f1 = f;
^
我也试过语法 (ax[1]).f1
得到了同样的结果。
执行此操作的正确语法是什么?
Postgres 服务器版本:9.2.2
PLpgSQL有时很简单,也许是太简单了。赋值语句的左边部分是一个例子——左边只能是变量、记录字段或数组字段。不支持任何复杂的左半部分表达式。
您需要一个数组元素类型的辅助变量。
DECLARE aux MTYPE;
aux := ax[1];
aux.f := 100000;
ax[1] := aux;
这对 plpgsql 来说似乎特别不合理,因为 SQL 本身 可以 很好地更新一个复合类型的字段数组。
演示:
CREATE TEMP TABLE mytype (f1 int, f2 text);
CREATE TEMP TABLE mycomp (c mytype);
INSERT INTO mycomp VALUES ('(10,hello)');
UPDATE mycomp
SET c.f1 = 12 -- note: without parentheses
WHERE (c).f1 = 10; -- note: with parentheses
TABLE mycomp;
c ------------ (12,hello)
CREATE TEMP TABLE mycomparr (ca mytype[]);
INSERT INTO mycomparr VALUES ('{"(10,hello)"}');
UPDATE mycomparr
SET ca[1].f1 = 12 -- works!
WHERE (ca[1]).f1 = 10;
TABLE mycomparr;
ca ---------------- {"(12,hello)"}
我想知道为什么 plpgsql 没有实现相同的功能?
尽管如此,另一种可能的解决方法是在临时 table:
上使用UPDATE
DO
$$
DECLARE
ax mytype[] := '{"(10,hello)"}';
BEGIN
CREATE TEMP TABLE tmp_ax ON COMMIT DROP AS SELECT ax;
UPDATE tmp_ax SET ax[1].f1 = 12;
-- WHERE (ax[1]).f1 = 10; -- not necessary while only 1 row.
SELECT t.ax INTO ax FROM tmp_ax t; -- table-qualify column!
RAISE NOTICE '%', ax;
END
$$;
这比