我已经定义了一个自定义类型:
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
答案 0 :(得分:2)
PLpgSQL有时非常简单,也许太简单了。赋值语句的左侧部分是一个示例 - 左侧可以是变量,记录字段或数组字段。不支持任何复杂的左侧部分表达式。
您需要一个数组元素类型的辅助变量。
DECLARE aux MTYPE;
aux := ax[1];
aux.f := 100000;
ax[1] := aux;
答案 1 :(得分:1)
这似乎与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没有实现相同的功能?
尽管如此,另一种可能的解决方法是在临时表上使用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
$$;
与@Pavel's simpler workaround相比,开销更大。我不会将它用于简单的情况。但是如果你有很多作业,那么使用临时表可能还是有用的。