Ich benutze Postgres 8.4 mit einem JDBC4 Treiber und habe eine Frage zum Bulk Load.
Ich suche eine von Java ausführbar Methode, um so etwas wie \copy table(column 1, column 2) from file.csv… auf ein csv File auszuführen.
Ich erstelle aus anderen Daten normalerweise eine csv Datei und lade sie dann per \copy in die Datenbank.
Nun soll das Programm an dem ich grade arbeite auch für Benutzer verständlich sein, die nicht auf Kommandozeilenebene ein \copy ausführen wollen/können. (Ziel: Benutzer wählt auf der GUI ein File aus. Dann wird es in Java verarbeitet und als Ergebnis ist dieses File dann in der Datenbank und das alles ohne, dass der Benutzer csv Files löschen, kopieren oder \copy machen muss)
Nun stelle ich mir 2 Szenarien vor von denen ich nicht weiß wie ich sie effizient (also ohne das Standard INSERT) implementieren kann.
Ich parse meine Daten direkt in einen Buffer und führe aus diesem Buffer (der irgendwie wie ein in Memory csv aussieht (zb. 2000 csv Zeilen)) ein copy Befehl aus. Wie kann ich das machen?
Ich parse meine Daten in ein CSV File, speichere es auf der Platte und führe einen Copy Befehl über Java aus, der mir die Daten in die Datenbank lädt. Für so etwas gibt es tatsächlich den copymanager, der schiebt die csv Daten trotzdem nochmal mit einem Reader durch die JAVA VM und erst dann in die Datenbank. Diesen Schritt möchte ich verhindern, denn es ist absolut ineffizient 10GB Dateien von einem Java Reader durch die VM laufen zu lassen.
Was denkt Ihr was am effizientesten ist? Und wie kann ich das implementieren? Ich vermute, dass Methode 1 am besten wäre, wenn implementierbar, denn dann brauche ich die CSV gar nicht auf Platte zu schreiben sondern brauche nur einen Read(vom nicht nicht geparsten File) und einem Write(direkt in die db).
Vielen Dank schon mal für die schnellen Antworten.
Ich will mit diesem einfachen Beispiel einfach mal den COPY Operator über Java testen. Sobald ich das verstehe, werden natürlich andere/komplexere Daten eingefügt.
Ich habe jetzt so “gelöst”:
Connection connection = DriverManager.getConnection(,,*);
PGConnection pConn = (PGConnection)connection;
CopyManager copyManager = pConn.getCopyAPI();
copyManager.copyIn(“COPY bla FROM stdin”, new FileReader(new File(“file.txt”)));
Nun ergeben sich 2 Probleme:
Ich muss immernoch zuerst ein CSV File schreiben und kann nicht wirklich vom Parser direkt in die DB parsen und
bekomme ich jetzt Fehler wie: “COPY-Ende-Markierung verfälscht” oder “ungültige Byte-Sequenz für Kodierung »UTF8«: 0x00
Hinweis: Dieser Fehler kann auch auftreten, wenn die Bytesequenz nicht mit der Kodierung übereinstimmt, die der Server erwartet, welche durch »client_encoding« bestimmt wird.”
je nachdem ob ich ein . am Ende mache oder nicht.
Ich vermute, dass ich ein spezielles CharSet mit Java benutzen muss. Oder gibt es weitere Ideen?
eine andere, viel trivialere Frage habe ich dann noch
ich habe
dbtest=# copy bla from ‘bla.txt’;
FEHLER: konnte Datei »bla.txt« nicht zum Lesen öffnen: No such file or directory
aber
dbtest=# \copy bla from bla.txt
das läuft ohne Probleme. Den Befehl \copy kann ich von Java aus aber nicht anschieben, lediglich copy. Wo liegt also, dass Problem, dass ein Befehl die Datei findet, die andere aber nicht?
Bzw warum brauch ich den totalen und nicht den relativen Pfad?