Passing a record as function argument PL/pgSQL

后端 未结 2 1750
遥遥无期
遥遥无期 2020-12-09 04:40

First I am really new to pl/pgsql. Need it for a project.

I am stuck with this (simplified) problem.

My db schema has a n to m relationship (author, books, a

相关标签:
2条回答
  • 2020-12-09 04:50

    Passing JSON datatype (Postgresql 9.2 or higher):

    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;
    
    0 讨论(0)
  • 2020-12-09 05:00

    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 (
       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
    

    The 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:

    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?

    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.

    0 讨论(0)
提交回复
热议问题