简体   繁体   中英

Multiple inserts using one cte postgres

I am beginner in postgres. while working on a dummy project I came across this problem.

I have two tables let say t1 and t2.The t1 having 1->Many relation with t2.

I am trying to write an SQL statement which first inserts data in t1 and using id from t1 inserts the multiple rows in t2.

Something like this.

WITH ins AS (
    INSERT INTO t1(t1_col) 
    VALUES (4)
    RETURNING t1_id
)
INSERT INTO t2(t1_id, t2_col) VALUES (ins.t1_id, 3), (ins.t1_id, 4)...

t1 structure -> (t1_id primary_key serial, t1_col integer).

t2 structure -> (t2_id primary_key serial, t1_id integer, t2_col integer).

What is the correct way to do this.

Thank you in advance.

except for inserting with VALUES clause you can insert the result of SELECT . in general form it will be:

WITH ins AS (
  INSERT INTO table1(target columns)
  VALUES (some values) -- or -- SELECT something FROM somewhere
  RETURNING some_id
)
INSERT INTO table2(target columns)
SELECT ins.some_id, other columns or expressions
FROM ins;

variant for multiple rows (fixed list)

WITH ins AS (
  INSERT INTO table1(target columns)
  VALUES (some values) -- or -- SELECT something FROM somewhere
  RETURNING some_id
)
INSERT INTO table2(target columns)
SELECT ins.some_id, UNNEST(ARRAY[3,4,...])
FROM ins;

where 3,4.... is the list of values

An anonymous plpgsql block will do.

do language plpgsql
$$
declare
  t1id t1.t1_id%type;
begin 
  INSERT INTO t1(t1_col) VALUES (4) RETURNING t1_id INTO t1id;
  INSERT INTO t2(t1_id, t2_col) 
  VALUES (t1id, 3), (t1id, 4)...;
end;
$$;

This will do it in a single statement.

WITH ins AS (
    INSERT INTO t1(t1_col) 
    VALUES (4)
    RETURNING t1_id
)
INSERT INTO t2(t1_id, t2_col) 
SELECT ins.t1_id, v.t2_col
  from ins
 cross join (VALUES (3), (4)) as v(t2_col)
;

If you are running this from a host language and can pass the t2 values as an array, please comment because this can be simplified.

I would build it something like this for use with a host language:

with invars as (
  select $1 as t1_col, $2::text[] as t2_cols
), ins as (
  insert into t1 (t1_col)
  select t1_col 
    from invars
  returning t1_id 
)
insert into t2 (t1_id, t2_col)
select ins.t1_id, unnest(invars.t2_cols) as t2_col
  from ins
 cross join invars;

Then, from the host, I would pass t1_col and an array of t2_col values as parameters to the query.

No need for a CTE or variables, you can uselastval() to get the last generated identity (or sequence) value:

INSERT INTO t1(t1_col) 
VALUES (4);

INSERT INTO t2(t1_id, t2_col) 
VALUES 
(lastval(), 3), 
(lastval(), 4),
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM