2016-09-02 2 views
0

Also bin ich ein ziemlich großer Neuling in der Programmierung und ich lerne etwas von Trial and Error, dieses Mal versuche ich mit einer DB mit Perl zu arbeiten, eigentlich funktioniert es gut, wenn ich nur 3 Tabellenköpfe benutze (Terminal, Zeitstempel , Ergebnisnummer), aber wenn ich versuche, weitere Header hinzuzufügen (Ergebnistext, Transart, Belegnummer, Trace, Bericht, Kartenart, Kartennummer, Entrymode) gibt es immer einen Syntax-Fehler und ich habe eine halbe Stunde gecheckt, konnte aber den Fehler nicht finden. Wenn jemand weiß, warum ich Ihre Hilfe zu schätzen wüsste! dieser Teil meines Codes sieht wie folgt aus:Warum gibt MySQL mir einen Syntaxfehler?

  foreach $file (@file) 
     { 
      $currentfile = "$currentdir\\$file"; 
      open(zloop, "<", $currentfile) or die "Failed to open file: $!\n"; 
        while (<zloop>) { 
        my %row; 
        chomp; 
        @row{@headers} = split /;/; 
        my $tid = $row{'tid'}; 
        my $zeit = $row{'zeit'}; 
        my $ergebnisnummer = $row{'ergebnisnummer'}; 
        my $ergebnistext = $row{'ergebnistext'}; 
        my $transart = $row{'transart'}; 
        my $belegnummer = $row{'belegnummer'}; 
        my $trace = $row{'trace'}; 
        my $betrag = $row{'betrag'}; 
        my $kartenart = $row{'kartenart'}; 
        my $kartennummer = $row{'kartennummer'}; 
        my $entrymode = $row{'entrymode'}; 

    my $sth = $dbh->prepare("INSERT INTO `teso`(Terminal, Zeitstempel, Ergebnisnummer, Ergebnistext, Transart, Belegnummer, Trace, Betrag, Kartenart, Kartennummer, Entrymode) 
    values ($tid, $zeit, $ergebnisnummer, $ergebnistext, $transart, $belegnummer, $trace, $betrag, $kartenart, $kartennummer, $entrymode)"); 
    $sth->execute() or die $DBI::errstr; 
    $sth->finish(); 

ich habe nicht die Variablennamen in Englisch ändern, weil vielleicht sind sie die Syntaxfehler verursacht. Dies ist die Fehlermeldung:

DBD :: mysql :: st ausführen fehlgeschlagen: Sie haben einen Fehler in Ihrer SQL-Syntax; Überprüfen Sie das Handbuch, das Ihrer MySQL-Serverversion für die richtige Syntax für die Verwendung in der Nähe von '') in Zeile 2 unter C: \ Benutzer \ Desktop \ findlogstamp \ sqlneu.pl Zeile 50, Zeile 1. Sie habe einen Fehler in deiner SQL-Syntax; Sie in der Bedienungsanleitung für die richtige Syntax zu verwenden in der Nähe von '')‘in Linie 2 bei C bis MySQL-Server-Version entspricht: \ User s \ Desktop \ findlogstamp \ sqlneu.pl Linie 50, Linie 1.

+0

hilft Was ist der Fehler? – mwp

+2

Erstellen einer SQL-Anweisung durch Interpolieren von Variablen in eine Zeichenfolge ist in der Regel eine sehr schlechte Idee - Siehe [Bobby Tables] (http://bobby-tables.com/) für Details. –

Antwort

7

Sie erhalten möglicherweise Angebotsfehler, die sich aus der Übergabe Ihrer Variablen als String ergeben. Sie sollten stattdessen Platzhalter verwenden.

versuchen, etwas wie diese stattdessen tun:

my $sth = $dbh->prepare('INSERT INTO `teso`(Terminal, Zeitstempel, Ergebnisnummer, Ergebnistext, 
    Transart, Belegnummer, `Trace`, Betrag, Kartenart, Kartennummer, Entrymode) 
    values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); 
$sth->execute($tid, $zeit, $ergebnisnummer, $ergebnistext, 
    $transart, $belegnummer, $trace, $betrag, $kartenart, 
    $kartennummer, $entrymode) or die $DBI::errstr; 

Ich habe auch mwp's answer too.

Es lohnt sich auch lesen Borodins Answer für eine gründlichere Möglichkeit, Platzhalter und SQL in Perl zu nähern.

+0

das funktionierte, vielen Dank, würde es Ihnen etwas ausmachen zu erklären, was genau falsch gelaufen ist? Meine Variablen sind meistens volle Zahlen, aber 2-3 sind entweder Zeichenketten oder Variantentypen. Ich dachte, sie würden mit '' 'markiert werden. –

+1

Sie müssen die Dinge genau zitieren, damit MySQL glücklich ist, sie zu verarbeiten. Wenn Sie Bind-Variablen (das '' 'in' prepare() ') verwenden und dann Ihre Werte an' execute() 'übergeben, wird das" Heavy Lifting "des Zitatens dort vorgenommen, wo es für Sie benötigt wird. Im Allgemeinen wird empfohlen, Variablen an Anweisungen zu übergeben. –

+0

Und für die Aufzeichnung, meinte ich Platzhalter, keine Variablen binden, sie sind verschiedene Dinge! –

3

Ich glaube, "Trace" ist ein reserviertes Wort in MySQL. Versuchen Sie, Backticks um die Spaltennamen hinzuzufügen.

+0

Würde es nicht herausfinden, dass es nur Spaltennamen innerhalb eines 'INSERT INTO foo (...)' Konstrukts haben kann? – simbabque

+1

Das wäre nett, aber leider nicht. – mwp

+0

ye, hatte ich einen Fehler, bevor das durch die Spalte "Terminal-ID" verursacht wurde, verursachte die -ID Probleme, brauchte 1 Stunde, um zu realisieren, also habe ich versucht, Spuren in '' schon zu setzen, aber es hat leider nicht funktioniert, danke für die gute Antwort aber! –

0

Ich denke, Fehler ist, weil Backticks um teso von Perl interpoliert wird. Wie auch immer, die Interpolation von Werten in eine Abfragezeichenfolge ist eine wirklich schlechte Idee. Sie können Anführungszeichen um Ihre Abfrage durch einfache Anführungszeichen ersetzen (um unerwünschte Interpolationen zu vermeiden) und Werte ersetzen, die mit Platzhaltern eingefügt werden sollen. Dann sollten Sie die tatsächlichen Werte an die Methode execute() übergeben. Wie folgt aus:

my $sth = $dbh->prepare('INSERT INTO teso(Terminal, Zeitstempel, Ergebnisnummer, Ergebnistext, Transart, Belegnummer, Trace, Betrag, Kartenart, Kartennummer, Entrymode) 
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); 
$sth->execute($tid, $zeit, $ergebnisnummer, $ergebnistext, $transart, $belegnummer, $trace, $betrag, $kartenart, $kartennummer, $entrymode) or die $DBI::errstr; 
$sth->finish(); 

oder, wenn Sie nur eine einzige Zeile einfügen möchten, können Sie dies alles mit einer einzigen ersetzen können():

$dbh->do('INSERT INTO teso(Terminal, Zeitstempel, Ergebnisnummer, Ergebnistext, Transart, Belegnummer, Trace, Betrag, Kartenart, Kartennummer, Entrymode) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', undef, 
    $tid, $zeit, $ergebnisnummer, $ergebnistext, $transart, $belegnummer, $trace, $betrag, $kartenart, $kartennummer, $entrymode) or die $DBI::errstr; 
+2

Ihre erste Annahme ist falsch. Perl läuft in Backticks nichts, was in den Anführungszeichen steht. Die Interpolation funktioniert nicht so. – simbabque

+0

@simbabque, du hast absolut recht! Aktualisierte Antwort –

1

Werte in einem SQL-Ausdruck muss korrekt angegeben werden . Einfache numerische Werte müssen nicht zitiert werden, und ich stelle mir vor, dass die ersten drei Spalten - Terminal-ID, Zeitstempel und Ergebnisnummer - alle Zahlen sind, weshalb sie ohne Anführungszeichen funktionierten

Das DBI Modul bietet Funktionen Datenbank Handle-Methode quote, die dies für Sie tun wird (sowie quote_identifier, die das Gleiche für Kennungen, wie Tabellen- und Spaltennamen tut).Es ist jedoch immer viel sicherer prepare eine SQL-Anweisung mit Platzhalter anstatt zu versuchen, die Werte in die Zeichenfolge selbst zu interpolieren. Dann werden die Ist-Werte können im execute Aufruf zur Verfügung gestellt werden, wehen DBI implizit $dbh->quote auf alle Werte nennen, bevor sie in die Aussage

Einfügen Es ist auch am besten zu prepare eine Erklärung nur einmal, wie der Griff kann dann wiederholt verwendet werden. Und es ist nicht notwendig, eine Reihe von skalaren Variablen aus Ihrem %row Hash zu extrahieren - ein Hash-Slice kann verwendet werden, um die richtigen Felder direkt aus dem Hash in den execute Aufruf zu holen. Es ist jedoch am besten, eine Liste der Feldnamen in einem Array zu führen, wie Sie es mit @headers getan haben; in der Tat das gleiche sein wie meine @items, Ihre @headers kann in diesem Fall gibt es keine Notwendigkeit, sowohl

zu definieren, die ich hier verwendet habe, ein für die SQL-Zeichenfolge dokumentieren. Wenn Sie das gleiche tun wollen, dann vorsichtig sein, dass es entweder kein Leerraum vor oder nach dem End-Tag sein muss END_SQL sonst wird es nicht

Bitte beachte, dass ich join gefunden wird zusammen mit der Liste verwendet habe Wiederholungsoperator x, um genau die richtige Anzahl von Fragezeichen-Platzhaltern in der QSL zu erzeugen. Es ist viel sicherer, Dinge auf diese Weise zu tun, um eine Fehlzählung zu vermeiden und die Anzahl der Felder zu ändern, ohne die SQL-Anweisung zu ändern. Sie können print "$sql\n" die SQL, um zu sehen, dass, wenn Sie

wünschen gebaut wurde ich hoffe, diese

my @items = qw/ 
    tid zeit ergebnisnummer ergebnistext transart 
    belegnummer trace betrag kartenart kartennummer entrymode 
/; 

my $sql = sprintf <<END_SQL, join ', ', ('?') x @items; 
INSERT INTO teso (
    Terminal, Zeitstempel, Ergebnisnummer, Ergebnistext, Transart, 
    Belegnummer, Trace, Betrag, Kartenart, Kartennummer, Entrymode 
) 
VALUES (%s) 
END_SQL 

my $insert = $dbh->prepare($sql); 

for my $file (@file) { 

    my $current_file = "$currentdir\\$file"; 

    open my $fh, '<', $current_file or die qq{Unable to open "$current_file" for input: $!}; 

    while (<$fh>) { 

     my %row; 
     @row{@headers} = split /;/; 

     $insert->execute(@row{@items}) or die $sth->errstr; 
    } 
} 
Verwandte Themen