将记录作为函数参数PL / pgSQL传递

时间:2012-10-03 20:04:55

标签: postgresql types plpgsql common-table-expression sql-insert

首先,我是pl / pgsql的新手。需要它用于项目。

我遇到了这个(简化的)问题。

我的数据库架构有一个n到m的关系(作者,书籍,作者书)

现在我想要一个pl / psgsql函数insert_book。 (我知道所有作者肯定已经在作者表中,所以我只想传递他们的主键。)

这个功能概要是我的想法。

 create or replace function insert_book(book_to_insert book, authors integer[])
  returns void as $$
begin
    -- insert book into table books
    -- for each author add an entry to author_books table
end;
 $$ language plpgsql;

作为论据,我想通过类型书的记录和编写它的作者。但这究竟是如何工作的呢?我用Google搜索了一下,似乎无法弄清楚这一点......

问题1 :功能大纲是否“正确”/是否有意义?

问题2 :如何将记录簿插入表格书?我是否必须遍历书籍的所有领域(title,isbn,publisher,...)并将它们添加到INSERT INTO语句中或者是否有“更智能”的方式?

问题3 :我如何调用我的函数insert_book?我在这里找到了这个例子(http://dbaspot.com/postgresql/206142-passing-record-function-argument-pl-pgsql.html),但这对我没有帮助。出于测试目的,我使用的是shell,但稍后我们将使用Java和JDBC。

非常感谢你的帮助。

2 个答案:

答案 0 :(得分:17)

使用unnest()data-modifying CTE(需要Postgres 9.1或更高版本),这可以是一个简单的SQL查询:

WITH x AS (SELECT '(1,foo_book)'::book AS _book
                , '{1,2,3}'::int[]     AS _authors)
   , y AS (
   INSERT INTO book  -- no column list, correct due to composite type
   SELECT (x._book).*
   FROM   x
   RETURNING book_id
   )
INSERT INTO author_book (book_id, author_id)
SELECT y.book_id, unnest(x._authors)
FROM   x,y;  -- CROSS JOIN ok, only 1 row for x and y

第一个CTE x仅用于简化数据输入,并非严格需要。

SQL Fiddle.

关于你的问题:

  

问题1:功能大纲是否“正确”/是否有意义?

可能更容易传递基类型而不是复合类型book,但它是一种非常有效的方法。但是,您必须了解复杂类型的语法。例如,请注意我示例中名称的括号:(x._book).*

plpgsql函数可能如下所示:

CREATE OR REPLACE FUNCTION f_insert_book(_book book, _authors integer[])
   RETURNS void AS 
$func$
BEGIN
    WITH y AS (
        INSERT INTO book b
        SELECT (_book).*
        RETURNING b.book_id
        )
    INSERT INTO author_book (book_id, author_id)
    SELECT y.book_id, unnest(_authors)
    FROM   y;
END
$func$ LANGUAGE plpgsql;
  

问题2:如何将记录簿插入表格书? (...)还是有“更聪明”的方式?

更智能的方法是使用(variable_name).*分解复合类型。

由于类型保证匹配table(从中派生),这是极少数情况之一,完全可以,在持久化代码中为INSERT命令提供列列表。

  

问题3:如何调用我的函数insert_book? ...

SELECT f_insert_book('(1,foo_book)'::book, '{1,2,3}'::int[]);

在其他plpgsql函数中,如果您没有为(不存在的)结果提供目标(SELECT),请使用PERFORM而不是INTO foo

答案 1 :(得分:1)

传递JSON数据类型(Postgresql 9.2或更高版本):

CREATE OR REPLACE FUNCTION f_insert_book(_book json, _authors json)
   RETURNS void AS 
$$
BEGIN
-- insert book into table books
Insert into books values select * from json_populate_recordset(null:book, _book);
    -- for each author add an entry to author_books table
Insert into authors values select * from json_populate_recordset(null:authors, _authors);
end;
$$ language plpgsql;