web-dev-qa-db-ja.com

混合型の配列を保存された関数に渡す

手続きは基本的にお支払い完了です。すべての情報を引数として取り、1つのトランザクションですべての挿入や処理を行います。

ここでの問題は、1つの引数がn個の配列のリスト(基本的には購入されたアイテムのリスト)であるため、FUNCTIONに配列の配列を食べさせる必要があります。

Erwin Brandstetterが質問から提供した解決策 複合型の配列を関数パラメーターとして使用し、それにアクセスする は、基本的に1つのことを除いて必要です。ターゲットテーブルにも列が必要です:id SERIAL PRIMARY KEY

私はそれを少し変更しようとしています:

これはターゲットテーブルです。

CREATE TABLE cashreg_journal (
  id SERIAL PRIMARY KEY,
  gid INTEGER NOT NULL,
  device_id TEXT NOT NULL,
  item TEXT NOT NULL,
  vat_percentage INTEGER NOT NULL,
  vat_sum INTEGER, price NUMERIC);

これは機能です:

CREATE OR REPLACE FUNCTION test_insert(daco TEXT, VARIADIC _journal_arr cashreg_journal[]) RETURNS TEXT
  LANGUAGE plpgsql
  AS $function$

DECLARE

  jr cashreg_journal;

BEGIN

  FOREACH jr IN ARRAY _journal_arr LOOP
    INSERT INTO cashreg_journal(gid, device_id, item, vat_percentage, vat_sum, price)
    SELECT jr.*;

  END LOOP;

  RAISE NOTICE 'Daco: %', daco;

  RETURN 'Saved';

END;
$function$;

しかし、それはこのように機能していません:

SELECT * FROM test_insert('Test daco', '(1,000-111,Test-P,20,20,100)', '(1,000-111,Test-F,10,10,100)');
ERROR:  invalid input syntax for integer: "000-111"
LINE 1: SELECT * FROM test_insert('Test daco', '(1,000-111,Test-P,20...
                                               ^

どうやったらよくわからなくて、マインドが良くないようです。

誰かが私に正しい方向を向くためのヒントを教えてくださいませんか? :)


編集:私は多くのマシンで作業していますが、postgresのバージョンは常に9.4、9.5、または9.6です。また、与えられたソリューションについて私が気に入っているのは、新しいタイプを作成する必要がないことです。私はそれを避けようとします。

2
rRr

私が探していた解決策はこれです:

CREATE OR REPLACE FUNCTION test_insert(daco TEXT, _journal_arr cashreg_journal[]) RETURNS TEXT
  LANGUAGE plpgsql
  AS $function$

DECLARE

  jr cashreg_journal;

BEGIN

  FOREACH jr IN ARRAY _journal_arr LOOP
    INSERT INTO cashreg_journal(gid, device_id, item, vat_percentage, vat_sum, price)
    SELECT jr.gid, jr.device_id, jr.item, jr.vat_percentage, jr.vat_sum, jr.price;

  END LOOP;

  RAISE NOTICE 'Daco: %', daco;

  RETURN 'Saved';

END;
$function$;

列を指定でき、新しいタイプを作成する必要はありません。 VARIADICも削除しました。これは、FUNCTIONに複数の入力がある場合にパラメーターが乱れるためです。

新しい呼び出しと結果は次のとおりです。

test=# SELECT test_insert('Test daco', '{"(1,1,000-111,Test-P,20,20,100)","(1,1,000-111,Test-F,10,10,100)"}'::cashreg_journal[]);
NOTICE:  Daco: Test daco
 test_insert 
-------------
 Saved
(1 row)

test=# 
test=# 
test=# SELECT * FROM cashreg_journal;
 id | gid | device_id |  item  | vat_percentage | vat_sum | price 
