Skriptbasiertes einlesen einer csv datei

Hallo miteinander,

leider bin ich komplett neu bei postgresql, aber ich denke dass man mein Problem mit einem geschickten Skript lösen kann. Würde mich freuen wenn mir jemand einen Tipp gibt.
Also:

in meiner CSVdatei liegen die Werte wie folgt vor:

[TABLE=“width: 500”]
[TR]
[TD]Zeitpunkt[/TD]
[TD]Wert A
[/TD]
[TD]Wert B
[/TD]
[TD]Wert C
[/TD]
[/TR]
[TR]
[TD]1:00
[/TD]
[TD]1,0
[/TD]
[TD]2,0
[/TD]
[TD]3,0
[/TD]
[/TR]
[TR]
[TD]1:01
[/TD]
[TD]1,5
[/TD]
[TD]2,1
[/TD]
[TD]2,7
[/TD]
[/TR]
[/TABLE]


Nach dem ausführen des Skripts sollen die Daten in einer Tabelle vorliegen wie:

[TABLE=“width: 500”]
[TR]
[TD]Zeitpunkt
[/TD]
[TD]Messpunkt
[/TD]
[TD]Wert
[/TD]
[/TR]
[TR]
[TD]1:00
[/TD]
[TD]A
[/TD]
[TD]1,0
[/TD]
[/TR]
[TR]
[TD]1:00
[/TD]
[TD]B
[/TD]
[TD]2,0
[/TD]
[/TR]
[TR]
[TD]1:00
[/TD]
[TD]C
[/TD]
[TD]3,0
[/TD]
[/TR]
[/TABLE]

Vielleicht hat jemand eine Idee oder kann mir sagen wo ich näheres zu so einem Problem nachlesen kann.
Würde mich sehr freuen.

vielen Dank

Ich würde eine Zwischentabelle anlegen:

create table stage_import
(
   zeitpunkt  time
   wert_a     decimal(12,2),
   wert_b     decimal(12,2),
   wert_c     decimal(12,2)
);

Dann die CSV Datei so wie sie ist in diese Zwischentabelle importieren (z.B. über COPY oder mit einem entsprechenden Tool).

Danach dann die Datensätze aus der Zwischentabelle in die “richtige” kopieren:

insert into zieltabelle (zeitpunkt, messpunkt, wert)
select zeitpunkt, 'A', wert_a
from stage_import
union all 
select zeitpunkt, 'B', wert_b
from stage_import
union all 
select zeitpunkt, 'C', wert_c
from stage_import;

Vielen Dank für den Hinweis, das hat so schon super funktioniert!

Allerdings habe ich noch ein weiteres Probleme…

Ich möchte zwecks Normalisierung gerne eine Tabelle in der nur die Messpunkte mit einer ID gelistet sind erstellen aus der ersten Zwischentabelle.
Also quasi nur die Namen der Spalten auflisten. Da die Tabelle sehr viele Spalten hat kann man sie nicht einfach per Hand übertragen. gibt es da eine Möglichkeit?

Vielen Dank

Sorry, verstehe ich nicht.

Von welche Namen sprichst Du, die man nicht “einfach per Hand übertragen” kann?

Naja, “Wert A”, “Wert B”, “Wert C” sind bei mir nicht drei Spalten, sondern ca. 50.000 und die möchte ich jetzt also in ein sql query bekommen ohne explizit ihre Namen hinschreiben zu müssen. :slight_smile:

Ähm, Moment mal … STOOOOOOOOOOP!

Du hast Tabellen mit 50.000 Spalten?

Bevor ich Dir sage, wie man die Kataloge auslesen kann, sagst Du mir, ob das stimmt und wenn ja, warum.

Andreas

Ich habe mehrere CSV Dateien, die in ein Datenbankschema konvertiert werden sollen. Jede CSV Datei hat ca. 100 Spalten und 1 bis 10 Millionen Zeilen. Im Endeffekt müssen alle CSV Dateien in eine Tabelle. Also nicht 50.000 aber immernoch recht viel. :slight_smile:

Btw. ist das importieren der CSV Dateien auch sehr anstrengend, weil der CREATE TABLE befehl für jede einzelne Spalte per Hand eingegeben werden muss.

Die Spaltennamen kannst Du aus information_schema.columns entnehmen. Aber da muß die Tabelle natürlich erst mal da sein. Nun weiß ich nicht, wie das da alles abläuft, vielleicht kannst das ja auch scripten. Wenn die CSV-Datien den Tabellen 1:1 entsprechen kannst die Spaltennamen ja auch weglassen.

Andreas

Vielen dank, kann ich irgendwie genauso auf alle Spalten ausgenommen der ersten Spalte zugreifen. Wenn ich alle Daten ohne die erste Spalte benötige?

ordinal_position. Mußt halt aus den Angaben Dir dynamisch Dein SQL basteln und via EXECUTE ausführen. Also mit einer pl/pgsql-Function arbeiten, SQL basteln, EXECUTE sql.

Andreas

Sry Leute, aber ich bekomms nicht hin. Im Grunde möchte ich doch nur:

SELECT columns_name FROM information_schema.columns WHERE table_name = 'myTable'

LOOP columns_name

insert into zieltabelle (zeitpunkt, "columns_name", wert)

END LOOP

zumindest im Pseudocode, hat da noch jemand nen Tipp oder Hinweis?
würde mich sehr freuen.

Ich schrieb doch, du mußt Dir eine Funktion schreiben.

Innerhalb dieser dann sowas wie:

test=*# \d foo;
      Table "public.foo"
 Column |  Type   | Modifiers
--------+---------+-----------
 c1     | integer |
 c2     | integer |
 c3     | integer |

test=*# select 'insert into zieltabelle (' || string_agg(column_name,',') || ')' from (select column_name from information_schema.columns where table_name = 'foo' and table_schema = 'public' order by ordinal_position)foo ;
              ?column?
------------------------------------
 insert into zieltabelle (c1,c2,c3)
(1 row)

Also, das natürlich so nicht in der Funktion, ich wollt nur zeigen, wie Du die Column-Names für die Tabelle foo aus den Katalogen sammelst und daraus einen String frickelst.

Andreas

Hallo nochmal,

ich habs jetzt folgendermaßen versucht:

insert into measurement (timestamp, sensor, value)
SELECT d."Timestamp", 
       ( SELECT s.id FROM sensor s WHERE s.name = spalten.column_name),
       ( SELECT spalten.column_name from sensor_list where "Timestamp" = d."Timestamp") 

FROM   sensor_list d, 
       (select column_name from information_schema.columns where table_name = 'sensor_list' AND column_name <> 'Timestamp' order by ordinal_position) spalten

Als Fehlermeldung bekomme ich aber: “FEHLER: Spalte »value« hat Typ numeric, aber der Ausdruck hat Typ information_schema.sql_identifier”

Alles andere funktioniert. “spalten.column_name” funktioniert also nur im where-teil der zeile darüber und nicht nach dem select-befehl. Kann mir jemand sagen warum da ein Typ information_schema.sql_identifier rauskommt und ob man es irgendwie auf den numischen messwert casten kann?

vielen Dank. Dann wäre ich auch fertig :wink: