Pro tisíce záznamů
1. Vytvořte dočasnou tabulku vstupních řádků složených z vašich hodnot $1
, $2
, $3
. Nejrychlejší způsob nahrání je COPY
- nebo \copy
meta-příkaz psql
pokud data nejsou na stejném stroji. Předpokládejme, že tato tabulka:
CREATE TEMP TABLE tmp(id int PRIMARY KEY, val1 text, val2 text);
Přidal jsem omezení PK, které je zcela volitelné, ale zajišťuje, že máme co do činění s jedinečnými hodnotami int, které nejsou null. Pokud můžete ručit za vstupní data, nepotřebujete omezení.
2. Řetězte své příkazy pomocí CTE upravujících data. Jak jsme zjistili podle vaší předchozí otázky , v této konkrétní operaci nejsou žádné závodní podmínky.
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;
Kroky 1. a 2. musí probíhat ve stejné relaci (ne nutně stejná transakce), protože rozsah dočasných tabulek je vázán na stejnou relaci.
Poznámka:UPDATE
závisí pouze na 1. INSERT
, úspěch 2. INSERT
je zaručena, protože neexistuje ON CONFLICT DO NOTHING
a celá operace bude vrácena zpět, pokud dojde ke konfliktu ve 2. INSERT
.
Související:
Jen pro pár záznamů
Jsou různé možnosti jak. Váš nápad předat funkci JSON pole je jedním z nich. Pokud objekty odpovídají cílové tabulce, můžete použít json_populate_recordset()
v jediném INSERT
dotaz. Nebo stačí použít INSERT
(jako připravený příkaz) bez obálky funkcí.
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" }]');
Pro hrstku sloupců můžete také předat pole pro každý sloupec a procházet je paralelně. Můžete to udělat pomocí jednoduché smyčky na indexu pole. Od Postgresu 9.4 existuje také pohodlné unnest()
s více parametry, abyste to všechno udělali v jediném dotazu:
Nejlepší řešení závisí na formátu dat, který máte .