Massen PHP substr und MySQL Insert

Seite 1 von 1 - Forum: Coding Stuff auf overclockers.at

URL: https://www.overclockers.at/coding-stuff/massen-php-substr-und-mysql-insert_245944/page_1 - zur Vollversion wechseln!


Umlüx schrieb am 11.04.2016 um 14:33

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? :D
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!


COLOSSUS schrieb am 11.04.2016 um 15:02

Rede ich eigentlich gegen eine Wand?

Code:
$ printf '%20s%20s%20s%20s\n' 1 2 3 4 > data_input
$ printf '%20s%20s%20s%20s\n' blah blub blaer foobar >> data_input

Code:
$ cat data_input 
                   1                   2                   3                   4
                blah                blub               blaer              foobar

Code:
$ 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);
}
?>

Code:
$ ./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 schrieb am 11.04.2016 um 15:15

ja ok die substr kann ich mit sscanf abkürzen, danke.
bleibt noch der insert in die db


Obermotz schrieb am 11.04.2016 um 15:28

Bulk Insert via
INSERT INTO table (a,b) VALUES (1,2), (2,3), (3,4);

Einfach mit prepared Statement: http://stackoverflow.com/a/12960624

Noch cooler:
https://dev.mysql.com/doc/refman/5.7/en/load-data.html


Umlüx schrieb am 11.04.2016 um 16:42

so, ich glaub ich hab jetzt halbwegs was wie ich mir das vorstelle.

hier ein gekürzter beispielstring aus einem der quellfiles:

Code:
$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...
Code: PHP
$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.
Code: PHP
$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
Code: PHP
$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


Crash Override schrieb am 11.04.2016 um 16:51

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 schrieb am 11.04.2016 um 16:54

danke für den tipp.
performance könnte bei 2mio+ zeilen eine sache werden. ich behalts mir im hinterkopf


kleinerChemiker schrieb am 11.04.2016 um 18:29

Entweder über LOAD DATA INFILE und davor das File anpassen, oder ansonsten würde ich auf alle Fälle mit Prepared Statements arbeiten.




overclockers.at v4.thecommunity
© all rights reserved by overclockers.at 2000-2025