PL/pgSQL: accessing fields of an element of an array of custom type

空扰寡人 提交于 2019-12-11 04:11:38

问题


I've defined a custom type:

create type pg_temp.MYTYPE as (f1 int, f2 text);  

Then, inside a function or a block, I've declared an array of such type:

declare ax MYTYPE[];

I can access an element through the familiar syntax ax[1].f1, but just for reading it.
When I use the same syntax for setting the field, I get a syntax error.

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; $$

The error is the following:

psql:test.sql:28: ERROR:  syntax error at or near "."
LINE 20:  ax[1].f1 = f;
          ^

I've tried also the syntax (ax[1]).f1 with the same result.
Which is the correct syntax to do this?

Postgres server version: 9.2.2


回答1:


PLpgSQL is sometimes very simple, maybe too simple. The left part of assignment statement is a example - on the left can be variable, record field, or array field only. Any complex left part expression are not supported.

You need a auxiliary variable of array element type.

DECLARE aux MTYPE;

aux := ax[1];
aux.f := 100000;
ax[1] := aux;



回答2:


That seems particularly inconsequent of plpgsql since SQL itself can very well update a field of a composite type inside an array.

Demo:

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)"}

I wonder why plpgsql does not implement the same?

Be that as it may, another possible workaround would be to use UPDATE on a temporary table:

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
$$;

That's more overhead than with @Pavel's simpler workaround. I would not use it for the simple case. But if you have lots of assignments it might still pay to use the temporary table.



来源:https://stackoverflow.com/questions/41772518/pl-pgsql-accessing-fields-of-an-element-of-an-array-of-custom-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!