18

まず、pl/pgsql は初めてです。プロジェクトに必要です。

私はこの(単純化された)問題に悩まされています。

私の db スキーマには対 m 関係 (author、books、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;

引数として、タイプ book のレコードとそれを書いた著者を渡すことを考えました。しかし、これはどのように機能しますか?私はかなりグーグルで調べましたが、これを理解できないようです...

質問 1 : 関数の概要は「正しい」か、または理にかなっていますか?

質問 2 : レコードブックをテーブルブックに挿入する方法は? 本のすべてのフィールド (タイトル、ISBN、出版社など) を調べて、それらを INSERT INTO ステートメントに追加する必要がありますか、または「よりスマートな」方法はありますか?

質問 3 : 関数 insert_book をどのように呼び出すのですか? ここでこの例を見つけました (http://dbaspot.com/postgresql/206142-passing-record-function-argument-pl-pgsql.html) が、実際には役に立ちません。テスト目的でシェルを使用していますが、後で Java と JDBC を使用します。

ご助力ありがとうございます。

4

2 に答える 2

17

データ変更 CTE (Postgres 9.1 以降が必要)を使用するunnest()と、これは単純な 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は単純化されたデータ入力用であり、厳密には必要ありません。

SQL フィドル。

あなたの質問について:

質問 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;

質問 2: レコードブックをテーブルブックに挿入する方法は? (...) または「よりスマートな」方法はありますか?

よりスマートな方法は、複合型を で分解すること(variable_name).*です。

は に一致することが保証されているため(tableそこから派生したもの)、これはまれなケースの 1 つであり、永続化されたコードでコマンドの列リストを提供しなくてもまったく問題ありません。INSERT

質問 3: 関数 insert_book をどのように呼び出すのですか? ...

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

他の plpgsql 関数内では、(存在しない) 結果のターゲット ( ) を提供しない場合PERFORMに代わりに使用します。SELECTINTO foo

于 2012-10-03T20:22:11.567 に答える