【问题标题】:Passing array of a composite type to stored procedure将复合类型的数组传递给存储过程
【发布时间】:2014-03-21 18:36:06
【问题描述】:

我可能在形成文字时做错了。假设我有一个像这样的简单存储过程:

CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
  RETURNS SETOF text AS
$BODY$
DECLARE
    temp_var composite_type;
BEGIN

    FOR temp_var IN SELECT unnest(input_array) LOOP
        return next temp_var.message;
    END LOOP;

END
$BODY$
  LANGUAGE plpgsql;

composite_type 定义为:

CREATE TYPE composite_type AS
   (message text,
    amount numeric(16,2));

执行这样的查询:

SELECT * FROM do_something('{"(test,11)","(test2,22)"}')

产生这个结果集:

(test,11.00)
(test2,22.00)

代替:

test
test2

我的文字有问题还是我应该以不同的方式访问message 字段?感谢您的任何建议。

【问题讨论】:

    标签: sql postgresql stored-procedures plpgsql


    【解决方案1】:

    您指定输入的方式看起来不错,因为使用行构造函数和数组构造函数语法观察到相同的行为:

    SELECT * FROM do_something( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
    

    还有:

    SELECT ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[];
    

    产生:

     '{"(test,11.00)","(test2,22.00)"}'
    

    如果你添加一个:

     RAISE NOTICE '!%!',temp_var;
    

    在循环内的输出是:

    NOTICE:  !("(test,11.00)",)!
    NOTICE:  !("(test2,22.00)",)!
    

    表明您实际上得到了一个元组,其中“消息”作为您期望的元组文本和一个空的“金额”。

    所以。为什么?

    这有点微妙。您正在使用:

    SELECT unnest(input_array)
    

    这似乎做你想做的,对吧:

    regress=>     SELECT unnest( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
        unnest     
    ---------------
     (test,11.00)
     (test2,22.00)
    (2 rows)
    

    ...但实际上,它返回的是composite_type 类型的单列。 PL/PgSQL 复合类型赋值需要每个类型列一列。所以单列被推到“消息”中,没有第二列。

    改为:

    SELECT * FROM unnest(input_array)
    

    解压缩复合材料以进行分配。然后它按预期工作:

    regress=> SELECT * FROM do_something( ARRAY[ ROW('test',11), ROW('test2',22) ]::composite_type[] );
     do_something 
    --------------
     test
     test2
    (2 rows)
    

    如果composite_type 的第一个字段是非文本类型,您会收到一个关于此信息的错误信息。

    【讨论】:

    • 很好的解释。这是 plpgsql 中一个相当不幸的设计。与错误接壤。 (我只是在运行相同的测试集。你打败了我。:))
    • @ErwinBrandstetter 是的,倾向于同意这是边界错误。
    • @CraigRinger:这不是错误,而是功能 :( - 这是两个事实的结果:Postgres 支持嵌套复合类型 - 任何人都应该注意嵌套的级别;而 plpgsql 是键入顺从并使用基于后期文本的转换 - 因此任何内容都会转换为文本,然后转换为目标类型 - 但您丢失了有关类型的元数据。
    【解决方案2】:

    Craig 很好地解释了这种行为的原因 - FOR 语句中的赋值变量 = 值期望零嵌套。所以你应该这样做:

    CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
    RETURNS SETOF text AS $BODY$
    DECLARE
        temp_var record;
    BEGIN
         -- unnesting
        FOR temp_var IN SELECT (unnest(input_array)).*
        LOOP
            RETURN NEXT temp_var.message;
        END LOOP;
        RETURN;
    END
    $BODY$ LANGUAGE plpgsql;
    

    或者——更可取——在“列列表”中使用 SetReturnedFunction

    CREATE OR REPLACE FUNCTION do_something(input_array composite_type[])
    RETURNS SETOF text AS $BODY$
    DECLARE
        temp_var record;
    BEGIN
         -- SELECT FROM
        FOR temp_var IN SELECT * FROM unnest(input_array) 
        LOOP
            RETURN NEXT temp_var.message;
        END LOOP;
        RETURN;
    END
    $BODY$ LANGUAGE plpgsql;
    

    【讨论】:

      猜你喜欢
      • 2016-04-27
      • 1970-01-01
      • 2010-11-07
      • 1970-01-01
      • 2018-01-01
      • 1970-01-01
      • 2014-08-29
      相关资源
      最近更新 更多