Postgresに2つのBooks
フィールドと2つのnumeric
フィールドを持つタイプvarchar
を作成しました。 Books
の配列を関数に送信して、一致するテーブルのそれらの値をINSERT
に送信します。
これは私のタイプです:
CREATE TYPE Books AS (
V_Book_ID NUMERIC,
V_Row_Num NUMERIC,
V_Book_OWNER TEXT,
V_Book_OWNER_ID TEXT
);
これは私の機能です:
CREATE OR REPLACE FUNCTION Update_Table(row_book Books[]) RETURNS TEXT AS $$
DECLARE
Status TEXT;
I_Max integer := array_length(row_book, 1);
BEGIN
FOR I in 1..I_Max
LOOP
INSERT INTO books_table(Book_ID,
Row_Num,
Book_OWNER,
Book_OWNER_ID)
values
(row_book[I].V_Book_ID,
row_book[I].V_Row_Num,
row_book[I].V_Book_OWNER,
row_book[I].V_Book_OWNER_ID);
END LOOP;
STATUS:='Saved';
exception when others then
STATUS:='failure';
RETURN STATUS;
END;
$$ language plpgsql;
関数にデータを送信するにはどうすればよいですか、またはデータで関数を呼び出すにはどうすればよいですか?
私はSO少し前に基本的に同じ質問に答えました:
@a_horseと同じように、unnest()
を使用して同じソリューションを提案します。
仮定して books_table
は複合タイプbooks
と同じ行タイプです。追加のタイプを作成する必要はまったくありません。テーブルの行タイプを使用するだけです。
CREATE TABLE books_table (
book_id numeric
, row_num numeric
, book_owner text
, book_owner_id text
);
宣言されていない理由でplpgsql関数が必要な場合、これを検討してください。
CREATE OR REPLACE FUNCTION update_table_variadic(VARIADIC _books_arr books_table[])
RETURNS TEXT AS
$func$
DECLARE
b books_table;
BEGIN
FOREACH b IN ARRAY _books_arr
LOOP
INSERT INTO books_table -- rare case where column list is not necessary
SELECT b.*;
END LOOP;
RETURN 'Saved';
EXCEPTION WHEN others THEN
RETURN 'Failure';
END
$func$ LANGUAGE plpgsql;
呼び出し(行の値のリストを使用して!):
SELECT update_table_variadic('(2,100,Arthur,1)', '(2,50,Zaphod,1)');
VARIADIC
を使用しない場合、関数呼び出しには全体として単一の配列が必要になります。 配列リテラル(オプションで明示的にキャスト):
SELECT update_table('{"(1,100,Arthur,1)","(1,50,Zaphod,1)"}'::books_table[]);
または、配列コンストラクターを @ a_horseの例 のように使用できます。多くの場合、配列リテラルの方が簡単です。
主なポイント:
より単純なFOREACH
を使用して配列をループします。
何をしているのかわからない場合は、PostgresでCaMeLケース名を使用しないでください。
(オプションで)VARIADIC
パラメーターを使用して、関数呼び出しの構文を簡略化します。このようにして、行の値のlistを提供できます。 VARIADIC
を使用する場合は、関数パラメーターの最大数(デフォルトは100)に注意してください。
例外をキャッチする必要がなく、文字列 'Saved'/'Failure'を返す必要がない場合は、単純化します。
CREATE OR REPLACE FUNCTION update_table_set(VARIADIC _books_arr books_table[])
RETURNS void AS
$func$
INSERT INTO books_table
SELECT * FROM unnest(_books_arr) b;
$func$ LANGUAGE sql;
タイプの配列を作成するには、明示的な配列コンストラクターを使用します。
array[(1,100,'Arthur',1), (1,50,'Zaphod',1)]::books[]
したがって、関数を呼び出すには、以下を使用する必要があります。
select update_table(array[(1,100,'Arthur',1), (1,50,'Zaphod',1)]::books[])
ただし、関数にはエラーがあります。ループの後、returnステートメントがありません。例外ブロックのステートメントはonly実行されているためですif例外が発生します。
したがって、次のようなものが必要です。
begin
....
STATUS:='Saved';
return status; ---<<< this is missing
exception when others then
STATUS:='failure';
RETURN STATUS; --<<< this is only execute if an exception occurs
END;
または、別のbegin .. end;
ブロックが必要です。
begin
begin
for ...
end loop;
STATUS:='Saved';
exception when others then
STATUS:='failure';
end;
RETURN STATUS;
END;
無関係ですが、配列を反復するループは必要ありません。これは、1つのステートメントを使用してより効率的に行うことができます。
INSERT INTO books_table
(Book_ID, Row_Num, Book_OWNER, Book_OWNER_ID)
select *
from unnest(row_book);