Вы действительно можете сделать это с помощью цепочки вывода различных функций JSON:
with input (parameter) as (
values ('{"questA": [["a1", "a2"], ["a3", "a4"]], "questB": [["b1", "b2"], ["b2", "b4"]]}'::jsonb)
), elements as (
select j.quest, k.answer
from input i
cross join lateral jsonb_each(i.parameter) as j(quest,vals)
cross join lateral jsonb_array_elements(j.vals) as k(answer)
), new_quests as (
insert into quest ("key")
select distinct quest
from elements
returning *
)
insert into quest_values (val1, val2, quest_id)
select e.answer ->> 0 as val1,
e.answer ->> 1 as val2,
nq.id as quest_id
from new_quests nq
join elements e on e.quest = nq.key;
Первый шаг («элементы») превращает значение JSON в строки, которые можно использовать в качестве источника операторов INSERT. ,Он возвращает это:
quest | answer
-------+-------------
questA | ["a1", "a2"]
questA | ["a3", "a4"]
questB | ["b1", "b2"]
questB | ["b2", "b4"]
Следующий шаг вставляет уникальные значения столбца quest
в таблицу quest
и возвращает сгенерированные идентификаторы.
И последний оператор объединяет сгенерированные идентификаторы со строками первого шага и извлекает два элемента массива как два значения. Он использует этот запрос в качестве источника для вставки в таблицу quest_values
.
Внутри процедуры вам явно не нужна часть, генерирующая данные примера, поэтому она будет выглядеть примерно так:
with elements as (
select j.quest, k.answer
from jsonb_each(the_parameter) as j(quest,vals)
cross join lateral jsonb_array_elements(j.vals) as k(answer)
), new_quests as (
insert into quest ("key")
select distinct quest
from elements
returning *
)
insert into quest_values (val1, val2, quest_id)
select e.answer ->> 0 as val1,
e.answer ->> 1 as val2,
nq.id as quest_id
from new_quests nq
join elements e on e.quest = nq.key;
Где the_parameter
- параметр JSONB, переданный вашей процедуре.
Онлайн пример: https://rextester.com/NBJIK44025