Mit MySQL csv umstrukturieren

Alles, was PHP betrifft, kann hier besprochen werden.

Mit MySQL csv umstrukturieren

Postby mactoni » 12. November 2008 22:43

Möchte aus einer csv Datei (3 Spalten, über 1.000.000 Zeilen) eine andere, umstrukturierte csv Datei erstellen. Hier die Struktur der ersten Datei:

log_id------ variable ------ wert
__________________________________________________
1 ------ x001 ------ wert1_1
1 ------ x002 ------ wert1_2
1 ------ x003 ------ wert1_3
... ------ ..... ------ ......
1 ------ x100 ------ wert1_100
2 ------ x001 ------ wert2_1
2------ x002 ------ wert2_2
2------ x003 ------ wert3_3
.... ------ .....------ ...........
.... ------ ..... ------ ...........
350 ------ x099 ------ wert350_99
350 ------ x100 ------ wert350_100


und so soll die zweit und umstrukturierte Datei aussehen:

log_id------ x001 ------ x002------ .............x100
______________________________________________________
1 --------- wert1_1------ wert1_2 ------ wert1_100------
2 ------ --- wert2_1 ------ wert2_2------ wert2_100
3 ------ --- wert3_1 ------ wert3_2------ wert3_100
.. ------ ..... ------ ...... ------ ......
350 ------ wert350_1 ------ wert350_2 ------ wert350_100

In der neuen csv Datei sollen also die Variablenwerte aus der ersten csv als Spaltennamen stehen und die werte entsprechend log_id und wert als Datensatz eingefügt werden.
Werde die csv mit PHP über fgetcsv() einlesen. Hoffe ich konnte mein Problem verständlich darlegen.
Kann mir jemand mit dem mysql Code helfen, habe davon kaum Ahnung?

Gruß
mactoni
mactoni
 
Posts: 3
Joined: 12. November 2008 22:41

Postby glitzi85 » 13. November 2008 00:32

1) Warum gerade mit MySQL?
2) Mit fgetcsv geht das nicht, da delimiter nur 1 Zeichen sein darf
3) Mit 1M Zeilen könntest du leichte Probleme mit der Laufzeit des PHP-Scripts bekommen

Wenn es unbedingt PHP sein muss, dann musst du die Datei quasi Zeilenweise einlesen (halt über die normale fgets-Funktion) und manuell mit explode splitten. Dann kannst dir zwar überlegen ob du die Daten in ne Datenbank haust, kannst aber auch einfach in ein Array speichern und am Ende direkt wieder ausgeben.

Was du auf jeden Fall hochstellen musst ist die Scriptlaufzeit, höchstwahrscheinlich auch das Speicherlimit von PHP (bei der Array-Version auf jeden Fall).

mfg glitzi
User avatar
glitzi85
 
Posts: 1920
Joined: 05. March 2004 23:26
Location: Dahoim

Postby mactoni » 13. November 2008 08:59

Hallo glitzi,
erstmal Danke für die Antwort.

1) Denke das es mit MySQL schneller geht als mit PHP
2) ?
3) Was wäre denn die schnellste Lösung, nicht MySQL? Die derzeitige Lösung benötigt über 4h und das ist nicht akzeptabel.

Gruß
mactoni
mactoni
 
Posts: 3
Joined: 12. November 2008 22:41

Postby Nobbie » 13. November 2008 13:14

Wie sieht denn die derzeite Lösung aus?
Nobbie
 
Posts: 13170
Joined: 09. March 2008 13:04

Postby glitzi85 » 13. November 2008 13:36

mactoni wrote:1) Denke das es mit MySQL schneller geht als mit PHP

MySQL ist erstmal nur eine Datenbank, damit kannst du hier gar nichts anfagngen. Du brauchst immer eine Programmiersprache mit der du auf die Datenbank zugreifst (über die Zugriffssprache SQL).

mactoni wrote:2) ?

OK, natürlich kannst du auch einfach - als Trennzeichen angeben, dein Array vergrößert sich dann natürlich stark dadurch, da ja die Werte zwischen den Bindestrichen auch ein Feld benötigen (auch wenn da nichts drinsteht).

mactoni wrote:3) Was wäre denn die schnellste Lösung, nicht MySQL? Die derzeitige Lösung benötigt über 4h und das ist nicht akzeptabel.

