web-dev-qa-db-fra.com

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

J'utilise Postgres et j'aimerais faire une grande requête de mise à jour qui serait extraite d'un fichier CSV, disons que j'ai un tableau qui a (id, banana, Apple).

Je voudrais exécuter une mise à jour qui change les bananes et non les pommes, chaque nouvelle banane et leur identifiant seraient dans un fichier CSV.

J'ai essayé de regarder le site Postgres mais les exemples me tuent.

62
user519753

COPY le fichier dans une table de transfert temporaire et mettez à jour la table à partir de cet emplacement. 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 contrainte.

Privilèges

SQL COPY nécessite des privilèges de superutilisateur pour cela. ( Le manuel ):

COPY l'attribution de nom à un fichier ou à une commande est uniquement autorisée pour les super-utilisateurs de la base de données, car elle permet de lire ou d'écrire tout fichier auquel le serveur dispose de privilèges d'accès.

La psql méta-commande \copy fonctionne pour tout rôle de base de données. Le manuel:

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

La portée des tables temporaires est limitée à un seul session d'un seul rôle. Le précédent doit donc ê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 ceci dans une commande bash, veillez à envelopper le tout dans un appel single 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 commandes méta psql et les commandes SQL dans psql, mais \copy est une exception à cette règle. Le manuel à nouveau:

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

Grandes tables

Si la table d'importation est grande, il peut être intéressant 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 exécutez ANALYZE manuellement, car les tables temporaires ne sont pas couvertes par autovacuum/auto-analysis.

ANALYZE tmp_x;

Réponses associées:

132
Erwin Brandstetter