[php/mysql] überprüfen ob ID in Spalte (Zeichenkette) vorkommt

eggman

Well-known member
ID: 70062
L
21 Mai 2006
216
8
Hallo zusammen,

wie so oft stehe ich mal wieder vor einem (für mich) scheinbar unlösbarem Problem...

Folgendes Ziel: Auf einer Informationsseite möchte ich relevante Produkte anzeigen. Im Gegenzug möchte ich auf den Produktseiten aber auch Einträge der relevanten Informationen auflisten. Für ein Produkt können mehrere Informationen vorhanden sein und vice versa.

Nun habe ich bei der Tabelle der Informationsseiten eine Spalte, in die ich die IDs der Produkte mit Komma getrennt eintrage:

PHP:
123, 534, 968, 475, 968, ...

Nun habe ich es auf den Informationsseiten relativ einfach geschafft, die jeweiligen Produkte aufzulisten (mittels explode und foreach dann mit Abfrage). Nun möchte ich aber auf der Seite zum Produkt 968 aber auch auflisten, weile Informationen dazu passen.

Das wäre ja im Prinzip kein Problem: mit WHERE und like %968%

Nun ergibt sich aber das Problem, dass wenn beim Eintrag einer völlig anderen Information die ID 1968 hinterlegt wurde, wird diese ja auch beim Produkt 968 angezeigt.

