2017-06-01 187 views
1

我正在創建一個過程來解析輸入json數據並存儲在表中。該功能看起來像:Postgresql插入選擇多行

create or replace function test_func(d json) 
returns void as $$ 
    begin 
    with n as (
    insert into t1 (name) values (d::json -> 'name') returning id 
    ), c as (
    insert into t2 (cars) values json_array_elements_text(d::json -> 'cars') returning id 
    ) 
    insert into t3 (id, name_id, cars_id, brand) 
    select 1, n.id, c.id, json_array_elements_text(d::json -> 'brands') from n, c; 
end; 
$$ language plpgsql; 


CREATE TABLE t1 
(
    "id" SERIAL PRIMARY KEY, 
    "name" text NOT NULL 
) 

CREATE TABLE t2 
(
    "id" SERIAL PRIMARY KEY, 
    "cars" text NOT NULL, 
    "car_type" int 
) 

CREATE TABLE t3 
(
    "id" int, 
    "name_id" int REFERENCES t1(id), 
    "cars_id" int REFERENCES t2(id), 
    "brand" text 
) 

數據輸入名稱爲文本,汽車和品牌是數組,都包裹在一個JSON中。 所以最後一個插入有混合值類型,如果人有兩輛車,我有4行插入t3因爲c.id和json_array_elements_text(d :: json - >'品牌')都有兩個數據集,2x2 = 4 ,如何將插入的值映射到一個?所以第一個c.id應該映射到第一個品牌。

+0

你可以添加你的JSON的一個例子,實際結果和預期的結果?並可能描述你的表格。 – cachique

+0

當然,t1存儲id和name:text,t2有id和cars:text(每輛車都有自己的行),t3基本上鍊接t1和t2,添加品牌信息,t3:id:int,name_id(fk到t1), cars_id(fk到t2)和品牌:文本。 json看起來像{姓名:john,汽車:[「bmw X5 xdrive」,「volvo v90 rdesign」]},品牌:[「bmw」,「volvo」]}。預計t3將一個car_id映射到與json數組中相同索引的單品牌。這個功能在t3中插入4行,每輛車出現兩次不同品牌 – Wizer

回答

0

要映射它們,你必須加入不是真實的,但在不同的行。

這裏是示例如何加入兩個ID with ordinality - 希望它會有所幫助。根據您的JSON樣本

t=# with j as (select '{"name":"john", "cars":["bmw X5 xdrive","volvo v90 rdesign"], "brands":["bmw","volvo"]}'::json d) 
select car,brand,t1.id from j 
join json_array_elements_text(j.d->'cars') with ordinality t1(car,id) on true 
join json_array_elements_text(j.d->'brands') with ordinality t2(brand,id) on t1.id = t2.id 
; 
     car  | brand | id 
-------------------+-------+---- 
bmw X5 xdrive  | bmw | 1 
volvo v90 rdesign | volvo | 2 
(2 rows) 

更新闡述了OP:

可以避開映射多行,通過聚合EM,然後利用指數:

您的FN:

create or replace function test_func(d json) 
returns void as $$ 
    begin 
with j as (select d) 
, a as (
    select car,brand,t1.id oid 
    from j 
    join json_array_elements_text(j.d->'cars') with ordinality t1(car,id) on true 
    join json_array_elements_text(j.d->'brands') with ordinality t2(brand,id) on t1.id = t2.id 
) 
, n as (
    insert into t1 (name) values (d::json -> 'name') returning id 
), c as (
    insert into t2 (cars) select car from a order by oid returning id 
) 
, ag as (
    select array_agg(c.id) cid from c 
) 
insert into t3 (id, name_id, cars_id, brand) 
    select 1, n.id,cid[oid], brand 
    from a 
    join n on true 
    join ag on true 
; 
end; 
$$ language plpgsql; 

您的表格:

CREATE TABLE t1 ("id" SERIAL PRIMARY KEY, "name" text NOT NULL); 
CREATE TABLE t2 ("id" SERIAL PRIMARY KEY, "cars" text NOT NULL); 
CREATE TABLE t3 ("id" int, "name_id" int REFERENCES t1(id), "cars_id" int REFERENCES t2(id), "brand" text); 

執行:

t=# select test_func('{"name":"john", "cars":["bmw X5 xdrive","volvo v90 rdesign"], "brands":["bmw","volvo"]}'); 
test_func 
----------- 

(1 row) 

t=# select * from t1; 
id | name 
----+-------- 
14 | "john" 
(1 row) 

t=# select * from t2; 
id |  cars 
----+------------------- 
27 | bmw X5 xdrive 
28 | volvo v90 rdesign 
(2 rows) 

t=# select * from t3; 
id | name_id | cars_id | brand 
----+---------+---------+------- 
    1 |  14 |  27 | bmw 
    1 |  14 |  28 | volvo 
(2 rows) 
+0

感謝Vao,它確實發出了一些亮光,但我試圖添加與t3插入的順序,這似乎沒有工作。你可以請按照我的代碼插入到t1和t2然後使用返回ids對齊數組值插入到t3? – Wizer

+0

當然,請將表格定義添加到您的文章中,以便我可以重現您的功能 –

+0

非常感謝Vao!它讓我感到愉快總感 – Wizer