# CSV Import in MySQL



## gulo92 (13. März 2012)

Hi,

ich habe eine Funktion á la 

```
LOAD DATA LOCAL
        INFILE '/home/www/servers/www.servername.de/tmp/import.csv'
        REPLACE
        INTO TABLE tabellenname
        FIELDS
                TERMINATED BY ';'
                OPTIONALLY ENCLOSED BY '"';
```

um CSV-Daten in meine MySQL Datenbank zu importieren. Wie kann ich es schaffen, dass nur bestimmte Spalten eingesetzt werden. Heißt: Ich habe eine Tabelle mit Werten schon gefüllt und möchte nun zu den bestehenden Daten die per ID als Primärschlüssen durchnummeriert sind eine neue Spalte mit Werten füllen. Also ich habe eine Tabelle mit 'id' und 'name', welche ich bereits gefüllt habe mit Werten. Nun füge ich eine neue Spalte 'nachname' ein mit der ich die bestehenden Werte ergänzen möchte. An den Spalten 'id' und 'name' soll sich nichts ändern, aber die die neuen Daten sollen aus der CSV Datei in die  neue Spalte importiert werden.

Bin am Verzweifeln .. Danke für eure Hilfe.


----------



## syntax (13. März 2012)

Wenn ich das richtig verstehe, musst du die Werte die du nicht einfügen möchtest als @dummy deklarieren. Sommit werden diese Spalten in der CSV-Datei ignoriert.
Siehe Quellcode.


```
$sql = "LOAD DATA LOCAL INFILE '{$csv_datei}'
        INTO TABLE `{$tabelle}`
        FIELDS TERMINATED BY ';'
        OPTIONALLY ENCLOSED BY '\"'
        LINES TERMINATED BY '\n'
        IGNORE 1 LINES //ignoriert die erste Zeile der CSV-Datei
        ( @dummy, @dummy, kunde, mitarbeiter, taetigkeit, @startdatum, startzeit, @endedatum, endezeit, dauer, stundensatz, @umsatz, notizen, @dummy)

        SET startdatum = STR_TO_DATE(@startdatum, GET_FORMAT(DATE,'EUR')),
            endedatum = STR_TO_DATE(@endedatum, GET_FORMAT(DATE,'EUR')),
            umsatz = REPLACE(@umsatz, ',', '.')";
```


----------



## gulo92 (13. März 2012)

Okay, danke.

Aber überschreibt das nicht die bestehenden Datensätze mit leerem Inhalt?


----------



## syntax (13. März 2012)

Ich denke nicht da er die Spalten völlig ignoriert. Bin mir aber nicht sicher.

Am besten mal ausprobieren, bin auch kein Fachmann.


----------



## gulo92 (13. März 2012)

Hast das Skript selbst geschrieben oder ist das von einer Seite wo es noch erläutert ist kopiert?


----------



## syntax (13. März 2012)

http://www.tutorials.de/content/1403-mysql-dateieinlesung.html


----------



## Yaslaw (13. März 2012)

Ich denke du kommst nicht umhin die Daten zuerst in eine Stage-Tabelle zu laden und dann die Originaldaten mittels UPDATE um diese Informationen zu erweitern.


----------



## gulo92 (13. März 2012)

Wasn eine Stage Tabelle? Letztlich will ich ja nur updaten, aber es überschreibt mir immer die alten Daten ...


----------



## Yaslaw (13. März 2012)

'*Wasn*' das für eine Sprache? '*Was ist den*', wenn ich bitten darf - ansonsten fange ich auch mit Dialekt an.

Zum Thema.
LOAD DATA ist IMMER ein INSERT. Nie ein Update.

Eine Stage-Tabelle? Eine einfache Tabelle. In diese setzt du dein LOAD DATA ab. Wenn die Daten da drin sind, kannst du mit einem UPDATE deine Haubttabelle anpassen


----------



## gulo92 (13. März 2012)

Sorry Sorry ;-)

gibt es also noch eine Funktion in MySQL die anstatt LOAD DATA LOCAL einfach nur updatet? Hast du irgendwie einen Link, der mir zeigt, wie ich meine Tabelle updaten kann?

Danke!


----------



## Yaslaw (13. März 2012)