Wie kann ich dieses Problem lösen? Oder habe ich bereits bei der Konzeption der Tabellen Mist gebaut? Sieht mir irgendwie ganz danach aus :(

Ich danke schonmal für eure Hilfe...
Schönen Sonntag noch!
 
Oder habe ich bereits bei der Konzeption der Tabellen Mist gebaut? Sieht mir irgendwie ganz danach aus :(
Richtig. Das ist ein Verstoß gegen die 1. Normalform! Daten müssen atomar abgespeichert werden. Du hast quasi eine ganze Liste als ein Datum verwendet und jetzt hast du logischerweise auch das Problem, dass du kein explode() in der Datenbank hast, um die Daten wieder aufzubröseln.
 
Shit. Also wie befürchtet. Nungut, vielen Dank für die Bestätigung! Damit habe ich viel für die Zukunft gelernt :)

Jetzt war es natürlich sehr bequem, die einzelnen IDs schnell in nur einer Zeile abzuspeichern. Wenn ich die Daten nun in der Normalform speichern möchte, sähe die Tabelle doch so aus, oder?

Code:
ID|Wert|Zuweisung

Sprich: Ich muss für jede Verknüpfung von Produkt und Information eine einzelne Zeile anlegen?

Mal angenommen, die Theorie ist richtig - könnt ihr mir dann eine möglichst elegante Methode nennen, wie man die Daten über Formularfelder (möglichst auch für Laien einfach) einträgt und später auch leicht bearbeiten kann?

Für die Eintragung hätte ich diese Idee: Die Produkt-IDs werden nach wie vor per Einzelzeile, durch Komma oder Leerzeichen getrennt, vom Benutzer eingetragen. Im Anschluss wird der String per explode aufgeteilt und alle Produkt-IDs einzeln mit der jeweiligen Informations-ID in die Datenbank eingetragen. So hätte ich doch die Daten für alle erdenklichen späteren Operationen richtig vorliegen?

Nur: Wenn ich später diese Zuordnungen auf einfache Art bearbeiten (einzelne Produkt-IDs hinzufügen oder löschen) will, wie realisiere ich das am besten mit den Formularfeldern? Die Produkt-IDs der Informationsseite müssen ja dann wieder irgendwie zusammengeführt werden und später in ihrer neuen Form erneut in die Datenbank geschrieben werden. Für meinen Verstand ergibt das irgendwie sehr große Unordnung =/

phu, also wenn mir jetzt noch jemand antwortet - Respekt! *g*
 
Wenn Du Dein bisheriges Konzept nicht aufgeben willst ( trotz Verstoss gegen 1NF ), dann füge an erste Stelle Deiner Spalte noch ein Komma ein und frage nicht ab
Code:
WHERE ... LIKE '%968%'

sondern

Code:
WHERE ... LIKE '%,968,%'

dann kannst Du die Werte auch unterscheiden
 
Wenn Du Dein bisheriges Konzept nicht aufgeben willst ( trotz Verstoss gegen 1NF ), dann füge an erste Stelle Deiner Spalte noch ein Komma ein und frage nicht ab
Code:
WHERE ... LIKE '%968%'

sondern

Code:
WHERE ... LIKE '%,968,%'

dann kannst Du die Werte auch unterscheiden

Das Problem an seinem Konzept ist aber nicht nur, dass es auf Dauer einfach unproduktiv ist (es muss dauernd ein Workaround gebastelt werden), sondern auch, dass die Performance der Datenbankabfragen erheblich darunter leidet, weil für LIKE-Konstrukte mit "%" am Anfang des Strings kein Index verwendet werden kann.

Greetz

paddya
 
Sprich: Ich muss für jede Verknüpfung von Produkt und Information eine einzelne Zeile anlegen?
Produkt | Information
Eine zusätzliche ID ist nicht erforderlich und wäre hier wohl nur Speicherplatzverschwendung.
Mal angenommen, die Theorie ist richtig - könnt ihr mir dann eine möglichst elegante Methode nennen, wie man die Daten über Formularfelder (möglichst auch für Laien einfach) einträgt und später auch leicht bearbeiten kann?
Ganz einfach, sogar noch einfacher:

Beispiel: Administriere Produkt 42
Erstmal alle relevanten Infos holen:
Code:
[FONT=Courier New][B][COLOR=#9932cc]SELECT[/COLOR][/B] information
[B][COLOR=#9932cc]FROM[/COLOR][/B] [B][COLOR=#9932cc]table[/COLOR][/B]
[B][COLOR=#9932cc]WHERE[/COLOR][/B] produkt= 42;[/FONT]
Nun stellst du die alle dar, z.B. Listenfeld oder noch einfacher n Textarea, wo jede ID in einer Zeile steht. Optisch aufpeppen kannst du das, indem du ne Tabelle machst, dort (müsstest in der Abfrage auf die Informationstabelle JOINen) weitere Spalten aus den Informationsseiten (z.B: Title, Erstellungszeit, ... weiß ja ned, was du so hast) und rechts einen Löschen-Button darstellst.

Beispiel: Lösche nun von Produkt 42 die relevante Infoseite 4711.
Klicke auf den Button rechts neben der Infoseite 4711, um sie zu löschen. Eine Abfrage:
Code:
[FONT=Courier New][B][COLOR=#9932cc]DELETE[/COLOR][/B] [B][COLOR=#9932cc]FROM[/COLOR][/B] [B][COLOR=#9932cc]table[/COLOR][/B]
[B][COLOR=#9932cc]WHERE[/COLOR][/B] information = 4711 [B][COLOR=#9932cc]AND[/COLOR][/B] produkt = 42;[/FONT]

Für die Eintragung hätte ich diese Idee: Die Produkt-IDs werden nach wie vor per Einzelzeile, durch Komma oder Leerzeichen getrennt, vom Benutzer eingetragen. Im Anschluss wird der String per explode aufgeteilt und alle Produkt-IDs einzeln mit der jeweiligen Informations-ID in die Datenbank eingetragen. So hätte ich doch die Daten für alle erdenklichen späteren Operationen richtig vorliegen?
Wenn dus so primitiv machen willst, reicht das.
Nachteil bei "alles auf einmal bearbeiten", dass du nachgucken musst, welche ID neu is und welche gelöscht werden muss.

Eleganter wäre es, wenn du erst alle relevanten Informationen zusammensuchst - ein Formular stellt alle Informationen dar und speichert sie in der Session. Du suchst alles zusammen und wenn du fertig bist, klickst du einen Speichern-Button, der dann eine INSERT-Query absendet.

Dass du nicht doppelt einträgst, INSERT IGNORE benutzen. Der Primärschlüssel verhindert dann automatisch eine doppelte Eintragung.
(Ich bin nur grad unsicher, ob das dann mit einem Query geht, oder ob die alle separat sein müssen :think: Musst im Manual nachgucken.)
Oder eben vorher abrufen und PHP muss entscheiden, was eintragen und was zu löschen is.