Ergebnisse aus der SQL-Abfrage in CSV schreiben und zusätzliche Zeilenumbrüche vermeiden

8

Ich muss Daten aus verschiedenen Datenbank-Engines extrahieren. Nachdem diese Daten exportiert wurden, sende ich die Daten an AWS S3 und kopiere diese Daten mit einem COPY-Befehl zu Redshift. Einige der Tabellen enthalten viel Text mit Zeilenumbrüchen und anderen Zeichen in den Spaltenfeldern. Wenn ich den folgenden Code ausführen:

%Vor%

Einige der Spalten, die Zeilenumbrüche / Zeilenumbrüche enthalten, erstellen neue Zeilen:

%Vor%

, wodurch der Importvorgang fehlschlägt. Ich kann das umgehen, indem ich für Ausnahmen hart codiere:

%Vor%

Aber das dauert eine lange Zeit, um größere Dateien zu verarbeiten, und scheint im Allgemeinen wie schlechte Praxis. Gibt es eine schnellere Möglichkeit zum Exportieren von Daten von einem SQL-Cursor in eine CSV-Datei, die bei Textspalten, die Zeilenumbrüche / Zeilenumbrüche enthalten, nicht unterbrochen wird?

    
user2752159 14.02.2018, 18:25
quelle

4 Antworten

2

Ich vermute, dass das Problem so einfach ist, wie sicherzustellen, dass die Python-CSV-Exportbibliothek und der COPY-Import von Redshift eine gemeinsame Schnittstelle sprechen. Kurz gesagt, überprüfen Sie Ihre Trennzeichen und zitierenden Zeichen und stellen Sie sicher, dass sowohl die Python-Ausgabe als auch der COPY-Befehl Redshift übereinstimmen.

Mit ein wenig mehr Detail: Die DB-Treiber werden bereits die harte Arbeit geleistet haben, um Python in einer wohlverstandenen Form zu erreichen. Das heißt, jede Zeile aus der Datenbank ist eine Liste (oder ein Tupel, ein Generator usw.), und auf jede Zelle kann individuell zugegriffen werden. Und an dem Punkt, an dem Sie eine listenähnliche Struktur haben, kann der CSV-Export von Python den Rest der Arbeit erledigen und - Redshift - ist in der Lage, die Ausgabe, eingebettete Zeilenumbrüche und alles andere zu kopieren. Insbesondere sollten Sie kein manuelles Escaping durchführen. Die Funktionen .writerow() oder .writerows() sollten alles sein, was Sie tun müssen.

