Postgresql

將混合類型的數組傳遞給儲存的 FUNCTION

  • December 17, 2018

我正在準備程序,基本上是完成付款。它將所有資訊作為參數,並在一個事務中執行所有插入和內容。

這裡的問題是,一個參數是 n 個數組的列表(基本上是購買的項目列表),所以我必須讓我的 FUNCTION 吃數組數組。

Erwin Brandstetter 從問題使用複合類型數組作為函式參數並訪問它基本上是我需要的解決方案,除了一件事。我的目標表還必須有列: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。我也忘了提到我喜歡給定解決方案的是,我不需要創建新類型。我盡量避免。

我正在尋找的解決方案是這樣的:

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 只是忽略它。

如果我不提供這個虛擬值,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=#

按照您提供的連結並仔細閱讀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;

這是結果:

編號 | 吉德 | device_id | 項目 | 增值稅百分比 | 增值稅 | 價格
-: | --: | :-------- | :----- | -------------: | ------: | ----:
1 | 1 | 000-111 | 測試-P | 20 | 20 | 100
2 | 1 | 000-111 | 測試-F | 20 | 10 | 100

db<>在這裡擺弄

引用自:https://dba.stackexchange.com/questions/224785