За хиляди записи
1. Създайте временна таблица с входни редове, съставена от вашите стойности $1
, $2
, $3
. Най-бързият начин за качване е COPY
- или \copy
мета-команда на psql
ако данните не са на същата машина. Да предположим, че тази таблица:
CREATE TEMP TABLE tmp(id int PRIMARY KEY, val1 text, val2 text);
Добавих PK ограничение, което е напълно незадължително, но гарантира, че имаме работа с уникални ненулеви int стойности. Ако можете да гарантирате за входни данни, нямате нужда от ограничението.
2. Свържете вашите команди с модифициращи данни CTE. Както установихме във вашия предишен въпрос , няма условия за състезание, за които да се грижим в тази конкретна операция.
WITH ins1 AS (
INSERT INTO table1 AS t1 (id, val1, val2)
SELECT id, val1, val2 FROM tmp ON CONFLICT DO NOTHING
RETURNING t1.id, t1.val1, t1.val2 -- only actually inserted rows returned
)
, ins2 AS (
INSERT INTO table2 (table1_id, val1)
SELECT id, val1 FROM ins1
)
UPDATE table3 t3
SET val2 = i.val2
, time = now()
FROM ins1 i
WHERE t3.table1_id = i.id;
Стъпка 1. и 2. трябва да се изпълняват в същата сесия (не непременно същата транзакция), тъй като обхватът на временните таблици е обвързан с една и съща сесия.
Обърнете внимание, че UPDATE
зависи само от първия INSERT
, успех на втория INSERT
е гарантирано, тъй като няма ON CONFLICT DO NOTHING
и цялата операция ще бъде върната назад, ако има някакъв конфликт във 2-рия INSERT
.
Свързани:
Само за няколко записа
Има различни варианти как. Вашата идея да предадете JSON масив към функция е една от тях. Ако обектите съответстват на целевата таблица, можете да използвате json_populate_recordset()
в един INSERT
заявка. Или просто използвайте INSERT
(като подготвен израз) без обвивка на функция.
INSERT INTO target_tbl -- it's ok to omit target columns here
SELECT *
FROM json_populate_recordset(null::target_tbl, -- use same table type
json '[{ "id": "1", "val1": "1-val1", "val2": "1-val2" },
{ "id": "2", "val1": "2-val1", "val2": "2-val2" },
{ "id": "3", "val1": "3-val1", "val2": "3-val2" },
{ "id": "4", "val1": "4-val1", "val2": "4-val2" }]');
Само за няколко колони можете също да подадете масив за всяка колона и да преминете през тях паралелно. Можете да направите това с обикновен цикъл върху индекса на масива. От Postgres 9.4 има и удобния unnest()
с множество параметри, за да направите всичко в една заявка:
Най-доброто решение зависи от формата на данните, който имате .