Passing A Record As Function Argument Pl/pgsql
Solution 1:
Using unnest() and a data-modifying CTE (requires Postgres 9.1 or later), this can be a simple SQL query:
WITH x AS (SELECT'(1,foo_book)'::book AS _book
, '{1,2,3}'::int[] AS _authors)
, y AS (
INSERTINTO book -- no column list, correct due to composite typeSELECT (x._book).*FROM x
RETURNING book_id
)
INSERTINTO 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 yThe first CTE x is just for simplified data input and not strictly needed.
SQL Fiddle.
As to your questions:
Question 1: Is the function outline "correct"/does it make sense?
Might be easier to pass base types instead of the composite type book, but it is a perfectly valid approach. You have to know your way around the syntax for complex types, though. For instance, note the parenthesis around the name in my example: (x._book).*.
A plpgsql function could look like this:
CREATEOR REPLACE FUNCTION f_insert_book(_book book, _authors integer[])
RETURNS void AS
$func$
BEGINWITH y AS (
INSERTINTO book b
SELECT (_book).*
RETURNING b.book_id
)
INSERTINTO 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?
The smarter way is to decompose the composite type with (variable_name).*.
As the type is guaranteed to match the table (being derived from it), this is one of the rare cases, where it is perfectly ok, not to provide a column list for the INSERT command in persisted code.
Question 3: How would I call my function insert_book? ...
SELECT f_insert_book('(1,foo_book)'::book, '{1,2,3}'::int[]);
Within other plpgsql functions, use PERFORM instead of SELECT if you don't provide a target (INTO foo) for the (non-existing) results.
Solution 2:
Passing JSON datatype (Postgresql 9.2 or higher):
CREATEOR REPLACE FUNCTION f_insert_book(_book json, _authors json)
RETURNS void AS
$$
BEGIN-- insert book into table booksInsertinto books valuesselect*from json_populate_recordset(null:book, _book);
-- for each author add an entry to author_books tableInsertinto authors valuesselect*from json_populate_recordset(null:authors, _authors);
end;
$$ language plpgsql;
Post a Comment for "Passing A Record As Function Argument Pl/pgsql"