Die COPY-Implementierung von Redshift versteht standardmäßig den gebräuchlichsten Dialekt von CSV, nämlich

  • Begrenze Zellen durch ein Komma ( , ),
  • zitieren Zellen mit doppelten Anführungszeichen ( " ),
  • und um alle eingebetteten doppelten Anführungszeichen durch Verdoppelung zu umgehen ( """ ).

Um das zu untermauern mit Dokumentation von Redshift FORMAT AS CSV :

  

... Das standardmäßige Anführungszeichen ist ein doppeltes Anführungszeichen ("). Wenn das Anführungszeichen in einem Feld verwendet wird, wird das Zeichen mit einem zusätzlichen Anführungszeichen entfernt. ...

Allerdings verwendet Ihr Python-CSV-Exportcode eine Pipe ( | ) als delimiter und setzt quotechar auf doppelte Quote ( " ). Das kann auch funktionieren, aber warum sollten Sie von den Standardeinstellungen abweichen? Schlage vor, den Namensvetter von CSV zu verwenden und deinen Code dabei einfacher zu halten:

%Vor%

Teilen Sie COPY mit, dass das CSV-Format verwendet werden soll (auch hier sind keine Standardspezifikationen erforderlich):

%Vor%

Das sollte es tun.

    
hunteke 24.02.2018, 19:28
quelle
3

Wenn Sie SELECT * FROM table ohne eine WHERE -Klausel ausführen, können Sie stattdessen COPY table TO STDOUT mit den richtigen Optionen verwenden:

%Vor%

Dies führt bei meinen Tests zu einem wörtlichen "\ n" anstelle von tatsächlichen Zeilenumbrüchen, bei denen das Schreiben durch den csv-Writer zu unterbrochenen Linien führt.

Wenn Sie in der Produktion eine WHERE -Klausel benötigen, können Sie eine temporäre Tabelle erstellen und stattdessen kopieren:

%Vor%

(Bearbeiten) Wenn ich Ihre Frage noch einmal anschaue, sehe ich, dass Sie "alle verschiedenen Datenbank-Engines" erwähnen. Das obige funktioniert mit psyopg2 und postgresql, könnte aber wahrscheinlich für andere Datenbanken oder Bibliotheken angepasst werden.

    
Nathan Vērzemnieks 20.02.2018 00:07
quelle
0

Warum schreibe ich nach jeder Zeile in die Datenbank?

%Vor%     
Batman 24.02.2018 18:32
quelle
0

Das Problem ist, dass Sie den Befehl Redshift COPY mit seinen Standardparametern verwenden, die eine Pipe als Trennzeichen verwenden (siehe hier und hier ) und erfordert das Entfernen von Zeilenumbrüchen und Pipes in Textfeldern (siehe hier und hier ). Wie auch immer, der Python-CSV-Writer weiß nur, wie man die Standard-Sache mit eingebetteten Zeilenumbrüchen macht, nämlich, sie in einer in Anführungszeichen gesetzten Zeichenfolge zu belassen.

Glücklicherweise kann der Befehl Redshift COPY auch das Standard-CSV-Format verwenden. Hinzufügen der CSV -Option zu Ihrem COPY -Befehl gibt Ihnen dieses Verhalten :

  

Aktiviert die Verwendung des CSV-Formats in den Eingabedaten. Um Trennzeichen, Zeilenumbruchzeichen und Zeilenumbrüche automatisch zu umgehen, schließen Sie das Feld in das Zeichen ein, das im Parameter QUOTE angegeben ist. Das standardmäßige Anführungszeichen ist ein Anführungszeichen ("). Wenn das Anführungszeichen in einem Feld verwendet wird, müssen Sie das Zeichen mit einem zusätzlichen Anführungszeichen ausschließen."

Dies ist genau der Ansatz, den der Python-CSV-Writer verwendet, also sollte er sich um Ihre Probleme kümmern. Also mein Rat wäre, eine Standard-CSV-Datei mit Code wie folgt zu erstellen:

%Vor%

Ändere dann in Redshift deinen COPY -Befehl auf etwas dies (beachten Sie das hinzugefügte CSV -Tag):

%Vor%

Alternativ können Sie Ihre Felder auch manuell so konvertieren, dass sie den Standardeinstellungen für den COPY-Befehl von Redshift entsprechen. Pythons csv.writer wird das nicht für dich allein tun, aber du kannst deinen Code vielleicht etwas beschleunigen, besonders für große Dateien, wie zum Beispiel:

%Vor%

Als weitere Alternative könnten Sie mit dem Importieren der Abfragedaten in einen pandas DataFrame mit .from_sql experimentieren, die Ersetzungen im DataFrame durchführen (jeweils eine ganze Spalte) und dann die Tabelle mit .to_csv schreiben. . Pandas hat unglaublich schnellen CSV-Code, so dass dies eine erhebliche Beschleunigung geben kann.

Update: Ich habe gerade festgestellt, dass ich @ huntekes Antwort am Ende im Wesentlichen dupliziert habe. Der Schlüsselpunkt (den ich beim ersten Mal verpasst habe) ist, dass Sie wahrscheinlich das CSV Argument in Ihrem aktuellen Redshift COPY Befehl nicht benutzt haben; Wenn Sie das hinzufügen, sollte das einfach werden.

    
Matthias Fripp 25.02.2018 02:25
quelle