SQL Insert - Frage

RedlightX

Aktiver NGBler
Registriert
18 Juli 2013
Beiträge
1.094
Hallo zusammen,

schon meine Mutter sagte immer, dass es keine blöden Fragen gibt, deshalb wage ich es mal:

Ich möchte: Einen Datensatz in eine Datenbank schreiben.

Ich habe: 2 Tabellen (Kategorie und Snippet)

Kategorie: kategorie_ID (Primary Key), bezeichnung

Snippet: snippet_ID (Primary Key), bezeichnung, code, kategorie_ID (Foreign Key) und tags


Das Problem ist folgendes:

Ich habe ein Formular, das mittels POST die Daten an ein PHP-Script übergibt, welches dann den Datensatz in die Datenbank schreibt. Meine SQL-Abfrage sieht momentan so aus:

[src=mysql] $sql = "INSERT INTO Snippet(titel, bezeichnung, code, kategorie_ID, tags) VALUES (:inputTitle, :inputDescription, :inputSnippet, (SELECT kategorie_ID FROM Kategorie WHERE Kategorie.bezeichnung = :inputCategory JOIN Kategorie ON (Katgorie.kategorie_ID = Snippet.kategorie_ID), :inputTags)";[/src]

Er soll natürlich beim Snippet anhand der im Formular ausgewählten Kategorie, die sich schon in der Datenbank befindet, den entsprechenden Fremdschlüssel in der Tabelle Snippet (kategorie_ID) einsetzen.


Mag mir jemand sagen, was an meiner Abfrage falsch ist? :/


Danke :T
 
Müßte das nicht "JOIN Snippet" heißen, statt "JOIN Kategorie"?
 
  • Thread Starter Thread Starter
  • #3
Auch damit geht es leider nicht - folgende Meldung kommt:

SQLSTATE[42000]: Syntax error or access violation: 1064 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 'JOIN Snippet ON (Katgorie.kategorie_ID = Snippet.kategorie_ID), 'sql')' at line 1

Ich fürchte ja, dass der Fehler wahrscheinlich hier irgendwo liegt: WHERE Kategorie.bezeichnung = :inputCategory, da ich nicht weiß, ob man diesen POST-"Platzhalter" da einsetzen kann. Generell bin ich mir unsicher, ob ich da einfach eine Select-Abfrage im Insert einbauen kann/darf :/
 
Wofür brauchst du dort den Doppelpunkt? Ist das überhaupt korrekte Syntax? Habe ich so noch nie gesehen
 
Es geht nicht "so einfach" in einem Statement.

Siehe auch

@werner, er nutzt wahrscheinlich PDO auf PHP Ebene, und da kennzeichnen die Variablen nach ":" eine Variable, die später ausgetauscht wird.
 
  • Thread Starter Thread Starter
  • #6
Ja, ich nutze PDO, danke für die bisherigen Antworten. Ich hätte nicht gedacht, dass man da diese Umwege gehen muss. Ist sowas nicht alltäglich?

--- [2016-05-14 02:23 CEST] Automatisch zusammengeführter Beitrag ---

Für die Nachwelt:

Ich habe es mit 2 SQl-Statements gemacht.

Kategorie_ID der mittels POST übertragenen Kategorie zurückgeben lassen, diese gespeichert und im 2. Query als Value angegeben...
Das Leben könnte ja so einfach sein - wenn man weiß, wie es funktioniert.


Es hat gedauert, aber ich werde mit einem Lächeln einschlafen können :D
 
Da der Join oben 1. unnötig und 2. an der falschen Stelle war, hätte es mit dem Subselect von oben so ausgesehen:
[src=mysql]INSERT INTO Snippet(titel, bezeichnung, code, kategorie_ID, tags)
VALUES (:inputTitle, :inputDescription, :inputSnippet,
(SELECT kategorie_ID FROM Kategorie WHERE Kategorie.bezeichnung = :inputCategory), :inputTags)
[/src]

Probleme bekommst du so nur wenn die Kategoriebezeichnung mehrfach oder gar nicht vorkommen sollte.
 
Ich rate dir davon ab in den Klammern von VALUES diese Form von Subquery zu verwenden! Erlaubt sind dort nur scalare Werte (bzw Ausdrücke, die solche ergeben), ein Subquery ist aber eine Liste von Listen von Werten:
Beipiel: SELECT a,b,c,.. FROM X;
(
(1, 2, 4, ...),
(n, g, b, ...),
...
)

Ok, du hast exakt ein Attribut im SELECT, also ist es eine Liste von Listen der Länge 1:
((1), 👎, ...)
und du weißt, dass, wegen dem WHERE, nur eine solche Liste ausgegeben werden wird, also ((1)).
Man nennt das einen "Scalaren Subquery", also einen Subquery der einen Scalar zurückgibt.
Syntaktisch darfst du diesen also in VALUES verwenden. Aber es ist keine gute Idee. Wenn es nun doch mal passiert, dass es mehr als einen Eintrag für die Bezeichnung in Kategorie gibt, dann crasht es.
Mit einem LIMIT kannst du forcieren, dass er Scalar bleibt, aber es sollte klar sein, dass um Dateninkonsistenzen "herumzucoden" irgendwie der falsche Ansatz ist.

Praktischerweise gibt es noch INSERT ... SELECT:
[src=mysql]INSERT INTO Snippet (titel, bezeichnung, code, kategorie_ID, tags)
SELECT :inputTitle, :inputDescription, :inputSnippet, kategorie_ID, :inputTags FROM Kategorie WHERE Kategorie.bezeichnung = :inputCategory;[/src]

Das Subquery ergibt nun eine Liste von Listen der Länge fünf.
Und wir wissen, dass mit dem WHERE daraus eine Liste mit exakt einer Liste der Länge 5 erzeugt wird.
Wenn die selbe Bezeichnung in deiner Kategorie Tabelle nun zwei mal vorkommen würde, dann ergibt das Subquery eine Liste mit zwei Listen mit fünf Werten. Und INSERT fügt dann fröhlich zwei Datensätze in Snippet ein: Einen für jeden der zwei kategorie_ID Werte der Bezeichnung.
Ob dieser Umgang mit der theoretischen Dateninkonsistenzen besser ist als ein Crash sei mal dahingestellt ;-)

Aber genug der Theorie. ("Das Leben könnte ja so einfach sein - wenn man weiß, wie es funktioniert." - once said by a wise man) kommen wir nun zur Praxis:
Ich vermute einfach mal, dass dein Formular keine Freitext-Eingabe für die Kategorie hat (sonst müsstest du ja sowieso erst einmal nach sehen, ob es diese schon gibt und, wenn nicht, eine neue Kategorie erstellen), sondern dass es sich um eine select-Tag (Drop-Down Auswahl) handelt, in dem du die Kategorien aus der Datenbank aufführst. Ist dies der Fall, dann schreib doch in das value-Attribut der option-Tags lieber die ID rein, statt die Bezeichnung. Denn dann sendet dir der Client per POST direkt die ID ;-)


Achja: Wie X-Coder schon sagte: Der JOIN steht an der falschen Stelle, daher der Syntax-Error. Korrekt wäre FROM Kategorie JOIN ... Aber das nur nebenbei
 
Zuletzt bearbeitet:
  • Thread Starter Thread Starter
  • #9
Danke euch beiden für eure Antworten - es klappt und ich habe wieder was gelernt :T

Die Idee mit der ID im Value-Tag klingt einleuchtend, das werde ich mal einbauen!
Und ja, die Kategorien werden direkt aus der Datenbank geholt und können separat über ein Modal angelegt werden
 
Zurück
Oben