Umlüx
Huge Metal Fan
|
als folgefrage zu meinem CSV problemthread: stellt euch vor, ihr müsst einen string in rund 90 (verschieden große) teile zerlegen und diese dann in eine MySQL tabelle schreiben. ich würd jetzt hergehen und den string mit 90 "substr" in 90 variablen zersetzen und diese 90 variablen danach in ein insert packen. und das dreimal für je drei verschiedene dateien. ...gibts da irgendwelche eleganteren, advanced methoden mit weniger schreibaufwand? die tabelle würde jedesmal truncated werden, also gibts vielleicht ja irgendwelche tricks um sie z.b. gleich autoamtisch aus einem array mit den 90 werten zu erstellen? irgendwas, was weniger nach anfänger aussieht und mich weiterbildet? danke!
Bearbeitet von Umlüx am 11.04.2016, 14:33
|
COLOSSUS
AdministratorGNUltra
|
Rede ich eigentlich gegen eine Wand?$ printf '%20s%20s%20s%20s\n' 1 2 3 4 > data_input
$ printf '%20s%20s%20s%20s\n' blah blub blaer foobar >> data_input
$ cat data_input
1 2 3 4
blah blub blaer foobar
$ cat demo.php
#!/usr/bin/env php5
<?php
$handle = @fopen("data_input", "r");
if ($handle) {
while (($buffer = fgets($handle, 4096)) !== false) {
$res = sscanf(trim($buffer), '%20s%20s%20s%20s', $a, $b, $c, $d);
print "a=$a b=$b c=$c d=$d\n";
}
if (!feof($handle)) {
echo "Error: unexpected fgets() fail\n";
}
fclose($handle);
}
?>
$ ./demo.php
a=1 b=2 c=3 d=4
a=blah b=blub c=blaer d=foobar
(Disclaimer: Ich kann kein PHP.) Achtung; der [ code ]-bbcode-Tag verschlingt Backslashes beim Rendern.
|
Umlüx
Huge Metal Fan
|
ja ok die substr kann ich mit sscanf abkürzen, danke. bleibt noch der insert in die db
|
Obermotz
Fünfzylindernazi
|
Bearbeitet von Obermotz am 11.04.2016, 15:53
|
Umlüx
Huge Metal Fan
|
so, ich glaub ich hab jetzt halbwegs was wie ich mir das vorstelle. hier ein gekürzter beispielstring aus einem der quellfiles: $string = "01VSPRI ALLE 25.07.201625.07.2016";
erst bau ich mir ein array mit der datensatzstruktur. hier hab ich die feldbezeichnungen, startposition und länge und datentyp für die mysql. davon gibts 90 stück... $data = array ("version" => array(0,2,'int'),
"aktion" => array(2,1,'varchar'),
"lieferant" => array(3,5,'varchar'),
"angebotsnummer" => array(14,10,'int'),
"benutzergruppe" => array(24,9,'varchar'),
"angebotstermin" => array(33,10,'varchar'),
"angebotsdauer" => array(43,10,'varchar')
);
dann lass ich mir die tabelle in der mysql datenbank bauen. ich werde wohl einfach immer eine tabelle für jedes file und jeden tag anlegen und mir die letzten 3 tage behalten. der rest wird gedropt. $keys = array_keys($data);
$query = "DROP TABLE IF EXISTS flugdaten".date("Ymd").";
CREATE TABLE flugdaten".date("Ymd")." (
id mediumint(8)";
foreach($keys as $key) {
$query .= ", $key ".$data[$key][2]."(".$data[$key][1].")";
}
$query .= ") ENGINE=MyISAM";
jetzt gehen wir das quellfile zeilenweise durch und zerlegen den string mit hilfe des definitionsarrays und bauen gleich das insert dazu $i=1;
$query = "INSERT INTO flugdaten".date("Ymd")." (id,".implode(",",$keys).") VALUES ( $i";
foreach($keys as $key) {
// get data from string
$value = substr($string,$data[$key][0],$data[$key][1]);
$query .= ", '$value'";
}
$query .= ")";
$i++;
umständlich? wirkt so gehts besser? bestimmt dafür kaum schreibarbeit bis auf die erstellung des definitions arrays
Bearbeitet von Umlüx am 11.04.2016, 16:44
|
Crash Override
BOfH
|
Hast du einen fortlaufenden Key? Dann währe eine eine Tabelle mit partitionierung einfacher. Für die Performance könnte es helfen, vor der Schleife ein "BEGIN;" abzusetzen und z.B. alle 100-1000 Schleifendurchläufe ein "COMMIT; BEGIN;" nach der Sleife dann noch ein "COMMIT;". Damit hast du nur eine Schreiboperation alle 100-1000 Einträge anstatt für jeden Eintrag.
|
Umlüx
Huge Metal Fan
|
danke für den tipp. performance könnte bei 2mio+ zeilen eine sache werden. ich behalts mir im hinterkopf
|
kleinerChemiker
Here to stay
|
Entweder über LOAD DATA INFILE und davor das File anpassen, oder ansonsten würde ich auf alle Fälle mit Prepared Statements arbeiten.
|