带多行的Postgresql插入选择

带多行的Postgresql插入选择,sql,postgresql,sql-insert,Sql,Postgresql,Sql Insert,我正在创建一个过程来解析输入json数据并存储在表中。该函数如下所示: 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_arr

我正在创建一个过程来解析输入json数据并存储在表中。该函数如下所示:

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包装。
最后一次插入有混合值类型,如果这个人有两辆车,我在t3中插入了4行,因为c.id和json_数组_元素_文本(d::json->‘brands’)都有两个数据集,2x2=4,我如何将插入的值映射到一对一?因此,第一个c.id应该映射到第一个品牌。

要映射它们,您必须在不同的行中加入,而不是在true上

下面是一个示例,说明如何在id
上按顺序将两者连接起来,希望对您有所帮助。基于您的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)
您的表格:

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)
执行:

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)

要映射它们,您必须在不同的行上加入,而不是在true上

下面是一个示例,说明如何在id
上按顺序将两者连接起来,希望对您有所帮助。基于您的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)
您的表格:

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)
执行:

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)

您可以添加一个json示例、实际结果和预期结果吗?当然,t1存储id和name:text,t2有id和cars:text(每辆车都有自己的行),t3基本上链接t1和t2添加品牌信息,t3:id:int,name_id(fk到t1),cars_id(fk到t2)和brand:text。json看起来像{name:john,cars:[“bmw X5 xdrive”,“volvo v90 rdesign”]},brands:[“bmw”,“volvo”]}。expectt3将一个car_id映射到与json数组中相同的单个品牌索引。此函数在t3中插入4行,每辆车以不同的品牌显示两次。您是否添加json示例、实际结果和预期结果?当然,t1存储id和name:text,t2有id和cars:text(每辆车都有自己的行),t3基本上链接t1和t2添加品牌信息,t3:id:int,name_id(fk到t1),cars_id(fk到t2)和brand:text。json看起来像{name:john,cars:[“bmw X5 xdrive”,“volvo v90 rdesign”]},brands:[“bmw”,“volvo”]}。expectt3将一个car_id映射到与json数组中相同的单个品牌索引。这个函数在t3中插入4行,每辆车以不同的品牌出现两次Hanks Vao,它确实会发出一些光,但我尝试将常规添加到t3 insert中,这似乎不起作用。请按照我的代码插入t1和t2,然后使用与数组值对齐的返回ID插入t3,好吗?当然,请在您的帖子中添加表定义,这样我就可以重现您的函数了。非常感谢!这使我感到非常愉快!loog lucksorry,也许我在这里有点慢:)现在需要向t2添加一个新列,car_type:int,它应该从一个新数组d::json->“cart_type”接收值,显然我不能在a()中加入t2两次,我如何使用新数组的索引?JSON看起来像“{”名字“:”约翰“,”汽车“:[”宝马X5 xdrive“,”沃尔沃v90 rdesign“],”品牌“:[”宝马“,”沃尔沃“,”汽车类型“:[1,1]”感谢Vao,它确实发出了一些光芒,但我试图以普通的方式添加到t3插件中,这似乎不起作用。请按照我的代码插入t1和t2,然后使用与数组值对齐的返回ID插入t3,好吗?当然,请在您的帖子中添加表定义,这样我就可以重现您的函数了。非常感谢!这使我感到非常愉快!loog lucksorry,也许我在这里有点慢:)现在需要向t2添加一个新列,car_type:int,它应该从一个新数组d::json->“cart_type”接收值,显然我不能在a()中加入t2两次,我如何使用新数组的索引?JSON看起来像“{”名字“:”约翰“,”汽车“:[”宝马X5 xdrive“,”沃尔沃v90 rdesign“],”品牌“:[”宝马“,”沃尔沃“,”汽车类型“:[1,1]}”