it-swarm.com.de

Importieren Sie in Postgres JSON-Daten in eine CSV-Datei

Ich versuche, eine csv -Datei mit den Daten für eine Tabelle in postgres zu importieren. Eine der Spalten der Tabelle hat den Typ jsonb.

Eine Zeile meiner csv -Datei enthält so etwas wie

1,{"a":"b"}

Angenommen, die Tabelle hat ein Schema

id              | smallint          | 
data            | jsonb             | 

Wenn ich nur versuche, die Daten einzufügen, funktioniert alles einwandfrei

INSERT INTO table VALUES (1, '{"a":"b"}');

Es wird versucht, direkt aus der Datei mit zu importieren

COPY table FROM '/path/to/file.csv' DELIMITER ',' csv;

gibt mir folgenden Fehler:

ERROR:  invalid input syntax for type json
DETAIL:  Token "a" is invalid.
CONTEXT:  JSON data, line 1: {a...
COPY availability, line 1, column services: "{a: b}"

Ich habe versucht, die Felder mit ', Mit ", Mit \" Und \' Zu zitieren, aber nichts funktioniert.

Welches ist die richtige Syntax?

7
marcosh

Der Befehl PostgreSQL COPY ist selten ideal, funktioniert aber häufig. Als Referenz gibt es bessere Methoden, um dies herauszufinden, als zu raten.

CREATE TEMP TABLE baz AS
  SELECT 1::int, '{"a":"b"}'::jsonb;

Dies sind Ihre genauen Beispieldaten. Jetzt können wir verschiedene Einstellungen testen.

# COPY baz TO STDOUT;
1   {"a": "b"}

COPY baz TO STDOUT DELIMITER ',';
1,{"a": "b"}

Sie werden sehen, dass das oben Genannte genau die Daten generiert, die Sie befragt haben ...

COPY baz TO '/tmp/data.csv' DELIMITER ',';

Es gibt kein Problem. Zumindest nicht mit PostgreSQL 9.5.

CSV-Modus

Wo ist dein Problem, es ist im CSV-Modus. Beobachten,

# COPY baz TO STDOUT;
1   {"a": "b"}
# COPY baz TO STDOUT CSV;
1,"{""a"": ""b""}"

Sie können sehen, dass diese beiden jetzt unterschiedlich sind. Versuchen wir, die Nicht-CSV-Datei im CSV-Modus zu laden, der das Format annimmt, das der CSV-Modus oben generiert hat.

TRUNCATE baz;
COPY baz FROM '/tmp/data.csv' DELIMITER ',' CSV;
ERROR:  invalid input syntax for type json
DETAIL:  Token "a" is invalid.
CONTEXT:  JSON data, line 1: {a...
COPY baz, line 1, column jsonb: "{a: b}"

Jetzt irren wir. Der Grund dafür kommt von RFC 418

Jedes Feld kann in doppelte Anführungszeichen eingeschlossen sein oder nicht (einige Programme, wie z. B. Microsoft Excel, verwenden jedoch überhaupt keine doppelten Anführungszeichen). Wenn Felder nicht in doppelte Anführungszeichen eingeschlossen sind, werden doppelte Anführungszeichen möglicherweise nicht in den Feldern angezeigt.

  1. Also JSON RFC 4627 gibt an, dass Namen eines Objekts in Name/Wert-Paaren Zeichenfolgen sein müssen, für die doppelte Anführungszeichen erforderlich sind.
  2. Und CSV RFC 418 gibt an, dass, wenn sich doppelte Anführungszeichen innerhalb des Feldes befinden, das gesamte Feld in Anführungszeichen gesetzt werden muss.

An diesem Punkt haben Sie zwei Möglichkeiten.

  1. Verwenden Sie nicht den CSV-Modus.
  2. Oder entkommen Sie den inneren Anführungszeichen.

Dies wären also gültige Eingaben unter denselben Optionen im CSV-Modus.

#COPY baz TO STDOUT DELIMITER ',' CSV ESCAPE E'\\';
1,"{\"a\": \"b\"}"

# COPY baz TO STDOUT DELIMITER ',' CSV;
1,"{""a"": ""b""}"
5
Evan Carroll

Gefunden die Lösung, verwendet postgres " als Escapezeichen, daher sollte das richtige Format sein

{"""a""": """b"""}
3
marcosh

Wie in anderen Antworten vermerkt CSV und der JSON Spezifikationen (und wahrscheinlich die postgresql Spezifikationen) sind etwas inkompatibel. Um sie dazu zu bringen, nicht mehr zu kämpfen, zumindest in ihrer einfachen Form, muss man den Dingen entkommen, bis sie ein unlesbares Durcheinander sind. Nicht verwenden CSV Modus ist noch schlimmer als der KOPIEREN wird an allem sterben, was JSON hat ein Problem mit: eingebetteten neuen Zeilen, Schrägstrichen oder Anführungszeichen.

Ich hatte genau das gleiche Problem nur mit einer viel komplexeren Eingabe: einer Menge von ENUM Typen, ganze Zahlen und komplexe JSON Felder. Nämlich:

create table messages( a blab, b integer, c text, d json, e json);

wo das typische JSONs wäre {"default":"little","sms":"bigger"} und ["name","number"]. Versuchen Sie, einen Stapel von denen mit einem zu importieren KOPIEREN Befehl: Wenn die Kommas in der JSON Erhalten Sie nicht die Anführungszeichen werden! Ich verbringe Stunden damit, bis ich diesen schönen Blog-Beitrag gefunden habe, der auf die Ursachen des Problems und die Optionen hinwies, die Sie benötigen, um daraus herauszukommen.

Grundsätzlich müssen Sie die Trennzeichen- und Anführungszeichenfelder in etwas ändern, von dem Sie garantieren können, dass es nicht in Ihrem Feld enthalten ist JSON Daten. In meinem Fall kann ich viel garantieren, damit ich einfach gehen kann

COPY messages( a, b, c, d, e) from stdin  csv quote '^' delimiter '|';
malfunction|5|La la la|{"default":"little","sms":"bigger"}|["name","number"]

Schön und lesbar, leicht zu erreichen mit einigen geringfügigen Zeichenersetzungen in Ihrem Lieblingstext-Mangler, und kein Entkommen von nichts! Wenn Sie nicht garantieren können, dass die oben verwendeten Zeichen nicht in Ihrem enthalten sein können JSON dann kannst du das ziemlich verrückte e'\x01' und e'\x02' als die JSON spec hält sie für völlig illegal. Nicht ganz so lesbar und so weiter, aber pünktlich korrekt.

Beachten Sie, dass eingebettete neue Zeilen wie einige JSON Generatoren neigen dazu, aus Gründen der Lesbarkeit zu emittieren. Sie sind immer noch "Nein-Nein", daher müssen Sie sie aus Ihrem herausfiltern JSON.

1
Nadreck