与PostgreSQL中的数组有关的错误“错误:记录文字格式错误:”

时间:2018-12-05 11:52:22

标签: postgresql plpgsql

我正在尝试将表中的值放入数组中,并且数组定义与表的列定义不同。我试过做强制转换,但是没有用。基本上,我需要将表中的值作为数组(tab_small_str)。有人可以建议吗?

CREATE TYPE tab_small_str AS (
  str CHARACTER VARYING(50)
);  

create table test_emp(emp_id integer, ename character varying (10));

insert into test_emp values(1,'a1')

insert into test_emp values(2,'a2')

insert into test_emp values(3,'a3')

CREATE OR REPLACE function test_fn () RETURNS VARCHAR[] as
$$
DECLARE
 v_ename tab_small_str[];
 i tab_small_str;
BEGIN

  SELECT   ARRAY(SELECT ename::tab_small_str FROM test_emp) INTO v_ename;

  RAISE INFO 'array is: %',v_ename;

  RETURN v_ename;

  FOREACH i IN ARRAY v_ename
LOOP 
   RAISE info 'value of ename is%', i;
END LOOP;

END;
$$
language plpgsql;

(function compiles fine).
select test_fn()

 --gives below error
    ERROR:  malformed record literal: "a1"
    DETAIL:  Missing left parenthesis.
    CONTEXT:  SQL statement "SELECT   ARRAY(SELECT ename::tab_small_str FROM test_emp)"
    PL/pgSQL function test_fn() line 7 at SQL statement
********** Error **********

ERROR: malformed record literal: "a1"
SQL state: 22P02
Detail: Missing left parenthesis.
Context: SQL statement "SELECT   ARRAY(SELECT ename::tab_small_str FROM test_emp)"
PL/pgSQL function test_fn() line 7 at SQL statement

嗨404, 我按照建议进行了修改:

CREATE OR REPLACE function test_fn () RETURNS tab_small_str[] as
$$
DECLARE
 v_ename tab_small_str[];
 i  tab_small_str;
BEGIN

  SELECT   ARRAY(SELECT ROW(ename)::tab_small_str FROM test_emp) INTO v_ename;

  RAISE INFO '%',v_ename;

  FOREACH i IN ARRAY v_ename
LOOP 
   RAISE NOTICE '%', i;
END LOOP;

  RETURN v_ename;

END;
$$
language plpgsql;

它返回输出为:

INFO:  {(a1),(a2),(a3)}
CONTEXT:  PL/pgSQL function test_fn() line 9 at RAISE
NOTICE:  (a1)
CONTEXT:  PL/pgSQL function test_fn() line 13 at RAISE
NOTICE:  (a2)
CONTEXT:  PL/pgSQL function test_fn() line 13 at RAISE
NOTICE:  (a3)
CONTEXT:  PL/pgSQL function test_fn() line 13 at RAISE

我的问题是为什么输出用括号括起来-为什么不仅是a1而是(a1)。您能建议一下吗?

1 个答案:

答案 0 :(得分:2)

由于缺乏更好的描述,您的新类型不是“单字段数据类型”,您可以在其中直接将类似VARCHAR(10)的内容转换为它;这是一个包含单个字段的ROW。所以类似'blah'::tab_small_str之类的事情失败了,因为它试图将文本强制转换为包含字段而不是字段本身的类型。

要解决,请使用您现有的查询:

  

SELECT ename::tab_small_str FROM test_emp

更改为:

SELECT ROW(ename)::tab_small_str FROM test_emp

关于为什么您的结果用方括号括起来的原因:这是当将ROW或复合类型显示为单个字段(或未扩展)时的显示方式:例如,如果执行SELECT * FROM test_emp*将所有字​​段分别作为单独的列返回;但是,如果您执行SELECT test_emp FROM test_emp,则会返回未展开的表行,因此看起来像这样:

(1,a1)
(2,a2)
(3,a3)

和复合类型完全相同。 i tab_small_str;-将i视为test_emp,其中包含可以扩展的字段。在您的代码中,您正在打印对象i,而不是i.*i.str。因此,将代码更改为:

FOREACH i IN ARRAY v_ename
LOOP 
   RAISE NOTICE '%', i.str;
END LOOP;