Problem bei Import aus Datei

Hallo,

ich bin noch ein Newbie im Bereich Datenbanken, brauche diese aber zur Vervollständigung meiner Diplomarbeit. Was hierbei besonders interessant für mich ist, ist der Import von Daten aus einer Datei in eine Tabelle. Die Dateien sind selbst tabellenartig (bis zu 20 Spalten und 100000 Zeilen).
Soweit klappt das auch mit dem “Copy”-Befehl. Allerdings ist mir aufgefallen, daß dies nur der Fall ist, wenn die Einträge in den Spalten einer Zeile einen “Tab”-Abstand besitzen. Andernfalls kann PGSQL die Daten den einzelnen Spalten nicht zuweisen.
Deswegen meine Frage:
Besteht diese Problem überhaupt oder stelle ich mich nur dämlich an? :confused:
Wenn ersteres der Fall sein sollte, gibt es doch sicherlich ein Tool zur “Formatierung” der Dateien?!?
Bei letzterem: wie kann ich es besser machen?

Mein Befehl lautet ganz einfach:

copy … from ‘/…’;

Trenne ich die Einträge in der Datei nur mit einem Leerzeichen, dann kommt folgende Fehlermeldung:

“invalid input syntax”

Für Antworten bedanke ich mich im voraus!

Es gibt eine recht gute Onlinehilfe:

