Множественные вставки с использованием одного cte postgres - PullRequest
0 голосов
/ 05 августа 2020

Я новичок в postgres. во время работы над фиктивным проектом я столкнулся с этой проблемой.

У меня есть две таблицы, скажем, t1 и t2. t1 имеет отношение 1-> Many с t2.

Я пытаюсь написать оператор SQL, который сначала вставляет данные в t1 и с использованием id из t1 вставляет несколько строк в t2.

Что-то вроде этого.

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 -> (t1_id primary_key serial , целое число t1_col).

структура t2 -> (t2_id primary_key serial, t1_id integer, t2_col integer).

Как правильно это сделать.

Спасибо заранее.

Ответы [ 4 ]

0 голосов
/ 05 августа 2020

Нет необходимости в CTE или переменных, вы можете использовать lastval(), чтобы получить последнее сгенерированное значение идентификатора (или последовательности):

INSERT INTO t1(t1_col) 
VALUES (4);

INSERT INTO t2(t1_id, t2_col) 
VALUES 
(lastval(), 3), 
(lastval(), 4),
...
0 голосов
/ 05 августа 2020

за исключением вставки с предложением VALUES, вы можете вставить результат SELECT. в общем виде это будет:

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;

вариант для нескольких строк (фиксированный список)

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;

где 3,4 .... - список значений

0 голосов
/ 05 августа 2020

Это будет сделано в одном операторе.

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

Если вы запускаете это с основного языка и можете передавать значения t2 в виде массива, прокомментируйте, потому что это можно упростить.

Я бы построил что-то вроде этого для использования с основным языком:

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;

Затем с хоста я бы передал t1_col и массив значений t2_col как параметры запроса.

0 голосов
/ 05 августа 2020

Подойдет анонимный блок plpg sql.

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;
$$;
...