postgresql - 复合数组类型作为 PostgreSQL 中的 OUTPUT 参数

标签 postgresql plpgsql postgresql-9.4

我试图在我的函数中将数据插入到复合数组类型中。它应该接受来自输入参数的复合数组类型的数据,并将数据存储到相同类型的输出参数中。

CREATE TYPE public.type_x_type AS (x integer);

CREATE TYPE public.type_y_type AS(x integer,y integer);

我的功能是

CREATE OR REPLACE FUNCTION GET_PRICE_PC_X
  (
    IP_PRICE_INFO IN TYPE_X_TYPE[],
    PC_COST OUT TYPE_Y_TYPE[],
    OP_RESP_CODE OUT VARCHAR,
    OP_RESP_MSG OUT VARCHAR
  )
RETURNS RECORD AS $$
DECLARE
  SELECTED_PRICE CURSOR(IP_PFCNTR INT)
  FOR
    SELECT ID, PHONE FROM CUSTOMER WHERE ID=IP_PFCNTR;
  J NUMERIC(10);
BEGIN
J := 0;
  FOR I IN ARRAY_LOWER(IP_PRICE_INFO,1) .. ARRAY_UPPER(IP_PRICE_INFO,1)
  LOOP
    FOR K IN SELECTED_PRICE(IP_PRICE_INFO[I].X)
    LOOP
    PC_COST := ROW(K.ID,K.PHONE);
 END LOOP;
  END LOOP;
  OP_RESP_CODE :='000';
  OP_RESP_MSG  :='Success';
EXCEPTION
WHEN OTHERS THEN
  OP_RESP_CODE :='200';
  OP_RESP_MSG  :=SQLERRM;
END;
$$ language 'plpgsql';

select * from GET_PRICE_PC_X(ARRAY[ROW(1)] :: TYPE_X_TYPE[]);

我收到以下错误。

    PC_COST | OP_RESPONSE_CODE | OP_RESP_MSG
---------------------------------------------------------
            |  200              | malformed array literal: "(1,30003)"  

我将在某处调用该 OUT 类型,因此我需要将数据插入到数组中。

最佳答案

当你开发一个函数时,不要使用WHEN OTHERS。那么调试就很糟糕了。您的函数的问题是将复合类型赋值给数组

PC_COST := ROW(K.ID,K.PHONE);

这是错误的。可能你会做追加。

关键部分应该是这样的

J := 0; PC_COST := '{}';
FOR I IN ARRAY_LOWER(IP_PRICE_INFO,1) .. ARRAY_UPPER(IP_PRICE_INFO,1)
LOOP
  FOR K IN SELECTED_PRICE(IP_PRICE_INFO[I].X)
  LOOP
    PC_COST := PC_COST || ROW(K.ID,K.PHONE)::type_y_type;
  END LOOP;
END LOOP;

您的函数可以用一个查询替换 - 可能可读性较差,但速度明显更快 - 嵌套查询的循环可能很慢(运行一个简单的 SELECT 比更琐碎的 SELECTs):

CREATE OR REPLACE FUNCTION public.get_price_pc_x(ip_price_info type_x_type[],
                                                 OUT pc_cost type_y_type[],
                                                 OUT op_resp_code character varying,
                                                 OUT op_resp_msg character varying)
RETURNS record
LANGUAGE plpgsql STABLE
AS $function$
BEGIN
  pc_cost := ARRAY(SELECT ROW(id, phone)::type_y_type
                     FROM customer
                    WHERE id IN (SELECT (unnest(ip_price_info)).x));
  OP_RESP_CODE :='000';
  OP_RESP_MSG  :='Success';
EXCEPTION
  WHEN OTHERS THEN
    OP_RESP_CODE :='200';
    OP_RESP_MSG  :=SQLERRM;
END;
$function$;

注意:使用NUMERIC 类型作为循环变量是错误的想法——这种类型很昂贵,应该只用于金钱或珍贵的计算。 int 类型在这个地方是绝对正确的。

通常你可以减少你的功能更多 - 错误处理不应该在那里 - 没有理由为什么这个功能应该失败 - (不是可以处理的原因)

CREATE OR REPLACE FUNCTION public.get_price_pc_x(ip_price_info type_x_type[]) 
RETURNS type_y_type[]
LANGUAGE sql STABLE
AS $function$
  SELECT ARRAY(SELECT ROW(id, phone)::type_y_type
                     FROM customer
                    WHERE id IN (SELECT (unnest(ip_price_info)).x));
$function$;

关于postgresql - 复合数组类型作为 PostgreSQL 中的 OUTPUT 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42128807/

相关文章:

sql - Go sql - 准备好的语句范围

sql - 上一行结束日期作为 SQL 中的下一行开始日期

sql - Postgres - 如何对窗口函数列的每 x 行求和?

sql - PLpgSQL 函数结果上的 FOR 循环

sql - PL/pgSQL 查询计划内部函数比外部函数更糟糕

Postgresql 不使用多列索引 (btree_gin)

sql - 在层次结构表 PostgreSQL 上选择查询

postgresql - 限制减慢了我的 postgres 查询

postgresql - 动态语句 PL/PGSQL 中的错误(函数和运算符最多可以采用一个集合参数)

sql - 如何使用递归查询跟踪以前的 ID?