Gustl: SQL Syntax-Error

Welcher Fehler ist in dieser Syntax: Ich find keinen krieg aber trotzdem einen Syntax-Fehler angezeigt:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'alter,sex,teilnahme,email,datum) VALUES ('1004','anonym','a','a','a','a','a','2'' at line 1 at zum_ausflippen.pl line 37.

my $dbh=DBI->connect("DBI:mysql:base:localhost","base",'aha') or die "Fehler bei der Datenbankverbindung: $DBI::errstr";  
  
  my $insert=$dbh->prepare("INSERT INTO teilnehmer (lfdnr,ano,vorname,zuname,strasse,plz,ort,alter,sex,teilnahme,email,datum) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)") || die $DBI::errstr;  
  $insert->execute($lfn,$ano,$vorname,$zuname,$strasse,$plz,$ort,$alter,$sex,$teilnahme,$email,$unix) || die $DBI::errstr;

Was kann das sein ? Ich kann UPDATE aber nicht INSERT. Der selbe Syntax läuft an anderer Stelle mit anderer DB auf dem selben Server.

Gustl

  1. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'alter,sex,teilnahme,email,datum) VALUES ('1004','anonym','a','a','a','a','a','2'' at line 1 at zum_ausflippen.pl line 37.

    Da stimmt was nicht mit der Anzahl der Argumente.

    Zudem ist es vorteilhaft statt irgendwelchem Programmcode das tatsächlich versandte SQL-Statement hier einzureichen.

    Damit man weiss was man hat.

    1. echo $begrüßung;

      You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'alter,sex,teilnahme,email,datum) VALUES ('1004','anonym','a','a','a','a','a','2'' at line 1 at zum_ausflippen.pl line 37.

      Da stimmt was nicht mit der Anzahl der Argumente.

      Das ist irrelevant. Das Problem wurde auch so deutlich. Wenn es ein Parameteranzahl-Problem gegeben hätte, wäre das durch eine andere Fehlermeldung und nicht durch einen Syntax-Fehler angezeigt worden.

      Zudem ist es vorteilhaft statt irgendwelchem Programmcode das tatsächlich versandte SQL-Statement hier einzureichen.

      Das war das tatsächlich versandte SQL-Statement. Und es wurde durch den ebenfalls angegebenen Programmcode auch nicht mehr verändert. Bei Prepared Statements ist es üblich, den Befehl inklusive Platzhaltern und die Daten getrennt zu versenden. Alles weitere ist Sache der DB und vom Benutzer nicht zu beeinflussen. Selbst wenn er wollte bekommt er ein zusammengesetztes Statement gar nicht zu Gesicht. Vermutlich wird sich MySQL auch nicht die Mühe machen, das vorbereitete Statement mit den Daten zu verbinden und es nochmal neu zu parsen. Denn das würde den Vorteil Prepared Statements zunichte machen.

      echo "$verabschiedung $name";

      1. Denn das würde den Vorteil Prepared Statements zunichte machen.

        LOL - was es schon alles gibt für MySQL. http://dev.mysql.com/doc/refman/5.0/en/sqlps.html

        Erinnert uns an den kleinen Bruder einer stored procedure (die es mittlerweile natürlich auch schon gibt unter MySQL).

        Bleibt nur noch die Frage warum MySQL nicht direkt das PREPARE angemängelt hat.

        1. echo $begrüßung;

          Bleibt nur noch die Frage warum MySQL nicht direkt das PREPARE angemängelt hat.

          Die Fehlermeldung wurde wegen Misslingens der Funktion $dbh->prepare() ausgegeben. Dabei kommt aber kein PREPARE-Statement zur Anwendung. Stattdessen werden Funktionen der MySQL-API verwendet, die sich um das PS-Handling direkt kümmern.

          echo "$verabschiedung $name";

          1. Bleibt nur noch die Frage warum MySQL nicht direkt das PREPARE angemängelt hat.

            Die Fehlermeldung wurde wegen Misslingens der Funktion $dbh->prepare() ausgegeben.

              
            my $dbh=DBI->connect("DBI:mysql:base:localhost","base",'aha') or die "Fehler bei der Datenbankverbindung: $DBI::errstr";  
            my $insert=$dbh->prepare("INSERT INTO teilnehmer (lfdnr,ano,vorname,zuname,strasse,plz,ort,alter,sex,teilnahme,email,datum) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)") || die $DBI::errstr;  
            $insert->execute($lfn,$ano,$vorname,$zuname,$strasse,$plz,$ort,$alter,$sex,$teilnahme,$email,$unix) || die $DBI::errstr;  
            
            

            Die Fehlermeldung kommt ja wohl ganz offenkundig aus dem execute():
            "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'alter,sex,teilnahme,email,datum) VALUES ('1004','anonym','a','a','a','a','a','2'' at line 1 at zum_ausflippen.pl line 37."

            Dabei kommt aber kein PREPARE-Statement zur Anwendung.

            Klar, es geht nicht um prepared statements, wie von Dir behauptet, vgl. auch http://search.cpan.org/~timb/DBI-1.53/DBI.pm

            Insofern gehen auch weitere Ausführungen zum Thema Deinerseits (Ausnahme: Dein Hinweis auf "alter" war durchaus richtig :) an der Sache vorbei:
            "Das ist irrelevant. ...", "Das war das tatsächlich versandte SQL-Statement. ..." ( https://forum.selfhtml.org/?t=144863&m=939807 )

            Somit sollte nach einem bind_param() - wie von uns angeregt - dieses hier im Forum für Analysezwecke angegeben werden.

            1. echo $begrüßung;

              Die Fehlermeldung kommt ja wohl ganz offenkundig aus dem execute():
              "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'alter,sex,teilnahme,email,datum) VALUES ('1004','anonym','a','a','a','a','a','2'' at line 1 at zum_ausflippen.pl line 37."

              Ja, stimmt, denn hier sind die Werte eingefügt. Das heißt, dass Perl in dem Fall nicht in der Lage ist, die von der MySQL-API angebotenen Funktionen für Prepared Statements zu nutzen und sie stattdessen selbst simuliert. Mit PHPs mysqli-Erweiterung und der Nutzung des dort angebotenen Prepared-Statements-Mechanismus wird der Fehler bereits beim prepare ausgegeben (dann natürlich mit den Platzhaltern anstatt der Werte im zitierten Statement).

              Dabei kommt aber kein PREPARE-Statement zur Anwendung.
              Klar, es geht nicht um prepared statements, wie von Dir behauptet, vgl. auch http://search.cpan.org/~timb/DBI-1.53/DBI.pm

              Welche Stelle dort genau meinst du? Das Dokument ist doch recht umfangreich und nicht alles passt auf das Thema.

              Insofern gehen auch weitere Ausführungen zum Thema Deinerseits (Ausnahme: Dein Hinweis auf "alter" war durchaus richtig :) an der Sache vorbei:
              "Das ist irrelevant. ...", "Das war das tatsächlich versandte SQL-Statement. ..." (

              O.K. es war nicht das versandte Statement. Trotzdem war die von dir bemängelte Parameter-Anzahl irrelevant. MySQL gibt bei Syntax-Fehlern den Teil vom Auftreten des Fehlers und die folgenden 80 Zeichen aus. Der Fehler ist also am Anfang des Zitats zu suchen, und der Rest ist für diesen Fehler belanglos.
              Außerdem kann man davon ausgehen, dass Perls DBI ausreichend getestet ist und die Ersetzung der Platzhalter problemlos funktioniert. Sollte es Unstimmigkeiten zwischen der Anzahl der Platzhalter und der später übergebenen Parameter geben, beschwert sich schon Perl darüber und nicht erst das DBMS. Somit kann man das DBI als Blackbox betrachten und zur Fehlersuche das prepare() übergebene Platzhalter-Statement nehmen.

              Somit sollte nach einem bind_param() - wie von uns angeregt - dieses hier im Forum für Analysezwecke angegeben werden.

              Das ist im Allgemeinenen dann richtig, wenn man sein Statement selbst zusammenbaut. Wenn dabei vertrauenswürdige Komponenten im Spiel sind, wie DBI oder die Prepared-Statement-Mechanismen oder -Nachbildungen anderer Systeme oder APIs, ist das nicht mehr erforderlich und manchmal gänzlich unmöglich.

              echo "$verabschiedung $name";

              1. Die Fehlermeldung kommt ja wohl ganz offenkundig aus dem execute():
                "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'alter,sex,teilnahme,email,datum) VALUES ('1004','anonym','a','a','a','a','a','2'' at line 1 at zum_ausflippen.pl line 37."

                Ja, stimmt, denn hier sind die Werte eingefügt. Das heißt, dass Perl in dem Fall nicht in der Lage ist, die von der MySQL-API angebotenen Funktionen für Prepared Statements zu nutzen und sie stattdessen selbst simuliert.

                Wenn wir schon mal präzise sein wollen, dann halten wir fest, dass Prepared Statements vom DBI keinesfalls simuliert werden, sondern lediglich SQL-Statements mit Platzhaltern bereitgehalten werden. Irgendwelche der von Dir an anderer Stelle zitierten Vorteile von Prepared Statements sind nicht erkennbar. Oder anders formuliert: Es geht nicht um Prepared Statements.

                Dabei kommt aber kein PREPARE-Statement zur Anwendung.
                Klar, es geht nicht um prepared statements, wie von Dir behauptet, vgl. auch http://search.cpan.org/~timb/DBI-1.53/DBI.pm

                Welche Stelle dort genau meinst du? Das Dokument ist doch recht umfangreich und nicht alles passt auf das Thema.

                Such mal nach "Drivers for engines without the concept of preparing a statement will typically just store the statement in the returned handle and process it when $sth->execute is called." - so ein Driver liegt vor.

                O.K. es war nicht das versandte Statement. Trotzdem war die von dir bemängelte Parameter-Anzahl irrelevant.

                War ein Anfangsverdacht, was wissen wir wie DBI das SQL-Statement zusammenbastelt?

                MySQL gibt bei Syntax-Fehlern den Teil vom Auftreten des Fehlers und die folgenden 80 Zeichen aus. Der Fehler ist also am Anfang des Zitats zu suchen, und der Rest ist für diesen Fehler belanglos.

                Schon klar, wg. "alter" hätte man Bescheid wissen können.

                Somit sollte nach einem bind_param() - wie von uns angeregt - dieses hier im Forum für Analysezwecke angegeben werden.

                Das ist im Allgemeinenen dann richtig, wenn man sein Statement selbst zusammenbaut. Wenn dabei vertrauenswürdige Komponenten im Spiel sind, wie DBI oder die Prepared-Statement-Mechanismen oder -Nachbildungen anderer Systeme oder APIs, ist das nicht mehr erforderlich und manchmal gänzlich unmöglich.

                Stichwort "pass-thru mode", d.h. die DBI-Verpackung ist dankenswerterweise recht dünn. Davon unabhängig, sind Probleme hartnäckiger Art, dann _muss_ man in die Logs des Datenservers bzw. mit einem "Profiler-Tool" kommen. Und zwar um das SQL-Statement zu packen zu kriegen.

                1. echo $begrüßung;

                  Wenn wir schon mal präzise sein wollen, dann halten wir fest, dass Prepared Statements vom DBI keinesfalls simuliert werden, sondern lediglich SQL-Statements mit Platzhaltern bereitgehalten werden. Irgendwelche der von Dir an anderer Stelle zitierten Vorteile von Prepared Statements sind nicht erkennbar. Oder anders formuliert: Es geht nicht um Prepared Statements.

                  Der Vorteil des Einmal-Parsens und Mehrmals-Ausführen mit unterschiedlichen Werten wird hier von DBI nicht ausgenutzt. Entweder liegt MySQL in einer Version kleiner als 4.1 zugrunde oder DBI ignoriert die Möglichkeit, Prepared Statements direkt von MySQL ausführen zu lassen.
                  Die zweite Haupteigenschaft, bzw. eine Eigenschaft, die zumindest häufig im Umfeld von Prepared Statements zu finden ist, sind die Platzhalter. Ebenso zu PS gehört die Art, SQL-Statements mit prepare() zu übergeben und mit execute() auszuführen, denn ansonsten wäre diese Teilung überflüssig.

                  [...] was wissen wir wie DBI das SQL-Statement zusammenbastelt?

                  Höchstwahrscheinlich so, wie man es erwartet. Es ersetzt die Platzhalter mit den später übergebenen Werten, die dabei auch noch SQL-gerecht bzw. DBMS-gerecht maskiert werden. Mehr nicht.

                  Stichwort "pass-thru mode", d.h. die DBI-Verpackung ist dankenswerterweise recht dünn. Davon unabhängig, sind Probleme hartnäckiger Art, dann _muss_ man in die Logs des Datenservers bzw. mit einem "Profiler-Tool" kommen. Und zwar um das SQL-Statement zu packen zu kriegen.

                  Nun, der MySQL-Server ist sogar so nett, im General Query Log ein zusammengebautes Statement anzuzeigen:

                  Time                 Id Command    Argument
                  070125 21:30:05       1 Connect     test@localhost on test
                                        1 Prepare     [1] SELECT ID FROM test WHERE feld=?
                                        1 Execute     [1] SELECT ID FROM test WHERE feld='bla'
                                        1 Quit

                  Doch bei der Fehlersuche nützt die Execute-Zeile wenig. Man sieht nur, welche Werte für welche Platzhalter verwendet werden. Generelle Syntax-Fehler fallen schon beim Prepare auf. Fehler beim Maskieren der anstelle der Platzhalter zu verwendenden Daten können aufgrund der Arbeitsweise der API nicht auftreten. Die Daten werden getrennt vom Statement und in Rohform in einer speziellen Struktur übergeben (MYSQL_BIND). Die Zusammensetzung mit dem Statement erfolgt anscheinend nur für das Log, denn, wie das Handbuch berichtet, findet das Parsen nur einmal statt. Wozu sollte dann noch das Statement zusammengesetzt werden?

                  Prepared execution is faster than direct execution for statements executed more than once, primarily because the query is parsed only once.

                  An welche Art von hartnäckigem Fehler dachtest du, den man nicht schon beim Prepare oder bei genauer Analyse der Daten erkennt, wozu man also unbedingt ein zusammengesetztes Statement benötigt?

                  echo "$verabschiedung $name";

                  1. An welche Art von hartnäckigem Fehler dachtest du, den man nicht schon beim Prepare oder bei genauer Analyse der Daten erkennt, wozu man also unbedingt ein zusammengesetztes Statement benötigt?

                    Wir dachten ehrlich gesagt weniger an MySQL, sondern an DAO bzw. ADO von MS, das bekanntermassen "im Hintergrund" SQL-Traffic fleissig generiert, der oft problematisch ist. Verpacken mit dem DBI-Modul unter Perl könnte - nach Murphy - ebenfalls Ungünstiges bewirken. (Gerade dann, wenn man nicht ohne weiteres genau herauskriegt, was an SQL-Traffic generiert wird.)

                    Dennoch vielen Dank für die kompetenten Antworten!

                    BTW - mischt Du bei PHP und MySQL irgendwie mit?

  2. echo $begrüßung;

    You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'alter,sex,teilnahme,email,datum) VALUES ('1004','anonym','a','a','a','a','a','2'' at line 1 at zum_ausflippen.pl line 37.

    "alter" ist ein reserviertes Wort und auch ein recht wenig sinnvolles Datum, da es sich ständig ändert. Was gleich bleibt, und aus dem man das Alter im Bedarfsfall berechnen kann, wäre das Geburtsdatum. Wenn man reservierte Wörter trotzdem verwenden möchte, muss man diese mit Backticks einrahmen.

    echo "$verabschiedung $name";

    1. "alter" ist ein reserviertes Wort und auch ein recht wenig sinnvolles Datum, da es sich ständig ändert. Was gleich bleibt, und aus dem man das Alter im Bedarfsfall berechnen kann, wäre das Geburtsdatum. Wenn man reservierte Wörter trotzdem verwenden möchte, muss man diese mit Backticks einrahmen.

      ja, alter ist ein reserviertes wort. ich kann mich nur über mich selbst wundern, eigentlich hab ich das gewusst, aber es hat nicht klick gemacht, erst als ichs las.

      jetzt läufts natürlich.

      für diese teilnehmerliste einer radsportveranstaltung brauche ich nur das age in ganzen jahren sonst hätte ich den unix-zeitwert aus dem geburtsdatum gebildet und eingetragen.

      Dank nochmals !

      Gustl

      1. Hallo Gustl,

        sonst hätte ich den unix-zeitwert aus dem geburtsdatum gebildet und eingetragen.

        Das ist fast noch schlimmer als ein Datum als einfache Zeichenkette abzuspeichern. Für Datumsangaben gibt es in MySQL den Datentyp DATE. Dieser ist angemessen, erst recht für sowas wie das Geburtsdatum. Meines kannst Du mit einem UNIX-timestamp nicht darstellen. DB-Funktionen zur Datumsrechnung fallen auch weg. Solche Umwandlungen sind in den seltensten Fällen sinnvoll.

        Freundliche Grüße

        Vinzenz