2017-06-01 8 views
1

Ich erstelle eine Prozedur zum Parsen von Eingabe JSON-Daten und in Tabellen gespeichert. Die Funktion sieht so aus:Postgresql Einfügen auswählen mit mehreren Zeilen

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 
) 

die Dateneingabe Name als Text, Autos hat und Marken sind Array, die alle in einem json gewickelt. So hat der letzte Einsatz gemischte Werttypen, wenn die Person zwei Autos hat, habe ich 4 Reihen in t3 eingefügt, weil c.id und json_array_elements_text (d :: json -> 'Marken') beide zwei Datensätze haben, 2x2 = 4 , wie kann ich den eingefügten Wert eins zu eins zuordnen? Daher sollte der 1. c.id der ersten Marke zugeordnet werden.

+0

Können Sie ein Beispiel Ihrer json, tatsächliches Ergebnis und erwartetes Ergebnis hinzufügen? und möglicherweise Beschreibung Ihrer Tabellen. – cachique

+0

Sicher, t1 speichert ID und Name: Text, t2 hat ID und Autos: Text (jedes Auto hat seine eigene Zeile), T3 im Grunde verknüpfen t1 und t2 hinzufügen Markeninfo, t3: id: int, name_id (fk zu t1), cars_id (fk bis t2) und Marke: Text. Der JSON sieht aus wie {Name: John, Autos: ["BMW X5 XDrive", "Volvo V90 Rdesign"]}, Marken: ["BMW", "Volvo"]}. Erwarte t3 maps eine car_id zu einem einzigen Marken gleichen Index wie in json Array. diese Funktion fügt 4 Reihen in t3 ein, jedes Auto erscheint zweimal mit verschiedenen Marken – Wizer

Antwort

0

Um sie zuzuordnen, müssen Sie nicht auf true, sondern in einer bestimmten Zeile verbinden.

Hier ist ein Beispiel, wie beide auf ID with ordinality beitreten - hoffe, es wird Ihnen helfen. basierend auf json Probe

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) 

Update für OP Ausarbeitung:

Sie Mapping mehrere Zeilen vermeiden können, indem em aggregiert und dann Index mit:

Ihre 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; 

Ihre Tabellen:

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); 

Ausführung:

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

Dank Vao, es scheint etwas Licht, aber ich versuchte, mit Ordinalität zu t3 einzufügen, die scheint nicht zu arbeiten. Können Sie bitte meinen Code folgen, um in t1 und t2 einzufügen, dann verwenden Sie zurückgebende IDs, die mit Array-Werten ausgerichtet sind, um sie in t3 einzufügen? – Wizer

+0

sicher, bitte fügen Sie Tabellen Definitionen zu Ihrem Beitrag, damit ich Ihre Funktion reproduzieren konnte –

+0

Vielen Dank Vao! Es macht total Sinn – Wizer

Verwandte Themen