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

¿Cómo actualizar las filas seleccionadas con valores de un archivo CSV en Postgres?

COPY el archivo a una tabla provisional temporal y actualice la tabla real desde allí. Me gusta:

CREATE TEMP TABLE tmp_x (id int, apple text, banana text); -- but see below

COPY tmp_x FROM '/absolute/path/to/file' (FORMAT csv);

UPDATE tbl
SET    banana = tmp_x.banana
FROM   tmp_x
WHERE  tbl.id = tmp_x.id;

DROP TABLE tmp_x; -- else it is dropped at end of session automatically

Si la tabla importada coincide exactamente con la tabla que se actualizará, esto puede ser conveniente:

CREATE TEMP TABLE tmp_x AS SELECT * FROM tbl LIMIT 0;

Crea una tabla temporal vacía que coincide con la estructura de la tabla existente, sin restricciones.

Privilegios

Hasta Postgres 10, SQL COPY requiere privilegios de superusuario para esto.
En Postgres 11 o posterior, también hay algunos roles predefinidos (anteriormente "roles predeterminados") para permitirlo. El manual:

COPY Solo se permite nombrar un archivo o comando a los superusuarios de la base de datos o a los usuarios que tienen uno de los roles pg_read_server_files ,pg_write_server_files o pg_execute_server_program [...]

El psql metacomando \copy funciona para cualquier rol de base de datos. El manual:

Realiza una copia de frontend (cliente). Esta es una operación que ejecuta un SQL COPY comando, pero en lugar de que el servidor lea o escriba el archivo especificado, psql lee o escribe el archivo y enruta los datos entre el servidor y el sistema de archivos local. Esto significa que la accesibilidad a los archivos y los privilegios son del usuario local, no del servidor, y no se requieren privilegios de superusuario de SQL.

El alcance de las tablas temporales está limitado a una sola sesión de un solo rol, por lo que lo anterior debe ejecutarse en la misma sesión de psql:

CREATE TEMP TABLE ...;
\copy tmp_x FROM '/absolute/path/to/file' (FORMAT csv);
UPDATE ...;

Si está escribiendo esto en un comando bash, asegúrese de envolverlo todo en un único llamada psql. Me gusta:

echo 'CREATE TEMP TABLE tmp_x ...; \copy tmp_x FROM ...; UPDATE ...;' | psql

Normalmente, necesita el meta-comando \\ para cambiar entre los metacomandos psql y los comandos SQL en psql, pero \copy es una excepción a esta regla. El manual de nuevo:

se aplican reglas de análisis especiales a \copy metacomando. A diferencia de la mayoría de los otros meta-comandos, el resto completo de la línea siempre se toma como los argumentos de \copy , y ni la interpolación de variables ni la expansión de comillas inversas se realizan en los argumentos.

Mesas grandes

Si la tabla de importación es grande, puede valer la pena aumentar temp_buffers temporalmente para la sesión (lo primero en la sesión):

SET temp_buffers = '500MB';  -- example value

Agregue un índice a la tabla temporal:

CREATE INDEX tmp_x_id_idx ON tmp_x(id);

Y ejecuta ANALYZE manualmente, ya que las tablas temporales no están cubiertas por autovacuum/auto-analyze.

ANALYZE tmp_x;

Respuestas relacionadas:

  • La mejor manera de eliminar millones de filas por ID
  • ¿Cómo puedo insertar datos comunes en una tabla temporal de esquemas dispares?
  • ¿Cómo eliminar entradas duplicadas?