ubuntuusers.de

CSV to MySQL Import

Status: Gelöst | Ubuntu-Version: Ubuntu 12.04 (Precise Pangolin)
Antworten |

elecsun

Anmeldungsdatum:
18. April 2016

Beiträge: Zähle...

Wohnort: Dessau-Roßlau

Hallo,

ich benötige zum Einlesen von Messwerten ein Skript, welches mehrere csv-Dateien in die lokale MySQL-DB importieren kann. Die Dateien werden dabei durch weitere Skripte bereits vorformatiert und teilweise werden die Dateinamen angepasst.

Die Dateinamen sehen wie folgt aus:

Stromschiene 1_Avg_2016-03-08.csv
Stromschiene 2_Avg_2016-03-10.csv
...

Die CSV-Dateien selbst haben folgenden Aufbau

2016-04-08T00:04:01,50020,23243,23248,23274,97889,83145,106857,951,63188,20627,
2016-04-08T00:03:00,50030,23244,23259,23281,97765,83452,106734,951,63220,20614,
2016-04-08T00:02:00,50030,23228,23231,23252,98144,83079,106656,951,63178,20486,
2016-04-08T00:01:00,50040,23246,23249,23274,97967,83100,106803,951,63207,20569,
2016-04-08T00:00:00,50040,23251,23251,23285,97999,83202,107063,951,63283,20681,
...

Und zu guter Letzt das Skript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#! /bin/bash

# ausgeführte Befehle anzeigen
set -x

# Daten der DB-Anbindung
_db="xxx"
_db_user="yyy"
_db_password="zzz"

# Verzeichnis in dem die Dateien liegen
_csv_directory="/srv/ftp/test"

# ins Verzeichnis wechseln
cd $_csv_directory

for f in *.csv
do
        # Tabellennamen aus Dateinamen bilden
        a=`echo ${f##*/}`
        _table_name=`echo ${a%_*}`

        # CSV nach MySQL importieren
        mysql -e "LOAD DATA LOCAL INFILE '"$f"' INTO TABLE '"$_table_name"' " --user=$_db_user --password=$_db_password $_db

done

exit 0

Nun muss ich aus dem Dateinamen jeder einzelnen CSV-Datei auf den Namen der Tabelle in der Datenbank kommen. Dies geschieht in Zeile 20 und 21. Aus diesen Daten versuche ich den mysql-Befehl zu bilden. Dies schlägt leider fehl.

Hier die Ausgabe aus der Konsole:

+ for f in '*.csv'
++ echo Stromschiene 2_Avg_2016-03-10.csv
+ a='Stromschiene 2_Avg_2016-03-10.csv'
++ echo Stromschiene 2_Avg
+ _table_name='Stromschiene 2_Avg'
+ mysql -e 'LOAD DATA LOCAL INFILE '\''Stromschiene' '2_Avg_2016-03-10.csv'\'' INTO TABLE '\''Stromschiene' '2_Avg'\'' ' --user=yyy --password=zzz xxx
mysql  Ver 14.14 Distrib 5.5.47, for debian-linux-gnu (x86_64) using readline 6.3
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Usage: mysql [OPTIONS] [database]
  -?, --help          Display this help and exit.
  -I, --help          Synonym for -?
...

Da ich an dieser Stelle mit meinem Latein am Ende bin, würde ich mich über Hilfe sehr freuen.

Viele Grüße elecsun

ChickenLipsRfun2eat Team-Icon

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12067

Hallo!

Also mir fällt auf Anhieb nur auf, dass du offenbar Leerzeichen im Tabellennamen hast. Das funktioniert zwar in mysql, aber du müsstest den Tabellennamen in backticks verpacken. Die Diskussion ob Leerzeichen im Namen sind, fange ich mal nicht an, das ist ja dein Problem ☺

Zudem wäre ein

1
2
3
4
_table_name=$(echo ${f$_*})

