PL / pgSQL:访问自定义类型数组元素的字段

时间:2017-01-20 21:19:50

标签: postgresql variable-assignment plpgsql

我已经定义了一个自定义类型:

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

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相比,开销更大。我不会将它用于简单的情况。但是如果你有很多作业,那么使用临时表可能还是有用的。