Ich verwende Postgres und möchte eine große Update-Abfrage durchführen, die aus einer CSV-Datei abgerufen wird. Nehmen wir an, ich habe eine Tabelle, die vorhanden ist (id, banana, apple)
.
Ich möchte ein Update ausführen, das die Bananen und nicht die Äpfel ändert. Jede neue Banane und ihre ID befinden sich in einer CSV-Datei.
Ich habe versucht, mir die Postgres-Site anzusehen, aber die Beispiele bringen mich um.
Antworten:
COPY
die Datei in eine temporäre Staging-Tabelle und aktualisieren Sie die tatsächliche Tabelle von dort. Mögen: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
Wenn die importierte Tabelle genau mit der zu aktualisierenden Tabelle übereinstimmt, kann dies praktisch sein:
CREATE TEMP TABLE tmp_x AS SELECT * FROM tbl LIMIT 0;
Erstellt eine leere temporäre Tabelle, die ohne Einschränkungen der Struktur der vorhandenen Tabelle entspricht.
Privilegien
SQL
COPY
erfordert hierfür Superuser-Berechtigungen. ( Das Handbuch ):Der psql Meta-Befehl
\copy
funktioniert für jede db Rolle. Das Handbuch:Der Umfang temporärer Tabellen ist auf eine einzelne Sitzung einer einzelnen Rolle beschränkt, daher muss das oben Gesagte in derselben psql-Sitzung ausgeführt werden:
CREATE TEMP TABLE ...; \copy tmp_x FROM '/absolute/path/to/file' (FORMAT csv); UPDATE ...;
Wenn Sie dies in einem Bash-Befehl skripten, müssen Sie alles in einem einzigen psql-Aufruf zusammenfassen. Mögen:
echo 'CREATE TEMP TABLE tmp_x ...; \copy tmp_x FROM ...; UPDATE ...;' | psql
Normalerweise benötigen Sie den Meta-Befehl
\\
, um zwischen psql-Meta-Befehlen und SQL-Befehlen in psql zu wechseln. Dies ist jedoch\copy
eine Ausnahme von dieser Regel. Das Handbuch noch einmal:Große Tische
Wenn die Importtabelle groß ist, kann es sich lohnen,
temp_buffers
die Sitzung vorübergehend zu erhöhen (als erstes in der Sitzung):SET temp_buffers = '500MB'; -- example value
Fügen Sie der temporären Tabelle einen Index hinzu:
CREATE INDEX tmp_x_id_idx ON tmp_x(id);
Und
ANALYZE
manuell ausführen , da temporäre Tabellen nicht durch Autovakuum / Autoanalyse abgedeckt werden.ANALYZE tmp_x;
Verwandte Antworten:
quelle
COPY tmp_x FROM '/absolute/path/to/file' (DELIMITER ';', HEADER TRUE, FORMAT CSV)
hat besser für mich gearbeitet. Siehe ( postgresql.org/docs/9.1/static/sql-copy.html )USING
durchFROM
in derUPDATE
-StatementSie können den folgenden in Python geschriebenen Code ausprobieren. Die Eingabedatei ist die CSV-Datei, deren Inhalt Sie in der Tabelle aktualisieren möchten. Jede Zeile wird anhand von Kommas aufgeteilt, sodass für jede Zeile Zeile [0] der Wert in der ersten Spalte, Zeile [1] der Wert in der zweiten Spalte usw. ist.
import csv import xlrd import os import psycopg2 import django from yourapp import settings django.setup() from yourapp import models try: conn = psycopg2.connect("host=localhost dbname=prodmealsdb user=postgres password=blank") cur = conn.cursor() filepath = '/path/to/your/data_to_be_updated.csv' ext = os.path.splitext(filepath)[-1].lower() if (ext == '.csv'): with open(filepath) as csvfile: next(csvfile) readCSV = csv.reader(csvfile, delimiter=',') for row in readCSV: print(row[3],row[5]) cur.execute("UPDATE your_table SET column_to_be_updated = %s where id = %s", (row[5], row[3])) conn.commit() conn.close() cur.close() except (Exception, psycopg2.DatabaseError) as error: print(error) finally: if conn is not None: conn.close()
quelle