Postgresql 将记录作为函数参数PL/pgSQL传递
首先,我对pl/pgsql非常陌生。项目需要它 我被这个(简化的)问题困住了 我的数据库模式具有n到m关系(作者、书籍、作者和书籍) 现在我想要一个pl/psgsql函数insert\u book。(我知道所有作者都肯定已经在author表中,所以我只想传递他们的主键) 这个函数大纲就是我想要的Postgresql 将记录作为函数参数PL/pgSQL传递,postgresql,types,plpgsql,common-table-expression,sql-insert,Postgresql,Types,Plpgsql,Common Table Expression,Sql Insert,首先,我对pl/pgsql非常陌生。项目需要它 我被这个(简化的)问题困住了 我的数据库模式具有n到m关系(作者、书籍、作者和书籍) 现在我想要一个pl/psgsql函数insert\u book。(我知道所有作者都肯定已经在author表中,所以我只想传递他们的主键) 这个函数大纲就是我想要的 create or replace function insert_book(book_to_insert book, authors integer[]) returns void as $$
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;
作为论据,我想通过一本书的类型和作者的记录。但这到底是怎么回事?我在谷歌上搜索了很多次,但似乎无法找到答案
问题1:功能大纲“正确”吗/有意义吗
问题2:如何将记录簿插入表格簿?我是否必须检查书籍的所有字段(标题、isbn、出版商等)并将它们添加到INSERT INTO语句中,还是有一种“更聪明”的方法
问题3:如何调用函数insert\u book?我在这里找到了这个例子(http://dbaspot.com/postgresql/206142-passing-record-function-argument-pl-pgsql.html),但这对我没什么帮助。出于测试目的,我正在使用shell,但稍后我们将使用Java和JDBC
非常感谢您的帮助。使用和(需要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
第一个CTEx
仅用于简化数据输入,并不严格需要
关于你的问题:
问题1:功能大纲“正确”吗/有意义吗
传递基类型可能比传递复合类型book
更容易,但这是一种非常有效的方法。不过,您必须了解复杂类型的语法。例如,请注意我的示例中名称周围的括号:(x.\u 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:如何将记录簿插入表簿?(…)还是有“更聪明”的方法
更聪明的方法是使用(变量名称)分解复合类型。*
由于类型保证与表
(从表中派生)匹配,这是极少数情况之一,在这种情况下,在持久化代码中不为插入
命令提供列列表是完全可以的
问题3:我如何调用我的函数insert_book
在其他plpgsql函数中,如果没有为(不存在的)结果提供目标(到foo
),请使用而不是选择。传递JSON数据类型(Postgresql 9.2或更高版本):
我得多读一些关于CTE的书。我必须承认我不理解他们。我看过你的几篇文章,其中你使用了它们,它们似乎简化了你的解决方案,但这并不是在处理问题时考虑使用的东西。@DavidS:对于简单的情况,普通的子查询通常要快一点。但CTE对于更复杂的操作或在多个子查询中重用结果非常有用。数据修改CTE非常适合同时操作多个表,将它们绑定在一起。递归CTE基本上是使用纯SQL进行递归处理的唯一方法。非常强大-但并不总是容易理解。是一个让你开始的好地方。谢谢欧文。。。好建议。我需要再读一次手册,并玩一些例子。对于更复杂的操作,我倾向于使用“做”语句,这些语句允许我以大脑似乎“得到”的方式做事情。我确信这是因为在此期间我编写的过程代码比SQL多。:)再次感谢,你好,欧文。非常感谢您的详细回答。它帮助了我很多,而且它像一个符咒一样工作:)。
SELECT f_insert_book('(1,foo_book)'::book, '{1,2,3}'::int[]);
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;