sql >> Base de Datos >  >> RDS >> PostgreSQL

Función INSERT masiva de Postgres usando argumentos JSON

Para miles de registros

1. Cree una tabla temporal de filas de entrada, compuesta por sus valores $1 , $2 , $3 . La forma más rápida de cargar es COPY - o el \copy metacomando de psql si los datos no están en la misma máquina. Supongamos esta tabla:

CREATE TEMP TABLE tmp(id int PRIMARY KEY, val1 text, val2 text);

Agregué una restricción PK, que es totalmente opcional, pero se asegura de que estemos tratando con valores int únicos no nulos. Si puede garantizar los datos de entrada, no necesita la restricción.

2. Encadene sus comandos con CTE de modificación de datos. Como hemos determinado en su pregunta anterior , no hay condiciones de carrera que atender en esta operación en particular.

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;

Los pasos 1 y 2 deben ejecutarse en la misma sesión (no necesariamente la misma transacción), ya que el alcance de las tablas temporales está vinculado a la misma sesión.

Tenga en cuenta que UPDATE solo depende del 1er INSERT , éxito del 2º INSERT está garantizado, ya que no hay ON CONFLICT DO NOTHING y toda la operación se revertirá si hay algún conflicto en el 2.º INSERT .

Relacionado:

Por solo un par de discos

Hay varias opciones de cómo. Su idea de pasar una matriz JSON a una función es una de ellas. Si los objetos coinciden con la tabla de destino, puede usar json_populate_recordset() en un solo INSERT consulta. O simplemente use el INSERT (como declaración preparada) sin contenedor de función.

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" }]');

Para solo un puñado de columnas, también puede pasar una matriz para cada columna y recorrerlas en paralelo. Puede hacer esto con un bucle simple en el índice de la matriz. Desde Postgres 9.4 también existe el conveniente unnest() con múltiples parámetros para hacerlo todo en una sola consulta:

La mejor solución depende del formato de datos que tenga .