Hi!
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.
1. 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?
2. 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.
Meister U.
Du könntest dir mal den SQL-Befehl COPY ... FROM STDIN anschauen.
Dann musst du die Daten von Java aus nur noch in die Datenbankverbindung schieben.
Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören
Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler
PostgreSQL Service & Support
schonmal vielen Dank.
Aber wie schiebe ich? Der Befehl würde ja irgendwie so aussehen:
copyManager.copyIn("COPY foo FROM stdin");
foo ist eine Tabelle, die nur eine Spalte hat und ich würde nun gerne 1,2,3,4,5.... reinschieben. Wie mache ich das?
Wenn es nur darim geht, eine einspaltige Tabelle mit fortlaufenden Zahlen zu füllen, dann geht das trivial einfacher so:
Es bleibt nun die Frage, wozu man sowas machen will, wenn es generate_series() gibt. Dies macht so eine Tabelle ganz, ganz sicher überflüssig.Code:test=# create table schiebe (i int); CREATE TABLE test=# insert into schiebe select generate_Series(1,10); INSERT 0 10 test=# select * from schiebe; i ---- 1 2 3 4 5 6 7 8 9 10 (10 rows)
Andreas
--
https://www.xing.com/profile/Andreas_Kretschmer7ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
Hi!
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.
Keine Ahnung, wie man in Java direkt in einen Stream schreibt. Steht aber sicher irgendwo in der Dokumentation.
Wenn du etwas findest, füge doch bitte deine Fundstellen hier ein. Damit andere in Zukunft etwas davon haben.
Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören
Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler
PostgreSQL Service & Support
Es gibt den CopyManager CopyManager
Mit diesem wird eine Methode copyIn anwendbar.
copyIn(sql, stream)
copyIn(sql, Reader)
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:
1. Ich muss immernoch zuerst ein CSV File schreiben und kann nicht wirklich vom Parser direkt in die DB parsen und
2. 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?
Deine Daten passen nicht zu UTF8.
select * from depesz; » Blog Archive » ERROR: invalid byte sequence for encoding
Andreas
--
https://www.xing.com/profile/Andreas_Kretschmer7ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
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?
Geändert von MeisterU (16.03.2010 um 14:31 Uhr)
--
https://www.xing.com/profile/Andreas_Kretschmer7ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
Links: Tobias Bauer - IT- und Funkdienstleistungen - Bilderrahmen-kaufen.de - Der Onlineshop für Bilderrahmen & Fotorahmen - Funkforum
Lesezeichen