test=*# \h copy
Command: COPY
Description: copy data between a file and a table
Syntax:
COPY tablename [ ( column [, …] ) ]
FROM { ‘filename’ | STDIN }
[ [ WITH ]
[ BINARY ]
[ OIDS ]
[ DELIMITER [ AS ] ‘delimiter’ ]
[ NULL [ AS ] ‘null string’ ]
[ CSV [ HEADER ]
[ QUOTE [ AS ] ‘quote’ ]
[ ESCAPE [ AS ] ‘escape’ ]
[ FORCE NOT NULL column [, …] ]

COPY tablename [ ( column [, …] ) ]
TO { ‘filename’ | STDOUT }
[ [ WITH ]
[ BINARY ]
[ HEADER ]
[ OIDS ]
[ DELIMITER [ AS ] ‘delimiter’ ]
[ NULL [ AS ] ‘null string’ ]
[ CSV [ HEADER ]
[ QUOTE [ AS ] ‘quote’ ]
[ ESCAPE [ AS ] ‘escape’ ]
[ FORCE QUOTE column [, …] ]

na schön, wenn ich jetzt

copy … from ‘/…’ with delimiter ’ ';

eingebe, importiert er Daten, die innerhalb einer Zeile nur von einem Leerzeichen getrennt sind.
Dasselbe geht mit ‘\t’, wenn ein tab dazwischen ist. Aber ich schaff es nicht, wenn z.B. 3 Leerzeichen Abstand sind, weil DELIMITER ein SINGLE CHARACTER sein muß.

Jedes beliebige Eingabeformat ist vielleicht nicht möglich, aber kannst du die Daten nicht vorher etwas aufbereiten? Ein kleines sed oder awk Script sollten da gute Dienste tun.

okay, das hab ich mir schon gedacht ^^
da hab ich leider keine ahnung von :wink:
könnte man das mit dem C-Prog machen?

Bestimmt auch mit C, aber sed oder awk geht bestimmt schneller. Was genau gefällt Dir an \t nicht?
Du kannst doch bestimmt auch ein Zeichen finden, das so nicht im text vorkommt, das PIPE-Zeichen z.B.

Andreas

nee, ich hab ja nix gegen ‘\t’ oder ‘|’ :wink:
die Daten sind halt so angeordnet:

v’ v" s’ s" J p" PQR wavenumbr A*HLF/(2J’+1) term values

0 0 1 1 3.5 + 1 11538.707 457142.857 12.096
0 0 1 1 4.5 + 1 11526.832 533333.333 36.611
0 0 1 1 5.5 + 1 11513.797 561038.961 73.419
0 0 1 1 6.5 + 1 11499.273 574358.974 122.464
0 0 1 1 7.5 + 1 11483.168 581818.182 183.701
0 0 1 1 8.5 + 1 11465.454 586425.339 257.083
0 0 1 1 9.5 + 1 11446.128 589473.684 342.557

und das ist noch viel schlimmer, wie ich jetzt sehe, weil die Einträge auch noch unterschiedliche Abstände innerhalb einer Zeile haben :astonished:
das kommt jetzt hier allerdings nicht rüber ^^

Naja. Erzeugst Du diese Datei per Hand oder automatisch?
Der TAB-Abstand ist Sache der Darstellung, im vim kann man das z.B. einstellen. Dann sieht das auch hybsch aus. Aber normalerweise sieht ‘Mensch’ das ja gar nicht erst.

Andreas

achso, das hätte ich vielleicht dazu sagen sollen: die dateien werden nicht von mir erzeugt, das sind daten, die ich aus dem netz ziehen muß, d.h. ich habe keine kontrolle darüber, wie diese werte innerhalb der dateien angeordnet sind

Naja. Damit ist das aber eher ein organisatorisches oder sonstiges Problem und keines von PostgreSQL. Mich wundert allerdings, das bei “(bis zu 20 Spalten und 100000 Zeilen)” nicht einmal die Reihenfolge der Daten klar ist.

Andreas

Hallo scytale,

leider hast Du die Tabellendefinition nicht angegeben. Ich vermute mal, dass die Fehlermeldung “invalid input syntax” durch das dem ‘+’-Zeichen folgende Leerzeichen entsteht. Das ‘+’-Zeichen hört zur nachfolgenden Zahl und muß daher direkt vor der Zahl stehen, ansonsten wird es als Character interpretiert.



mfg

fristo

die daten haben natürlich eine ordnung, sonst wäre es ja sinnlos :wink:
nur kann ich sie nicht bestimmen, weil ich nicht mit den leuten zusammenarbeite, die sie erstellen und die dateien teilweise auch schon 10 jahre alt sind

hi fristo,
das + gehört nicht zur nachfolgenden zahl, es gehört zum “p”
“p” wiederum ist eine eigene spalte, in der nur characters bzw. text stehen soll

Hallo scytale,

hier mal etwas Code zum Nachweis das es doch funktioniert. Verschiedene Parameter muss Du an Deine Bedürfnisse anpassen.

Drop Table
If Exists       aaa;
 
Create Table    aaa
                (
                v1              int,
                v2              int,
                s1              int,
                s2              int,
                j               double precision,
                p2              char,
                pqr             double precision,
                wavenumbr       double precision,
                formel          double precision,
                term            double precision,
                values          double precision
                );
 
Copy            aaa
From            'g:/dokumente und einstellungen/administrator/eigene dateien/tmp/data.txt'
With            delimiter       as ' '
                csv             header;

Die Datei “data.txt” hat folgenden Inhalt:

 
v1 v2 s1 s2 j p2 pqr wavenumbr formel term values
0 0 1 1 3.5 + 1 11538.707 457142.857 12.096 
0 0 1 1 4.5 + 1  11526.832 533333.333 36.611
0 0 1 1 5.5 + 1 11513.797  561038.961 73.419
0 0 1 1 6.5 + 1 11499.273 574358.974  122.464
0 0 1 1 7.5 + 1 11483.168  581818.182 183.701
0 0 1 1 8.5 + 1  11465.454 586425.339 257.083
0 0 1 1 9.5 + 1  11446.128 589473.684 342.557

Wie Du siehst habe ich an bestimmten Stellen doppelte Leerzeichen eingeführt (auch am Ende einer Zeile), so dass in der Tabelle es Spalten mit keinem Wert gibt. Der Code wurde von mir getestet und funktioniert einwandfrei. Sollte Dir weiterhelfen.



mfg

fristo

danke für die mühe fristo :wink:
leider muß ich dazu was anmerken: das es bei dir geklappt hat, war nur zufall :rolleyes:
du hast 11 Spalten definiert, aber es gibt in jeder Zeile nur 10 Zahlen, d.h. in deiner Tabelle müßten leere Felder auftauchen, oder?
diese entstehen, wenn du eben in einer Zeile mal nich nur 1 sondern 2 Leerzeichen Abstand zwischen den Zahlen hast
und das hast du für jede Zeile auch immer nur einmal gemacht, d.h. er lässt die eine Spalte dann frei (weil Leerzeichen) und trägt es in die nächste ein ^^

so sieht die tabelle bei mir aus bzw. so soll sie aussehen:

v1 v2 s1 s2 j p2 pqr w a t

und das soll dann rein:

0 0 1 1 3.5 + 1 11538.707 457142.857 12.096
0 0 1 1 4.5 + 1 11526.832 533333.333 36.611
0 0 1 1 5.5 + 1 11513.797 561038.961 73.419

das geht dann mit

copy linestrength from ‘/data.txt’;

nicht, auch nicht, wenn ich ein " with delimiter as ’ ’ " reinsetze, weil die abstände eben variabel sind :rolleyes:

Im Gegensatz zu Dir bin ich kein Student der bei einem einfachen Problem hier im Forum auf Unterstützung hofft, sondern ein Profi, der sein Handwerk beherrscht und dessen Programme immer funktionieren und nicht zufällig. Must wohl noch eine Menge lernen, nicht nur was Datenbanken betrifft.

beleidigen wollte ich dich nicht, sondern dir nur einen Hinweis geben, aber schau selbst:

diplomarbeit=# Create Table aaa
diplomarbeit-# (
diplomarbeit(# v1 int,
diplomarbeit(# v2 int,
diplomarbeit(# s1 int,
diplomarbeit(# s2 int,
diplomarbeit(# j double precision,
diplomarbeit(# p2 char,
diplomarbeit(# pqr double precision,
diplomarbeit(# wavenumbr double precision,
diplomarbeit(# formel double precision,
diplomarbeit(# term double precision,
diplomarbeit(# values double precision
diplomarbeit(# );
CREATE TABLE
diplomarbeit=# Copy aaa
diplomarbeit-# From ‘/home/scytale/data.txt’
diplomarbeit-# With delimiter as ’ ’
diplomarbeit-# csv header;
COPY
diplomarbeit=# select * from aaa;
v1 | v2 | s1 | s2 | j | p2 | pqr | wavenumbr | formel | term | values
----±—±—±—±----±—±----±----------±-----------±-----------±--------
0 | 0 | 1 | 1 | 3.5 | + | 1 | 11538.707 | 457142.857 | 12.096 | ----------
0 | 0 | 1 | 1 | 4.5 | + | 1 | -------------- | 11526.832 | 533333.333 | 36.611
0 | 0 | 1 | 1 | 5.5 | + | 1 | 11513.797 | ---------------- | 561038.961 | 73.419
0 | 0 | 1 | 1 | 6.5 | + | 1 | 11499.273 | 574358.974 | --------------- | 122.464
0 | 0 | 1 | 1 | 7.5 | + | 1 | 11483.168 | ---------------- | 581818.182 | 183.701
0 | 0 | 1 | 1 | 8.5 | + | 1 | -------------- | 11465.454 | 586425.339 | 257.083
0 | 0 | 1 | 1 | 9.5 | + | 1 | -------------- | 11446.128 | 589473.684 | 342.557
(7 Zeilen)

das war es, was ich mit leeren Einträgen meinte (die “----------” sind zur verdeutlichung von mir gesetzt worden)
jetzt das ganze mit 10 Spalten:

diplomarbeit=# create table LS (v1 int, v2 int, s1 int, s2 int, j1 double precision, p char, pqr double precision, w double precision, a double precision, t2 double precision);
CREATE TABLE
diplomarbeit=# copy ls from ‘/home/scytale/data.txt’ with delimiter as ’ ’ csv header;
FEHLER: zusätzliche Daten nach letzter erwarteter Spalte
CONTEXT: COPY ls, Zeile 2: »0 0 1 1 3.5 + 1 11538.707 457142.857 12.096 «
diplomarbeit=#

was eben nicht funktioniert

Hallo scytale,

den Untschied zwischen Ursache und Wirkung solltest Du eigentlich kennen.

Hier ein nettes Beispiel von Dir: Für den Header der Tabelle gibtst Du folgende Informationen an:

v’ v" s’ s" J p" PQR wavenumbr A*HLF/(2J’+1) term values

Ich zähle da 11 Felder, die durch ein Leerzeichen getrennt sind, und nicht 10. Und die Headerinformationen in einer Tabelle sind immer maßgebend, da Sie die Spalten einer Tabelle angeben. Nicht nur weil der COPY-Befehl immer für jede Spalte einer Zeile Werte verlangst, sondern um Dir auch zu zeigen, dass man Felder ohne Werte importieren kann, habe ich an verschiedenen Stellen ein Leerzeichen eingefügt.

Solange in der Import-Datei pro Zeile immer 10 Werte eingetragen sind, sollte es kein Problem darstellen, überflüssige Leerzeichen mittels eines Tools zu entfehrnen. Die Datenaubreitung gehört beim Import von Daten in der Regel dazu. Danach wird es auch keine Problem mit " with delimiter as ‘’ " geben.



mfg

fristo