使用复合类型的数组作为函数参数并访问它

Pos*_*thu 5 postgresql plpgsql functions array composite-types

Books在 Postgres 中创建了一个类型,它有 2 个numeric字段和 2 个varchar字段。我想将Books一个函数的数组发送到INSERT匹配表中的那些值。

这是我的类型:

CREATE TYPE Books AS (
V_Book_ID NUMERIC,
V_Row_Num NUMERIC,
V_Book_OWNER TEXT,
V_Book_OWNER_ID TEXT
);
Run Code Online (Sandbox Code Playgroud)

这是我的功能:

CREATE OR REPLACE FUNCTION Update_Table(row_book Books[]) RETURNS TEXT AS $$
DECLARE
   Status TEXT;
   I_Max integer := array_length(row_book, 1);
BEGIN
FOR I in 1..I_Max
  LOOP
   INSERT INTO books_table(Book_ID,
   Row_Num,
   Book_OWNER,
   Book_OWNER_ID)
   values
   (row_book[I].V_Book_ID,
   row_book[I].V_Row_Num,
   row_book[I].V_Book_OWNER,
   row_book[I].V_Book_OWNER_ID);
END LOOP;

   STATUS:='Saved';
exception when others then
   STATUS:='failure';
   RETURN STATUS;

END;
$$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)

如何向函数发送数据,或者如何使用数据调用函数?

Erw*_*ter 9

前段时间我在 SO 上回答了一个类似的问题,提出与unnest()@a_horse一样的解决方案:

如果books_table与复合类型具有相同的行类型books,则根本不需要创建附加类型,只需使用表的行类型:

CREATE TABLE books_table (
  book_id numeric
, row_num numeric
, book_owner text
, book_owner_id text
);
Run Code Online (Sandbox Code Playgroud)

PL/pgSQL 函数

如果您出于某种未声明的原因需要plpgsql 函数:

CREATE TABLE books_table (
  book_id numeric
, row_num numeric
, book_owner text
, book_owner_id text
);
Run Code Online (Sandbox Code Playgroud)

使用行值列表调用示例:

SELECT update_table_variadic('(2,100,Arthur,1)', '(2,50,Zaphod,1)');
Run Code Online (Sandbox Code Playgroud)

如果不使用VARIADIC,函数调用将需要一个数组参数。

要么数组字面量(可选择显式转换):

SELECT update_table('{"(1,100,Arthur,1)","(1,50,Zaphod,1)"}'::books_table[]);
Run Code Online (Sandbox Code Playgroud)

看:

或者您可以使用像@a_horse 演示这样的数组构造函数。数组文字通常更容易提供。

要点:

使用更简单FOREACH的循环遍历数组。看:

除非您知道自己在做什么,否则在 Postgres 中避免使用 CaMeL 大小写名称。

(可选)使用VARIADIC参数来简化函数调用的语法。然后您可以提供行值列表。请注意函数参数的最大数量(默认为 100),如果您使用VARIADIC

SQL函数

如果不需要捕获异常,也不需要返回字符串 'Saved' / 'Failure',请简化:

CREATE OR REPLACE FUNCTION update_table_set(VARIADIC _books_arr books_table[])
  RETURNS void
  LANGUAGE sql AS
$func$
   INSERT INTO books_table
   SELECT * FROM unnest(_books_arr) b;
$func$;
Run Code Online (Sandbox Code Playgroud)

db<>fiddle here
旧的sqlfiddle


小智 2

要创建类型的数组,请使用显式数组构造函数:

array[(1,100,'Arthur',1), (1,50,'Zaphod',1)]::books[]
Run Code Online (Sandbox Code Playgroud)

因此,要调用您的函数,您需要使用:

select update_table(array[(1,100,'Arthur',1), (1,50,'Zaphod',1)]::books[])
Run Code Online (Sandbox Code Playgroud)

但是您的函数有一个错误:在循环之后缺少 return 语句,因为在发生异常时才执行异常块中的语句。

所以你需要这样的东西:

begin 

  .... 

  STATUS:='Saved';
  return status;  ---<<< this is missing

  exception when others then
    STATUS:='failure';
    RETURN STATUS; --<<< this is only execute if an exception occurs

END;
Run Code Online (Sandbox Code Playgroud)

或者你需要另一个begin .. end;块:

begin 

  begin    
    for ... 
    end loop;

    STATUS:='Saved';

  exception when others then
    STATUS:='failure';
  end;

  RETURN STATUS; 
END;
Run Code Online (Sandbox Code Playgroud)

不相关,但是:您不需要循环来迭代数组。您可以使用单个语句更有效地做到这一点:

INSERT INTO books_table 
   (Book_ID, Row_Num, Book_OWNER, Book_OWNER_ID)
select *
from unnest(row_book);
Run Code Online (Sandbox Code Playgroud)