JOIN-Problem, zweiter Teil
Yadgar
- datenbank
High!
Nachdem ich durch Sven Rautenbergs Hilfe das JOIN-Problem bei der Tabelle "musiker_veroeffentlichung_instrument" lösen konnte (noch einmal danke für deinen Tipp!), stellt es sich jetzt in anderer Form noch einmal.
Es geht um die Tabelle "instrumentenmodelle" mit den Spalten ID, Hersteller, Modell, Instrument - "Hersteller" ist eine Primärschlüssel-Nummer (auto_increment) aus der Tabelle "instrumentenhersteller", "Modell" ist Klartext, "Instrument" wieder eine Primärschlüssel-Nummer (auto_increment) aus der Tabelle "instrumente".
Da die vorliegenden Rohdaten (Angaben zu Band-Besetzungen) längst nicht immer Hersteller und Modellname konkreter Instrumente (z. B. Hammond B3), sondern oft nur generische Instrumentenbezeichnungen (z. B. Orgel) oder sogar nur Bezeichnungen von Instrumentengruppen (z. B. Keyboards) enthalten, habe ich eine dreistufige Relationshierarchie eingerichtet: zunächst "instrumentengruppen" (ID, Bezeichnung), dann "instrumente" (ID, Instrument, Instrumentengruppe (ID aus "instrumentengruppen")), schließlich "instrumentenmodelle".
Da die Tabelle "musiker_veroeffentlichung_instrument" die Angaben für "Instrument" aus "instrumentenmodelle" bezieht, müssen in "instrumentenmodelle" auch die generischen Instrumentenbezeichnungen und sogar die Instrumentengruppenbezeichnungen stehen.
Jetzt möchte ich analog zu den bereits existierenden Tabellen eine Routine schreiben, die Eingaben per Formular auf bereits vorhandene identische Einträge prüft. Relevant sind dabei nur die Spalten "Hersteller" und "Modell"; geprüft wird sowohl auf mit der aktuellen Eingabe identische Einträge für "Hersteller" und "Modell" wie auch für den Fall, dass die Spalte "Hersteller" leer (=NULL) bleibt (also bei generischen Instrumentenbezeichnungen), auf identische Einträge für "Modell".
Konkret: wenn in der Tabelle bereits unter Hersteller "Hammond" und unter Modell "B3" steht und ich irrtümlicherweise noch einmal "Hammond" und "B3" eingebe, sollte eine Meldung "Eintrag mit diesen Daten existiert bereits! Bitte korrigieren Sie Ihre Eingabe!" angezeigt werden, nicht jedoch, wenn ich etwa "Bontempi" und "B3" eingebe, sehr wohl aber wiederum, wenn (bei leerem Eintrag für "Hersteller") ein zweites Mal "elektronische Orgel" unter "Modell" eingetragen werden soll.
Hier ist der bisherige Code:
$query="SELECT instrumentenmodelle.Hersteller, instrumentenmodelle.Modell FROM instrumentenhersteller RIGHT OUTER JOIN instrumentenmodelle ON instrumentenhersteller.ID = instrumentenmodelle.Hersteller OR instrumentenmodelle.Hersteller = NULL";
$result=mysql_query($query);
dberror();
while ($row = mysql_fetch_row($result))
{
var_dump($row);
echo "<br>";
dberror();
if ($row[0]==$Hersteller && $row[1]==$Modell || $row[0]==NULL && $row[1]==$Modell)
{
echo "Ein Eintrag mit diesen Daten existiert bereits! Bitte korrigieren Sie Ihre Eingabe!<br>";
$doubledat=true;
break;
}
}
So weit, so gut... nur wird aus einem mir unerklärlichen Grund die Bedingung des if-Blocks nie wahr!
var_dump($row) zeigt für $row[0] (also leere Spalte "Hersteller") seltsamerweise "0" und nicht "NULL" an!
Bis bald im Khyberspace!
Yadgar
High!
<Ingrid>
So weit, so gut... nur wird aus einem mir unerklärlichen Grund die Bedingung des if-Blocks nie wahr!
</Ingrid>
Das kann ja auch gar nicht anders sein, wenn ich in der MySQL-Query Primärschlüsselnummern aus "instrumentenhersteller" abfrage, im Formular aber Klarnamen (instrumentenhersteller.Name) eingegeben werde!
Also habe ich die Query geändert:
SELECT instrumentenhersteller.Name, instrumentenmodelle.Modell FROM instrumentenhersteller RIGHT OUTER JOIN instrumentenmodelle ON instrumentenhersteller.ID = instrumentenmodelle.Hersteller OR instrumentenmodelle.Hersteller = 0;
So werden schon einmal Doppeleingaben von Hersteller (!=NULL) und Modell richtig erkannt, leider keine Doppeleingaben von Modell bei Hersteller=NULL... stattdessen passiert bei Eingabe von z. B. "elektronische Orgel" ohne Hersteller etwas noch Seltsameres: var_dump($row) zeigt "elektronische Orgel" in allen Kombinationen mit den bereits vorhandenen Herstellern (gegenwärtig drei, nämlich Hammond, Yamaha und Korg) an! Stimmt womöglich etwas mit den INSERT-Sequenzen nicht und werden gleich drei Datensätze auf einmal in "instrumentenmodelle" eingetragen?!?
Hier noch mal der Gesamt-Code mit INSERT-Sequenzen:
$query="SELECT instrumentenmodelle.Hersteller, instrumentenmodelle.Modell FROM instrumentenhersteller RIGHT OUTER JOIN instrumentenmodelle ON instrumentenhersteller.ID = instrumentenmodelle.Hersteller OR instrumentenmodelle.Hersteller = NULL";
$result=mysql_query($query);
dberror();
while ($row = mysql_fetch_row($result))
{
var_dump($row);
echo "<br>";
dberror();
if ($row[0]==$Hersteller && $row[1]==$Modell || $row[0]==NULL && $row[1]==$Modell)
{
echo "Ein Eintrag mit diesen Daten existiert bereits! Bitte korrigieren Sie Ihre Eingabe!<br>";
$doubledat=true;
break;
}
}
if (!$doubledat)
{
$query= "SELECT ID FROM instrumentenhersteller WHERE Name='".mysql_real_escape_string($Hersteller)."'";
$result = mysql_query($query);
dberror();
$row = mysql_fetch_row($result); // nur 1 Ergebniszeile!
$ids[0]=$row[0];
$query = "SELECT ID FROM instrumente WHERE Bezeichnung = '".mysql_real_escape_string($Instrument)."'";
$result = mysql_query($query);
dberror();
$row = mysql_fetch_row($result); // nur 1 Ergebniszeile!
$ids[1]=$row[0];
$query = "INSERT INTO instrumentenmodelle (Hersteller, Modell, Typ) VALUES ('".mysql_real_escape_string($ids[0])."','".mysql_real_escape_string($Modell)."','".mysql_real_escape_string($ids[1])."')";
$result = mysql_query($query);
dberror();
echo "Ihre Eingabe war korrekt und wurde in die Datenbank eingetragen!";
}
Wieso wird die INSERT-Query unter bestimmten Bedingungen (nämlich $row[0]=NULL (oder meinetwegen $row[0]=0, PHPMyAdmin, mit dem ich die Ausgaben teste, lässt einen da ja leider konsequent im Unklaren) mehr als einmal ausgeführt? Da ist doch gar keine Schleife!
Und jetzt, wo ich mir gerade per PHPMyAdmin den Inhalt von "instrumentenmodelle" anzeigen lasse, stelle ich fest, dass die Eingabesequenz wohl doch korrekt funktioniert, jedenfalls steht "elektronische Orgel" dort nur in Kombination mit Hersteller=0 und nicht etwa mit allen gegenwärtig vorhandenen (Hammond, Yamaha, Korg) Herstellern... allerdings nach wie vor doppelt, weil die Fehlererkennung für Hersteller=0 (oder NULL? Ich blicke langsam überhaupt nicht mehr durch!!!) noch nicht funktioniert...
Also muss wohl die Query am Beginn des Codeausschnittes noch nicht ganz in Ordnung sein... vielleicht sollte ich dort "= 0" doch durch "= NULL" ersetzen...
...und, bingo!, es funktioniert! Mir fällt ein Asteroid vom Herzen!
Darauf eine Pringles- und Erdnussflips-Dröhnung von der 24/7-Junkstelle... oder lieber doch nicht, ich will schließlich irgendwann in diesem Jahrhundert noch mit dem Fahrrad nach Afghanistan, da ist ein BMI nahe 40 ein echter Showstopper!
Bis bald im Khyberspace!
Yadgar
Hi!
[SELECT; if (vorhanden) break; else INSERT;]
So macht man das nicht, weil nur diese eine Stelle kontrolliert, ob doppelte Werte eingetragen werden. An anderer Stelle kann diese gewünschte Einschränkung problemlos umgangen werden. Ebenso könnte in einer Mehrnutzerumgebung, wie sie das Web darstellt, zwischen Abfrage une Eintrag bereits ein anderer den Eintrag vorgenommen haben. Das ist zwar in der Regel nicht sehr wahrscheinlich, weil es wohl selten vorkommt, dass genau zur selben Zeit jemand den selben Gedanken hatte, aber trotzdem macht man das nicht. Wenn sowas doch vorkommt, sind solche Fehler schwer zu finden, weil sie von Natur aus ganz schlecht nachvollziehbar sind.
Deshalb ist es besser, auf die Spalte (oder auch mehrere Spalten), in der (oder über die) keine Dopplungen enthalten sein dürfen, einen Unique-Index zu legen. Dann frage man nicht vorher ab, sondern mache einfach auf gut Glück das INSERT. Wenn der Datensatz noch nicht vorhanden war, wird er eingetragen und das Statement meldet keinen Fehler. War er schon vorhanden, gibt es einen Unique-Constraint-Fehler. Beim Auswerten auf Fehler fragt man nun gezielt diesen Fehler ab und weiß bei seinem Auftreten, dass der Datensatz schon vorhanden war.
Lo!
High!
So macht man das nicht, weil nur diese eine Stelle kontrolliert, ob doppelte Werte eingetragen werden. An anderer Stelle kann diese gewünschte Einschränkung problemlos umgangen werden.
Unwahrscheinlich, da ich nicht damit rechne, die jeweiligen Skripte noch nennenswert ausbauen zu müssen und dabei entsprechende Programmierfehler zu produzieren... wer sollte sonst diese Einschränkung umgehen können, wenn allein ich Schreibrecht auf dem Server habe?
Ebenso könnte in einer Mehrnutzerumgebung, wie sie das Web darstellt, zwischen Abfrage une Eintrag bereits ein anderer den Eintrag vorgenommen haben. Das ist zwar in der Regel nicht sehr wahrscheinlich, weil es wohl selten vorkommt, dass genau zur selben Zeit jemand den selben Gedanken hatte, aber trotzdem macht man das nicht. Wenn sowas doch vorkommt, sind solche Fehler schwer zu finden, weil sie von Natur aus ganz schlecht nachvollziehbar sind.
O. k., das leuchtet allerdings ein!
Deshalb ist es besser, auf die Spalte (oder auch mehrere Spalten), in der (oder über die) keine Dopplungen enthalten sein dürfen, einen Unique-Index zu legen. Dann frage man nicht vorher ab, sondern mache einfach auf gut Glück das INSERT. Wenn der Datensatz noch nicht vorhanden war, wird er eingetragen und das Statement meldet keinen Fehler. War er schon vorhanden, gibt es einen Unique-Constraint-Fehler. Beim Auswerten auf Fehler fragt man nun gezielt diesen Fehler ab und weiß bei seinem Auftreten, dass der Datensatz schon vorhanden war.
Wieder was gelernt (und auch gleich ausprobiert) - funktioniert prima und spart eine ganze Menge PHP-Code ein! Danke für den Tipp... und rechne schonmal damit, dass es in einem meiner virtuellen PoV-Ray-Planetensysteme auf einem mittelgroßen Mond eine "Dedlfix Regio" geben wird!
Bis bald im Khyberspace!
Yadgar