Dla tysięcy rekordów
1. Utwórz tymczasową tabelę wierszy wejściowych, składającą się z wartości $1
, $2
, $3
. Najszybszym sposobem przesyłania jest COPY
- lub \copy
meta-polecenie psql
jeśli dane nie znajdują się na tej samej maszynie. Załóżmy, że ta tabela:
CREATE TEMP TABLE tmp(id int PRIMARY KEY, val1 text, val2 text);
Dodałem ograniczenie PK, które jest całkowicie opcjonalne, ale zapewnia, że mamy do czynienia z unikalnymi wartościami int o wartości niezerowej. Jeśli możesz ręczyć za dane wejściowe, nie potrzebujesz ograniczenia.
2. Połącz swoje polecenia z CTE modyfikującymi dane. Jak ustaliliśmy na podstawie Twojego poprzedniego pytania , w tej konkretnej operacji nie ma warunków wyścigu.
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;
Kroki 1. i 2. muszą być uruchomione w tej samej sesji (niekoniecznie ta sama transakcja), ponieważ zakres tabel tymczasowych jest powiązany z tą samą sesją.
Uwaga, UPDATE
zależy tylko od pierwszego INSERT
, sukces drugiego INSERT
jest gwarantowane, ponieważ nie ma ON CONFLICT DO NOTHING
a cała operacja zostanie wycofana, jeśli wystąpi jakikolwiek konflikt w drugim INSERT
.
Powiązane:
Tylko kilka rekordów
Istnieją różne opcje. Twój pomysł na przekazanie tablicy JSON do funkcji jest jednym z nich. Jeśli obiekty pasują do tabeli docelowej, możesz użyć json_populate_recordset()
w jednym INSERT
zapytanie. Lub po prostu użyj INSERT
(jako przygotowana instrukcja) bez opakowania funkcji.
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" }]');
W przypadku zaledwie kilku kolumn możesz również przekazać tablicę dla każdej kolumny i przejść przez nie równolegle. Możesz to zrobić za pomocą prostej pętli na indeksie tablicy. Od Postgresa 9.4 dostępna jest również wygodna funkcja unnest()
z wieloma parametrami, aby zrobić to wszystko w jednym zapytaniu:
Najlepsze rozwiązanie zależy od formatu danych, który posiadasz .