Wie kopiere ich von einer CSV-Datei in eine PostgreSQL-Tabelle mit Headern in einer CSV-Datei?

93

Ich möchte eine CSV-Datei in eine Postgres-Tabelle kopieren. Diese Tabelle enthält ungefähr 100 Spalten, daher möchte ich sie nicht neu schreiben, wenn ich nicht muss.

Ich benutze den \copy table from 'table.csv' delimiter ',' csv;Befehl, aber ohne eine erstellte Tabelle bekomme ich ERROR: relation "table" does not exist. Wenn ich eine leere Tabelle hinzufüge, wird kein Fehler angezeigt, aber es passiert nichts. Ich habe diesen Befehl zwei- oder dreimal ausprobiert und es gab keine Ausgabe oder Meldungen, aber die Tabelle wurde nicht aktualisiert, als ich sie über PGAdmin überprüfte.

Gibt es eine Möglichkeit, eine Tabelle mit Headern zu importieren, wie ich es versuche?

Stanley Cup Phil
quelle
2
Ihr Tisch heißt table? Sehr verwirrend. Existiert die Tabelle oder möchten Sie sie basierend auf der CSV erstellen? (Sie können nicht)
Wildplasser
1
Nun, ich habe es etwas anderes genannt, aber für dieses Beispiel nennen wir es Tabelle. Ich habe es mit und ohne es versucht, ich habe auch versucht, \copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;ohne Glück zu tun . Im Idealfall kann die Tabelle nur über die CSV erstellt und die Header in dieser Datei verwendet werden.
Stanley Cup Phil
Siehe auch
G. Cito
2
Nur ein Hinweis für alle, die vorhaben, aus einem großen CSV eine Postgres-Tabelle zu machen - Postgres ist auf 1600 Spalten in einer einzelnen Tabelle begrenzt. Sie können Tabellen nicht in Spalten mit einer Größe von 1600 Spalten aufteilen und sie anschließend verbinden. Sie müssen die Datenbank neu gestalten.
Achekroud
Wenn Ihnen Python zur Verfügung steht, können Sie d6tstack verwenden . Es kümmert sich auch um Schemaänderungen.
Citynorman

Antworten:

132

Das hat funktioniert. Die erste Zeile enthielt Spaltennamen.

COPY wheat FROM 'wheat_crop_data.csv' DELIMITER ';' CSV HEADER
G. Cito
quelle
5
Ich denke, das Problem mit diesem Befehl ist, dass Sie der DB-Superuser sein müssen. \ copy funktioniert auch als normaler Benutzer
Exocom
28
COPYErstellt keine Tabelle oder fügt keine Spalten hinzu, sondern fügt einer vorhandenen Tabelle mit den vorhandenen Spalten Zeilen hinzu. Vermutlich möchte der Fragesteller die Erstellung der ~ 100 Spalten automatisieren und COPYverfügt zumindest ab PG 9.3 nicht über diese Funktionalität.
Daniel Vérité
2
@Exocom guter Fang. Da ich auf den von mir verwendeten Postgres-Systemen niemals Administrator oder Superuser für DBs bin (der pgadmin macht mich zum Eigentümer der von mir verwendeten Datenbanken und gibt mir eingeschränkte Berechtigungen / Rollen), muss ich "\ COPY" verwendet haben. Prost
G. Cito
2
@ Daniel Ich habe verstanden, dass die Tabelle des Benutzers bereits vorhanden war und alle benötigten Spalten hatte und dass sie einfach Daten haben wolltenADD .
G. Cito
Ich syntax error at or near "HEADER" LINE 2: delimiter ',' CSV HEADERbin auf eine Rotverschiebung gekommen.
Mithril
24

Mit der Python-Bibliothek pandaskönnen Sie auf einfache Weise Spaltennamen erstellen und Datentypen aus einer CSV-Datei ableiten.

from sqlalchemy import create_engine
import pandas as pd

engine = create_engine('postgresql://user:pass@localhost/db_name')
df = pd.read_csv('/path/to/csv_file')
df.to_sql('pandas_db', engine)

Der if_existsParameter kann so eingestellt werden, dass er eine vorhandene Tabelle ersetzt oder an diese anhängt, z df.to_sql('pandas_db', engine, if_exists='replace'). Dies funktioniert auch für zusätzliche Eingabedateitypen, Dokumente hier und hier .