Wie Nobbie schon geschrieben hat wäre es interessant zu wissen wie die bisherige Lösung aussieht. Muss es denn unbedingt online sein? Mit VB wäre das ganze recht einfach zu lösen und würde garantiert keine 4 Stunden laufen. Mit C wird's zwar komplizierter, aber auch um einiges schneller.

mfg glitzi
User avatar
glitzi85
 
Posts: 1920
Joined: 05. March 2004 23:26
Location: Dahoim

Postby Nobbie » 13. November 2008 14:40

Ich habe mal ein kleines PHP Script geschrieben, Namen und Delimiter kann man oben einfach anpassen - das läuft auf meinem Rechner (Core2Duo E6300 mit 1,8GHz) etwa 6 - 7 Sekunden(!!) um eine Datei mit 1.000.000 Datensätzen umzuformatieren:

Code: Select all
<?php
   $infile = 'csv_in.csv';
   $outfile = 'csv_out.csv';
   $delimiter = ';';

   if (!($fd = fopen($infile, 'r')))
      die("Failed to read $infile");


   if (!($fdout = fopen($outfile, 'w')))
      die("Failed to create $outfile");

   $ar = array();
   $old_log_id = 0;

   while ($buffer = fgets($fd, 4096)) {
      $buffer = trim($buffer);
      list($log_id, $col, $val) = explode($delimiter, $buffer);

      if ($log_id != $old_log_id) {

         if (!empty($ar)) {

            $ar = array_values($ar);
            $line = implode($delimiter, $ar);
            $line = $old_log_id.";".$line."\n";

            if (!fwrite($fdout, $line))
               die("Write '$line' failed");

            unset($ar);
            $ar = array();

         }

         $old_log_id = $log_id;
      }

      $ar[$col] = $val;
   }

   fclose($fd);
   fclose($fdout);

   echo "Fertig!";
?>
Nobbie
 
Posts: 13170
Joined: 09. March 2008 13:04

Postby mactoni » 14. November 2008 08:52

@Nobbie
Vielen vielen Dank für dein Script!!
Deine PHP-Lösung schafft es auch bei mir in wenigen Sekunden. Mein erstes Script war wohl sehr sehr schlecht programmiert, bin eh noch blutiger Anfänger.
Es werden bei mir aber leider keine Spaltenüberschriften in die csv geschrieben.
Gehe ich Richtig in der Annahme das dies hier passieren soll: $ar[$col] = $val; ? Über den Spalten sollte log_id und dann x001 - x100 stehen. Bei mir steht nur 0 val.

Gruß
mactoni
mactoni
 
Posts: 3
Joined: 12. November 2008 22:41

Postby Nobbie » 14. November 2008 11:26

>Es werden bei mir aber leider keine Spaltenüberschriften in die csv geschrieben.

Dann baue es doch ein - das ist nun wirklich das allerleichteste.

>Gehe ich Richtig in der Annahme das dies hier passieren soll: $ar[$col] = $val; ?

Nein, das soll dort nicht passieren. Ich habe einfach nicht gewußt, dass Überschriften benötigt werden, deswegen habe ich auch keine ausgegeben.

Du brauchst doch einfach nur vor der ersten Ausgabe der Werte die Namen der Spalten in die Datei zu schreiben - wie wäre es, wenn Du das mal selbst versuchst? Im Array $ar stehen als Schlüssel die Spaltennamen drin und als Werte die Spaltenwerte. Bislang gibt das Script eben nur die Werte aus - nun mußt Du ein einziges Mal auch noch vorher die Namen ausgeben.

P.S.: Jetzt verstehe ich das erst mit dem "0 val" - mein Script geht weiterhin davon aus, dass auch in der Eingabedatei keine Spaltennamen in der ersten Zeile stehen, sondern dass nur Werte drin stehen. Du mußt also das Script auch noch dahingehend erweitern, dass die erste Zeile ignoriert wird (bzw. nur der Namen "log_id" o.ä. ermittelt wird - falls dieser nicht sowieso feststeht).
Nobbie
 
Posts: 13170
Joined: 09. March 2008 13:04


Return to PHP

Who is online

Users browsing this forum: No registered users and 17 guests