PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment mettre à jour les lignes sélectionnées avec les valeurs d'un fichier CSV dans Postgres ?

COPY le fichier dans une table intermédiaire temporaire et mettre à jour la table réelle à partir de là. Comme :

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 table importée correspond exactement à la table à mettre à jour, cela peut être pratique :

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

Crée une table temporaire vide correspondant à la structure de la table existante, sans contraintes.

Privilèges

Jusqu'à Postgres 10, SQL COPY nécessite des privilèges de superutilisateur pour cela.
Dans Postgres 11 ou version ultérieure, il existe également des rôles prédéfinis (anciennement "rôles par défaut") pour l'autoriser. Le manuel :

COPY nommer un fichier ou une commande n'est autorisé qu'aux super-utilisateurs de la base de données ou aux utilisateurs qui ont l'un des rôles pg_read_server_files ,pg_write_server_files , ou pg_execute_server_program [...]

Le psql méta-commande \copy fonctionne pour n'importe quel rôle db. Le manuel :

Effectue une copie frontale (client). Il s'agit d'une opération qui exécute un SQL COPY , mais au lieu que le serveur lise ou écrive le fichier spécifié, psql lit ou écrit le fichier et achemine les données entre le serveur et le système de fichiers local. Cela signifie que l'accès aux fichiers et les privilèges sont ceux de l'utilisateur local, et non du serveur, et aucun privilège de superutilisateur SQL n'est requis.

La portée des tables temporaires est limitée à une seule session d'un seul rôle, donc ce qui précède doit être exécuté dans la même session psql :

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

Si vous écrivez cela dans une commande bash, assurez-vous de tout envelopper dans un single appel psql. Comme :

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

Normalement, vous avez besoin de la méta-commande \\ pour basculer entre les méta-commandes psql et les commandes SQL dans psql, mais \copy fait exception à cette règle. Encore le manuel :

des règles d'analyse spéciales s'appliquent au \copy méta-commande. Contrairement à la plupart des autres méta-commandes, le reste entier de la ligne est toujours considéré comme les arguments de \copy , et ni l'interpolation de variable ni l'expansion des guillemets inversés ne sont effectuées dans les arguments.

Grandes tables

Si la table d'importation est grande, il peut être payant d'augmenter temp_buffers temporairement pour la session (première chose dans la session):

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

Ajoutez un index à la table temporaire :

CREATE INDEX tmp_x_id_idx ON tmp_x(id);

Et lancez ANALYZE manuellement, car les tables temporaires ne sont pas couvertes par autovacuum / auto-analyze.

ANALYZE tmp_x;

Réponses associées :

  • Meilleur moyen de supprimer des millions de lignes par ID
  • Comment puis-je insérer des données communes dans une table temporaire à partir de schémas disparates ?
  • Comment supprimer les entrées en double ?