#oder ohne Leerzeichen
_table_name=$(echo ${f// /_})

zeitgemäß.

elecsun

(Themenstarter)

Anmeldungsdatum:
18. April 2016

Beiträge: 5

Wohnort: Dessau-Roßlau

Wenn ich zu Testzwecken die Datei und die Tabelle so umbenenne, dass die Leerzeichen verschwinden und beide fest an die Variablen zuweise,

1
2
3
4
5
6
...
f="Stromschiene1_Avg_2016-03-08.csv"
_table_name="Stromschiene1_Avg"

mysql -e "LOAD DATA LOCAL INFILE '"$f"' INTO TABLE '"$_table_name"' " --user=$_db_user --password=$_db_password $_db
...

ist das Ergebnis folgendes:

+ f=Stromschiene1_Avg_2016-03-08.csv
+ _table_name=Stromschiene1_Avg
+ mysql -e 'LOAD DATA LOCAL INFILE '\''Stromschiene1_Avg_2016-03-08.csv'\'' INTO TABLE '\''Stromschiene1_Avg'\'' ' --user=yyy --password=zzz xxx
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''Stromschiene1_Avg'' at line 1
+ exit 0

Leider kann ich diesen Fehler nicht zuordnen.

ChickenLipsRfun2eat Team-Icon

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12067

Wie ist denn der Datenbankname?

1
2
3
4
#sollte so aussehen:
LOAD DATA INFILE 'Stromschiene1_Avg_2016-03-08' INTO TABLE DataBaseName.Stromschiene1_Avg;
#also:
mysql -e "LOAD DATA LOCAL INFILE 'Stromschiene1_Avg_2016-03-08.csv' INTO TABLE [Datenbankname].'Stromschiene1_Avg';" --user=yyy --password=zzz xxx

EDIT: Bei mir scheint das hier zu klappen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#! /bin/bash

# ausgeführte Befehle anzeigen
#set -x

# Daten der DB-Anbindung
_db="Alfred"
_db_user="schiggn"
_db_password="abcdefg"

# Verzeichnis in dem die Dateien liegen
_csv_directory="/home/schiggn/csvtest"

# ins Verzeichnis wechseln
cd $_csv_directory

for f in *.csv
do
        # Tabellennamen aus Dateinamen bilden
	_table_name=${f%.*} #extension weg
	_table_name=$(echo "${_table_name// /_}") #Leerzeichen durch _ ersetzen
	_table_name=$(echo "${_table_name//-/_}") #- durch _ ersetzen

        # CSV nach MySQL importieren
         mysql -e "LOAD DATA LOCAL INFILE '$f' INTO TABLE $_db.$_table_name;" --user=$_db_user --password=$_db_password
done

//nochn edit: Kürzer geht das mit dem Tabellennamen so:

1
_table_name="$(echo -e "${f%.*}" | tr -d '[[:space:]]')"

elecsun

(Themenstarter)

Anmeldungsdatum:
18. April 2016

Beiträge: 5

Wohnort: Dessau-Roßlau

Hallo und vielen dank für deine Hilfe. So bin ich schlussendlich zu einem lauffähigen Skript gekommen. Für Alle, die ein ähnliches Problem zu lösen haben, hier das Ganze als Listing:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#! /bin/bash

# ausgeführte Befehle anzeigen
set -x

# Daten der DB-Anbindung
_db="xxx"
_db_user="yyy"
_db_password="zzz"

# Verzeichnis in dem die Dateien liegen
_csv_directory="/srv/ftp/test"

# ins Verzeichnis wechseln
cd $_csv_directory

for f in *.csv
do
        # Tabellennamen aus Dateinamen bilden
        _table_name=${f%.*} #extension weg
        _table_name=${f%_*}
        _table_name=$(echo "${_table_name// /_}") #Leerzeichen durch _ ersetzen
        _table_name=$(echo "${_table_name//-/_}") #- durch _ ersetzen

#       _table_name="$(echo -e "${f%.*}" | tr -d '[[:space:]]')"

        # CSV nach MySQL importieren
         mysql -e "LOAD DATA LOCAL INFILE '$f' INTO TABLE $_db.$_table_name
                FIELDS TERMINATED BY ','
                LINES TERMINATED BY '\n'
                (date, @var_a, @var_b, @var_c, @var_d, @var_e, @var_f, @var_g, @var_h, i, k)
                SET ID = NULL, a = @var_a / 1000, b = @var_b / 100, c = @var_c / 100, d = @var_d / 100, e = @var_e / 100, f = @var_f / 100, g = @var_g / 100, h = @var_h / 1000;
                " --user=$_db_user --password=$_db_password --local-infile

done

exit 0

Die Zeile 32 die nur der korrekten Skalierung der Daten, da diese nur als Rohdaten angegegen sind.

@ChickenLipsRfun2eat: Hast eventuell einen Link wo diese Befehle zum umformatieren des Dateinamens zu finden sind? Deine verkürzte Form war mir bisher unbekannt.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Noch 3 Anmerkungen handwerklicher Art zu Deinem Skript:

  1. Du solltest unbedingt konsequent sauber "quoten", damit es bei Leerzeichen im Dateipfad nicht zu bösen Überraschungen kommt.
    Das betrifft bei Deinem Skript die Zeilen 15, 20-23, 28 und evtl. 33.

  2. Die $(echo ...) - Konstruktionen (Zeile 22/23) sind überflüssig. Nimm einfach direkt die Parameter Expansions und gut is': _table_name="${_table_name// /_}"

    • und: die Zeilen 20-24 könntest Du auch noch zusammenfassen, wenn Du klassenweise ersetzt:

              _table_name=${f%[._]*}
              _table_name="${_table_name//[- ]/_}"
  3. Das exit 0 am Ende ist Blödsinn. Es bringt nix, außer dass Du im Fehlerfall den Rückgabwert Deines Skriptes nicht mehr auswerten kannst.
    Denn der ist dann garantiert immer 0.

LG,

track

Edit: Unterpunkt eingefügt.

elecsun

(Themenstarter)

Anmeldungsdatum:
18. April 2016

Beiträge: 5

Wohnort: Dessau-Roßlau

Danke für deine Hinweise.

  • zu 1: Da ich mit solchen Skripten gerade anfange, ist mir nicht klar wo genau die Fehler liegen. Wenn ich die Anführungszeichen an dem mysql-Befehl ändere funktioniert er bei mir nicht mehr.

  • zu 2: Die echo-Konstrukte habe ich entfernt, leider funktioniert deine Ersetzung nicht - Der Datumsteil wird nicht abgeschnitten. Da ich von der Arbeit aus leider nicht auf die Webseite zugreifen kann, muss das wohl bis später warten.

  • zu 3: Ist entfernt.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

elecsun schrieb:

  • zu 1: Da ich mit solchen Skripten gerade anfange, ist mir nicht klar wo genau die Fehler liegen. Wenn ich die Anführungszeichen an dem mysql-Befehl ändere funktioniert er bei mir nicht mehr.

Da hast Du Recht. Ich hatte in Zeile 28 nicht genau geguckt: das hattest Du schon richtig, meine Korrektur war Quatsch.
In Zeile 33 sollten allerdings User und Passwort doch besser "gequotet" werden, damit ein Leerzeichen kein Unglück verursacht.

  • zu 2: Die echo-Konstrukte habe ich entfernt, leider funktioniert deine Ersetzung nicht - Der Datumsteil wird nicht abgeschnitten.

Oh, dann hatte ich da was nicht verstanden. Wenn er immer nach dem letzten "_" abschneiden soll, dann könnte das z.B. so gehen:

track@track:~$ f="Stromschiene 1_Avg_2016-03-08.csv"
track@track:~$ echo "${f%_*}"
Stromschiene 1_Avg
track@track:~$ _table_name="${f%_*}"
track@track:~$ _table_name="${_table_name//[- ]/_}"
track@track:~$ echo "$_table_name"
Stromschiene_1_Avg 

Es ist ohnehin ratsam, immer auch mal die Zwischenschritte probeweise mit auszugeben. Dann sieht man wenigstens, was da jeweils geschieht.

LG,

track

Antworten |