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

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

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

我被这个(简化的)问题困住了。

我的数据库模式有一个 n 到 m 的关系(作者、书籍、author_books)

现在我想要一个 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;

作为论据,我想通过类型书的记录和编写它的作者。但这究竟是如何工作的呢?我在谷歌上搜索了很多,但似乎无法弄清楚...

问题一:函数大纲是否“正确”/是否有意义?

问题2:如何将记录簿插入表格簿?我是否必须遍历书籍的所有字段(书名、isbn、出版商...)并将它们添加到 INSERT INTO 语句中,还是有“更聪明”的方法?

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

非常感谢您的帮助。

最佳答案

使用 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.

关于您的问题:

Question 1: Is the function outline "correct"/does it make sense?

传递基类型而不是复合类型 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;

Question 2: How to insert record book into table book? (...) or is there a "smarter" way?

更聪明的方法是用(variable_name).*分解复合类型。

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

Question 3: How would I call my function insert_book? ...

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

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

关于postgresql - 将记录作为函数参数传递 PL/pgSQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12716024/

相关文章:

postgresql - 我如何知道我的 PostgreSQL 服务器是否使用 "C"语言环境?

postgresql - 使用 pl/pgsql INSERT 选择行

postgresql - 整数列可以为空吗?

javascript - 在 Javascript 中检查数组中元素的类型

types - 在 Go 中调用嵌入式类型的重载方法的正确方法

postgresql - 为postgresql中的每个更新行调用一个函数

windows - psql : error: could not connect to server: FATAL: password authentication failed for user

sql - 在 PL/PGSQL 动态 SQL 内部函数中引用局部变量

postgresql - postgres 更新触发器执行除实际更新之外的所有其他操作

types - 为什么 Leans `Prop` 位置得到特殊处理?