Direkt ab einem File? Nur so wie ich es beschreiben hab oder das File über PHP abarbeiten.
Link? UPDATE


----------



## guenter024 (15. März 2012)

Da der Thread noch nicht geschlossen ist und ich gerade ebenfalls nach einer Update-Funktion suche möchte ich das Thema gerne nochmal aufgreifen.

Mit LOAD DATA LOCAL INFILE habe ich soeben auch mein Glück (leider mit dem gleichen Ergebnis wie der Ersteller dieses Threads) versucht. 
Ich dachte zunächst ebenfalls, dass ich mit @dummy das Feld nicht anrühre... denkste 
So bin ich zufällig auf das Thema hier gestossen.


Jetzt bin ich am überlegen, wie ich das ganze mit PHP angehe.
Folgender - mal ganz einfach angedachter - Lösungsansatz:

Die Daten aus der csv mit explode und \n als delimiter in ein Array ablegen.
Beispiel:

```
$csvfile = "1','Birne','grün\n2','Erdbeere','rot";

$zeile = explode("\n",$csvfile);

// Ergebnis:
// Array
// (
//    [0] => 1','Birne','grün
//    [1] => 2','Erdbeere','rot
// )
```

Dann dieses Array durcharbeiten und die Einträge wieder mit explode und diesmal ',' als delimiter nacheinander mittels UPDATE in die Datenbank schreiben.

Beispiel:

```
foreach($zeile as $felder)
{
  $feld = explode("','",$felder);

  $sql="UPDATE obst SET Sorte='$feld[1]', Farbe='$feld[2]' WHERE ID='$feld[0]'";
  // SQL QUERY ..

}
```

Wenn man jetzt z.B. einen Eintrag unverändert lassen will schließt man diesen einfach aus dem UPDATE aus:


```
foreach($zeile as $felder)
{
  $feld = explode("','",$felder);

  $sql="UPDATE obst SET Farbe='$feld[2]' WHERE ID='$feld[0]'";
  // SQL QUERY ..

}
```


Müsste auf jeden Fall so klappen


----------



## Yaslaw (16. März 2012)

Warum selber mit explode() arbeiten und damit ev. Fehler einbauen weil ein Feld in " gesetzt ist?
PHP bietet da bereits die Funktion fgetcsv() an um eine csv-Datei zu parsen.
Oder str_getcsv() um einen CSV-String zu parsen


----------



## guenter024 (16. März 2012)

Ja, guter Tipp! 

Edit:
Ich bin jetzt echt am grübeln, ob ich das UPDATE via php mache.
Habe bislang immer mit der zusätzlichen Tabelle gearbeitet und von dort das UPDATE gestartet.
Aber das Datenbank Hin-und-Her-Geschiebe ist doch irgendwie immer nervig.
Daher wollte ich ja auch erst den Versuch mit LOAD DATA machen.

Wenn ich das PHP-Skript einmal ordentlich programmiert habe ist Ruh'.
Dann müsste ich nur noch das PHP-Skript aufrufen und fertig.

Via php die CSV starten oder mit der Stage-Tabelle?
Die Tabelle hätte den Vorteil, dass man erst gucken kann, ob alles gut in die Datenbank eingetragen wurde und danach das SQL-UPDATE macht.
Obwohl, das Skript könnte man ja auch erst in eine Stage-Tabelle laden und von dort dann das UPDATE starten.

Wie würdest du es machen Yaslaw?


----------



## Yaslaw (16. März 2012)

Da ich ein DB-Mensch bin, würde ich die DB nehmen.

Unter Umständen eine Stage-Tabelle die genau der Target-Tabelle entspricht. Dazu noch ein INSERT-Trigger, damit der Update gleich automatisch abläuft. 


```
CREATE TRIGGER TRG_STAGE
BEFORE INSERT ON stage_table FOR EACH ROW 
BEGIN  
	INSERT INTO 
		target_table (id, field1, field2)  
	VALUES (NEW.id, NEW.field1, NEW.field2)  
		ON DUPLICATE KEY UPDATE field2 = NEW.field2; 
END;
```

Es kommt wirklich drauf an, wie viele verschiedene Uploads es gibt, wie häufig man die Definitionen ändern muss etc.


----------