----+-----+-----------+--------+----------------+---------+-------
  1 |   1 | 000-111   | Test-P |             20 |      20 |   100
  2 |   1 | 000-111   | Test-F |             10 |      10 |   100
  3 |   1 | 000-111   | Test-P |             20 |      20 |   100
  4 |   1 | 000-111   | Test-F |             10 |      10 |   100
  5 |   1 | 000-111   | Test-P |             20 |      20 |   100
  6 |   1 | 000-111   | Test-F |             10 |      10 |   100
  7 |   1 | 000-111   | Test-P |             20 |      20 |   100
  8 |   1 | 000-111   | Test-F |             10 |      10 |   100
  9 |   1 | 000-111   | Test-P |             20 |      20 |   100
 10 |   1 | 000-111   | Test-F |             10 |      10 |   100
(10 rows)

test=#

トリックは、最初の列IDに値を指定する必要があるということですが、関数は単にそれを無視しています。

このダミー値を指定しない場合、FUNCTIONは例外を発生させます。

test=# SELECT test_insert('Test daco', '{"(1,000-111,Test-P,20,20,100)","(1,000-111,Test-F,10,10,100)"}'::cashreg_journal[]);
ERROR:  invalid input syntax for integer: "000-111"
LINE 1: SELECT test_insert('Test daco', '{"(1,000-111,Test-P,20,20,1...
                                        ^
test=#
1
rRr

あなたが提供したリンクをたどって、 a_horse_with_no_nameErwin Brandstetter の良い答えを注意深く読んでくださいこの質問を解決しようとしました。

複合型の配列を関数パラメーターとして使用してアクセス

まず、複合タイプを作成しました:

_CREATE TYPE cr_journal AS (
  gid INTEGER,
  device_id TEXT,
  item TEXT,
  vat_percentage INTEGER,
  vat_sum INTEGER, 
  price NUMERIC);
_

次に、関数を少し編集しました。

_CREATE OR REPLACE FUNCTION test_insert(daco TEXT, _journal_arr  cr_journal[]) RETURNS TEXT
  LANGUAGE plpgsql
  AS $function$

DECLARE

    cj cr_journal;

BEGIN

    FOREACH cj IN array _journal_arr LOOP

        INSERT INTO cashreg_journal
            (gid, device_id, item, vat_percentage, vat_sum, price)
        SELECT cj.*;

    END LOOP;

  RAISE NOTICE 'Daco: %', daco;

  RETURN 'Saved';

END;
$function$;
_

そして最後のステップでは、SELECT * FROM function()の代わりに選択したセンテンスを変更し、SELECT function()として呼び出して、配列を_cr_journal[]_型の配列として明示的にキャストする必要がありますこの方法では:

_SELECT test_insert('Test daco', 
                   (ARRAY[(1, '000-111', 'Test-P', 20, 20, 100), 
                          (1, '000-111', 'Test-F', 20, 10, 100)])::cr_journal[]);

returns: Saved
_

これで確認できます:

_select * from cashreg_journal;
_

そしてこれが結果です:

 id | gid | device_id |アイテム| vat_percentage | vat_sum |価格
-:| -:| :----- :----- | -------------:| ------:| ----:
 1 | 1 | 000-111 | Test-P | 20 | 20 | 100 
 2 | 1 | 000-111 |テスト-F | 20 | 10 | 100 

db <> fiddle ---(ここ

1
McNets

unnest()を使用したよりシンプルで高速なセットベースのバリアントも 参照されている回答で示されています は、serial列を省略して、同様にユースケースに適合させることができます。 INSERT内。コアコマンド:

INSERT INTO cashreg_journal
        (gid,   device_id,   item,   vat_percentage,   vat_sum,   price)
SELECT j.gid, j.device_id, j.item, j.vat_percentage, j.vat_sum, j.price
FROM   unnest(_journal_arr) j;

また、回答のステートメントについて:

VARIADICも削除しました。これは、FUNCTIONに複数の入力がある場合にパラメーターが乱れるためです。

それはおそらく誤解です。次の日からのこの関連する回答は役立つかもしれません:

0