tar*_*aki 17 postgresql types plpgsql common-table-expression sql-insert
首先,我是pl/pgsql的新手.需要它用于项目.
我坚持这个(简化)问题.
我的db模式有一个到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;
Run Code Online (Sandbox Code Playgroud)
作为论据我想通过类型书的记录和编写它的作者.但这究竟是如何工作的呢?我用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.
非常感谢您的帮助.
Erw*_*ter 17
使用unnest()和修改数据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
Run Code Online (Sandbox Code Playgroud)
第一个CTE x仅用于简化数据输入,而不是严格需要的.
问题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;
Run Code Online (Sandbox Code Playgroud)
问题2:如何将记录簿插入表格书?(...)还是有"更聪明"的方式?
更智能的方法是使用分解复合类型(variable_name).*.
由于类型保证匹配table(从它派生),这是极少数情况之一,完全没问题,不提供INSERT持久代码中命令的列列表.
问题3:如何调用我的函数insert_book?...
SELECT f_insert_book('(1,foo_book)'::book, '{1,2,3}'::int[]);
Run Code Online (Sandbox Code Playgroud)
在其他plpgsql函数中,如果不为(不存在的)结果提供target(),请使用PERFORM而不是.SELECTINTO foo