joelostblom
quelle
1
Ich finde, dass pd.DataFrame.from_csv mir weniger Probleme bereitet, aber diese Antwort ist bei weitem der einfachste Weg, IMO.
Brock
Es stimmt, ich bin mir nicht sicher, warum ich pd.read_excelstattdessen getippt habe pd.read_csv. Ich habe die Antwort aktualisiert.
Joelostblom
1
Dies ist eine fantastische Lösung, wenn Sie die Tabelle mit einer großen CSV nicht vorab erstellen möchten. Nur ein Kopf hoch - Postgres können nur 1600 Spalten in einer Tabelle aufnehmen. Anscheinend werden andere DB-Motoren mehr erlauben. So viele Spalten zu haben, ist anscheinend eine schlechte SQL-Form, obwohl dieser Konsens noch nicht bis zur Epidemiologie durchgesickert ist.
Achekroud
1
Standardmäßig df.to_sql()ist SEHR LANGSAM . Um dies zu beschleunigen, können Sie d6tstack verwenden . Es kümmert sich auch um Schemaänderungen.
Citynorman
13

Alternative per Terminal ohne Erlaubnis

Die pg Dokumentation bei NOTES sagen

Der Pfad wird relativ zum Arbeitsverzeichnis des Serverprozesses (normalerweise zum Datenverzeichnis des Clusters) und nicht zum Arbeitsverzeichnis des Clients interpretiert.

psqlWenn Sie also einen Client verwenden oder einen Client verwenden, selbst auf einem lokalen Server, haben Sie Probleme ... Und wenn Sie den Befehl COPY für andere Benutzer ausdrücken, z. Bei einer Github README wird der Leser Probleme haben ...

Die einzige Möglichkeit, den relativen Pfad mit Clientberechtigungen auszudrücken , ist die Verwendung von STDIN .

Wenn STDIN oder STDOUT angegeben ist, werden Daten über die Verbindung zwischen dem Client und dem Server übertragen.

wie hier erinnert :

psql -h remotehost -d remote_mydb -U myuser -c \
   "copy mytable (column1, column2) from STDIN with delimiter as ','" \
   < ./relative_path/file.csv
Peter Krauss
quelle
3

Ich benutze diese Funktion seit einiger Zeit ohne Probleme. Sie müssen nur die Nummernspalten in der CSV-Datei angeben, und es werden die Headernamen aus der ersten Zeile übernommen und die Tabelle für Sie erstellt:

create or replace function data.load_csv_file
    (
        target_table  text, -- name of the table that will be created
        csv_file_path text,
        col_count     integer
    )

    returns void

as $$

declare
    iter      integer; -- dummy integer to iterate columns with
    col       text; -- to keep column names in each iteration
    col_first text; -- first column name, e.g., top left corner on a csv file or spreadsheet

begin
    set schema 'data';

    create table temp_table ();

    -- add just enough number of columns
    for iter in 1..col_count
    loop
        execute format ('alter table temp_table add column col_%s text;', iter);
    end loop;

    -- copy the data from csv file
    execute format ('copy temp_table from %L with delimiter '','' quote ''"'' csv ', csv_file_path);

    iter := 1;
    col_first := (select col_1
                  from temp_table
                  limit 1);

    -- update the column names based on the first row which has the column names
    for col in execute format ('select unnest(string_to_array(trim(temp_table::text, ''()''), '','')) from temp_table where col_1 = %L', col_first)
    loop
        execute format ('alter table temp_table rename column col_%s to %s', iter, col);
        iter := iter + 1;
    end loop;

    -- delete the columns row // using quote_ident or %I does not work here!?
    execute format ('delete from temp_table where %s = %L', col_first, col_first);

    -- change the temp table name to the name given as parameter, if not blank
    if length (target_table) > 0 then
        execute format ('alter table temp_table rename to %I', target_table);
    end if;
end;

$$ language plpgsql;
mehmet
quelle
Vergessen Sie nicht, zu dem zu wechseln set schema 'data';, was für Sie der Fall ist
Mehmet
0

Sie können d6tstack verwenden , das die Tabelle für Sie erstellt und schneller als pd.to_sql () ist, da native DB-Importbefehle verwendet werden. Es unterstützt Postgres sowie MYSQL und MS SQL.

import pandas as pd
df = pd.read_csv('table.csv')
uri_psql = 'postgresql+psycopg2://usr:pwd@localhost/db'
d6tstack.utils.pd_to_psql(df, uri_psql, 'table')

Es ist auch nützlich, um mehrere CSVs zu importieren, Datenschemaänderungen zu lösen und / oder mit Pandas (z. B. Datumsangaben) vorzuarbeiten, bevor Sie in db schreiben (siehe unten im Beispielnotizbuch)

d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), 
    apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
Stadtmensch
quelle