Stichwort nur einmal ausgeben
lima-city → Forum → Programmiersprachen → PHP, MySQL & .htaccess
abfrage
array
beschreibung
beziehung
code
datenbank
datum
eintrag
erstellen
geschicklichkeit
machen
performance
redundanz
spalten
speichern
spiel
tabelle
tag
url
zahl
-
Hallo,
ich habe eine MySQL tag/tabelle">Tabelle, in der Spiele gespeichert sind. Diesen Spielen sind außerdem noch "Tags" zugeordnet, welche mit Kommas getrennt sind (outdoorspiele, kreisspiele, sinnesspiele,). Nun möchte ich eine Übersichtsseite erstellen, auf der die Tags aller Spiele aufgelistet sind, allerdings nicht doppelt.
Wie löse ich dieses Problem am besten?
Grüßle Fabi -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
du könntest zuerst die komplette tabelle mit den spielen durchgehen, und die tags aufgesplittet in ein array einfügen.
dabei gibt es zwei möglichkeiten:
1. du schaust vor dem einfügen, ob das element schon im array vorhanden ist, wenn nicht fügst du es ein
2. du fügst einfach alles ein, und löscht nachträglich alles doppelte raus.
was am ende performanter ist hängt meiner meinung nach auch von der datenmenge ab.
mfg -
syberpsace schrieb:
1. du schaust vor dem einfügen, ob das element schon im array vorhanden ist, wenn nicht fügst du es ein
Und wie mache ich das? Bin Leider kein PHP-Profi...
Grüßle Fabi -
dazu gibt es die schöne funktion array_unique().
damit kannst du das ganze einfach lösen...wie schon gesagt, weiß ich aber nicht, ob das die schönere meiner beiden angebotenen lösungen ist.
€dit: sry...verlesen
fürs überprüfen vor dem einfügen gibt es leider keine so schöne fuktion, da müsstest du dir selbst was basteln.
mfg
Beitrag zuletzt geändert: 18.1.2010 17:50:52 von syberpsace -
Am besten siehst du dir an, was Normalformen sind, insbesondere die erste Normalform sollte dich interessieren. Diese tritt ein, wenn deine Attribute atomisch sind.
Oder im Klartext: Wenn du ordentlich arbeiten willst, musst du die Tags in eine extra Tabelle auslagern und eine Linker-Tabelle erstellen, die Tag und Spiel verbinden.
Dann kannst du auch die volle Macht von SQL nutzen und ein SELECT DISTINCT durchführen. -
nikic schrieb:
Am besten siehst du dir an, was Normalformen sind, insbesondere die erste Normalform sollte dich interessieren. Diese tritt ein, wenn deine Attribute atomisch sind.
Oder im Klartext: Wenn du ordentlich arbeiten willst, musst du die Tags in eine extra Tabelle auslagern und eine Linker-Tabelle erstellen, die Tag und Spiel verbinden.
Dann kannst du auch die volle Macht von SQL nutzen und ein SELECT DISTINCT durchführen.
Ja das hatte ich mir auch schon überlegt, allerdings wusste ich auch da nicht, wie ich das machen solle.
Hat da jemand ne Lösung?
Danke im Vorraus Fabi -
Also wenn mich nicht alles täuscht hängst du an deine Select Abfrage einfach "Group By "TAG" " an und schon sollte es nurnoch jeden Tag einmal ausgeben.
Auch bei unsortierten Listen welche nicht in 1. Normalform sind. Hab das grade mal bei mir getestet und es scheint zu funktionieren. -
Berndsbande.
Wenn in der einen Zeile als Tag steht: Muh, Blub, Mäh, und in der anderen Muh, Grr, Mäh, dann hat er Muh und Mäh trotzdem doppelt.
Du erstellst eine Tabelle Spiele:
spielID, spielname, sonstiges
Eine Tabelle (Tags)
spielID, tag
Du erstellst also ein Spiel, mit einer ID
Dann gibst du in Tabelle "Tags" für jeden Tag einmal die SpielID und einmal den Tag ein.
Zuletzt kannst du jetzt die Abfrage machen: SELECT tag FROM Tags GROUP BY tag
Willst du die zum Tag zugehörigen Spiele sammeln müsste das (bin da nicht ganz Fit) damit gehen:
SELECT spielname FROM Spiele, Tags WHERE Spiele.spielID = Tags.spielID AND Tags.tag = $gewünschter Tag
Angaben ohne gewähr.
lg,
Antagonist
PS: Lass mich wissen, ob es funktionierte! -
frodo89 schrieb:
PS: Lass mich wissen, ob es funktionierte!
Ich denk schon dass es funktioniert hätte, allerdings müsste ich dazu ja die Tags nochmal in eine extra Tabelle schreiben.
Gibt es denn keine Möglichkeit was mit PHP zu schreiben, das die Tags dann aus der Spieletabelle ausliest, in einen Array einliest (oder so - hab da wenig Ahnung) und diese Tags dann in einer extra Tabelle speichert wo diese dann per SELECT DISTINCT ausgelesen werden können?
Grüßle Fabi -
frodo89 schrieb:
Berndsbande.
Wenn in der einen Zeile als Tag steht: Muh, Blub, Mäh, und in der anderen Muh, Grr, Mäh, dann hat er Muh und Mäh trotzdem doppelt.
Du erstellst eine Tabelle Spiele:
spielID, spielname, sonstiges
Eine Tabelle (Tags)
spielID, tag
[...]
Das ist auch falsch.
Bei der Beziehung handelt es sich um eine n-m Beziehung: Einem Tag können belieblg viele (verschiedene) Spiele zugewiesen werden. Einem Spiel können beliebig viele (verschiedene) Tags zugewiesen werden.
D.h. du brauchst drei Tabellen.
=>
Table spiel:
spiel_id, spiel_name, spiel_sonstiges
Table tag:
tag_id, tag_name
Table spielTagRelation:
spielTagRelation_spiel_id, spielTagRelation_tag_id
Beispiel:
spiel_id: 1
spiel_name: Tetris
...
spiel_id 2
spiel_name Mario
tag_id 1
tag_name: Geschicklichkeit
tag_id 2
tag_name: Jump'n'Run
spielTagRelation_spiel_id 1
spielTagRelation_tag_id 1
spielTagRelation_spiel_id 2
spielTagRelation_tag_id 1
spielTagRelation_spiel_id 2
spielTagRelation_tag_id 2
D.h. Tetris ist ein Geschicklichkeitsspiel.
Mario ist ein Geschicklichkeitsspiel und ein Jump'n'Run Spiel.
VG Lucas
P.S.: Mein Karma ist ganz schön niedrig...
edit:
Dadruch steht in der Tabelle Tags nicht dreimal "Geschicklichkeit", sondern nur einmal.
Folglich reicht es die Tabelle Tags auszulesen, um zu wissen, wie viele verschiedene Tags es gibt.
Beitrag zuletzt geändert: 21.1.2010 4:39:54 von lucas9991 -
warum denn das?
Warum musst du einem eindeutigen Tag eine eindeutige ID zuweisen, und verwendest den Tag nicht selbst als ID, und sparst dir dafür Zeit bei der Abfrage, und Speicherplatz wegen weglassen unnötiger Daten.
Also sind wir soweit, das wir sehen, das man dem Tag nicht noch eine Zahl zuweisen muss, nur weil man es kann...
Warum müssen wir dann eine Tabelle mit nur einer Spalte erstellen, um diese über eine andere Tabelle zu verlinken?
Die Abfrage der 3. Tabelle mit den Tagnamen kann man sich also spaaren.
Warum schmeißen wir die Tabelle dann nicht gleich raus?
@Fabian:
schattenbaum.net sagt:
<?php $abfrage = "SELECT url, urlname FROM links"; $ergebnis = mysql_query($abfrage); while($row = mysql_fetch_object($ergebnis)) { echo $row->url; } ?>
Statt dem echo fügst du den Eintrag einem Array hinzu.
Statt -> url verwendest du halt ->tag
Danach kommt
$tagarray = array_unique($tagarray)
PS: Ich beherrsche kein PHP
lg,
Antagonist
Beitrag zuletzt geändert: 21.1.2010 11:14:41 von frodo89 -
frodo89 schrieb:
warum denn das?
Warum musst du einem eindeutigen Tag eine eindeutige ID zuweisen, und verwendest den Tag nicht selbst als ID, und sparst dir dafür Zeit bei der Abfrage, und Speicherplatz wegen weglassen unnötiger Daten.
Also sind wir soweit, das wir sehen, das man dem Tag nicht noch eine Zahl zuweisen muss, nur weil man es kann...
Warum müssen wir dann eine Tabelle mit nur einer Spalte erstellen, um diese über eine andere Tabelle zu verlinken?
Die Abfrage der 3. Tabelle mit den Tagnamen kann man sich also spaaren.
Warum schmeißen wir die Tabelle dann nicht gleich raus?
[...]
Man benötigt eine dritte Tabelle weil die Beziehung zwischen den Spielen und den Tags eine n-m Beziehung (n,m Elemnt aus den natürlichen Zahlen) ist.
Jedenfalls sollte man es als n-m Beziehung ansehen, dadurch werden Redundanzen vermieden.
Beispiel:
Du hast zwei Speile und beide Spiele sind Geschicklichkeitsspiele.
Wenn du jedem Tag ein Spiel zuweist, dann muss das Tag "Geschicklichketisspiel" zwei mal in der Tabelle Tags vorhanden sein.
Das heißt du hast zwei Einträge in Tags, die sich lediglich durch die ID unterscheiden. => Das nennt man Redundanz und ist meist unerwünscht, da dadurch schnell Fehler passieren und es auch nicht Effizient ist.
Darüberhinaus kann man durch dieses Datenbankschema die gewünschten Ausgaben viel leichter und dadurch effizienter abfragen. -
Eine ID muss nicht unbedingt eine Zahl sein.
Du kannst den Tag selbst, da er eine Eindeutige Bezeichnung ist, und damit so einmalig ist, wie die ID
als ID verwenden.
Was du vor hast, ist in meinen Augen so sinnlos, wie IDs IDs zuzuweisen, um mit deren IDs eine Verknüpfung zur ID der ID der ID von blub aufzubauen.
Es ist egal, ob du in die Link-tabelle 30 mal ID 2003 eingibst, oder 30 mal Geschicklichkeitsspiel.
Redundanz würde erst entstehen, wenn du bei den Tags eine Beschreibung dessen mitlieferst - was bei Tags ungewöhnlich ist.
Und selbst dann würde, so sich die Namen nicht überschneiden dürfen - die Tags selbst als ID empfehlen.
Die ID als Zahl einzuführen macht eigentlich nur Sinn, wenn nicht absolut sichergestellt ist, das es nicht einen anderen eindeutigen Schlüssel gibt.
Wenn wir z.B. 2 Spiele namens Fangen haben dann brauchen wir für die Spiele eine ID, um z.B. die beiden Fangen von einander zu trennen.
Sollte aber bereits von Anbegin der Zeit, endgültig festgelegt werden, das der Name des Spiels das Spiel eindeutig benennt, so können wir uns auch in dieser Tabelle die ID spaaren.
Redundanz:
Redundanz (latein. redundare „im Überfluss vorhanden sein“) bezeichnet grundsätzlich einen Zustand von Überschneidung oder Überfluss. Es hat in verschiedenen Gebieten eine spezifische Bedeutung:
Nach dieser Definition würde eine zusätliche ID eine Redundanz darstellen, da wir Eindeutige Bezeichner im überfluss haben, die sich in ihrer Funktionalität 100% überschneiden.
lg,
Antagonist -
S******!
Wollt ihr mich umbringen?
Ich bin schwer überfordert...
Muss denn das alles so kompliziert sein?
Geht das denn nicht so dass ich alle Tags aus allen Tabellenspalten auslese, diese mit explode() in einen Array einles und dann die einzelnen Tags ein eine neue Tabelle einlese. Dort kann ich sie dann einfach mit SELECT DISTINCT einzeln ausgeben.
Geht das so irgendwie?
Grüßle Fabi -
Dann hast du die Tags ja einfach in ner Tabelle, aber nichtmehr mit den Spielen in Beziehung gesetzt.
Wenn du sie in deinem Array hast,
dann kannst du - wie schon öfters angesprochen,
mit der Funktion array_unique() einen weiteren Array erstellen lassen, in dem jeder Tag nur einmal vorkommt.
das sieht dann etwa so aus:
$array_tag_unique = array_unique($array_tags_multiple)
oder ähnlich.
Es wäre schön, wenn wir das ganze hier so unblutig wie möglich über die Bühne bringen können.
Ich versuche eigentlich Tote zu vermeiden. Wäre schön, wenn du rechzeitig zum Arzt gehst :D
Ich könnte niemals mit dem Gedanken Leben, für deinen Tod verantwortlich zu sein.
lg,
Antagonist -
frodo89 schrieb:
Eine ID muss nicht unbedingt eine Zahl sein.
Du kannst den Tag selbst, da er eine Eindeutige Bezeichnung ist, und damit so einmalig ist, wie die ID
als ID verwenden.
Was du vor hast, ist in meinen Augen so sinnlos, wie IDs IDs zuzuweisen, um mit deren IDs eine Verknüpfung zur ID der ID der ID von blub aufzubauen.
[...]
Das ist eine völlig normale Technik und in keinster Weise sinnlos.
http://www.sqldocu.com/nine/relationship.htm (Thema m:n Beziehung)
Es ist egal, ob du in die Link-tabelle 30 mal ID 2003 eingibst, oder 30 mal Geschicklichkeitsspiel.
Nein, das ist es nicht. "2003" ist eine Zahl und wird somit als integer abgespeichert.
"Geschicklichkeitsspiel" ist ein Zeichenkette und wird als string abgespeichert.
Schon auf Grund der Performance und Größe ist eine ID vorzuziehen.
Wie willst du ein Datenbankschema erstellen ohne Redundanz im Bezug auf den Tagnamen?
Sobald du zwei Spielen den Tag "Geschicklichkeit" zuweisen willst, gibt es eine Redundanz des Tagnamens.
Tag Tabelle:
Id Tag
1 Geschicklichkeit
2 Geschicklichkeit
=> Redundanz des Tagnamens
=> es handelt sich um eine n-m Beziehung
=> Lösung durch eine dritte Tabelle die Tabelle1 mit Tabelle2 verknüpft
=> siehe meine Lösung
edit:
Nur um es eben klar zu stellen. Deine Lösung ist nicht falsch, sie funktioniert, aber sie ist nicht optimiert.
Beitrag zuletzt geändert: 22.1.2010 3:00:24 von lucas9991 -
frodo89 schrieb:
Dann hast du die Tags ja einfach in ner Tabelle, aber nichtmehr mit den Spielen in Beziehung gesetzt.
Die Tags müssen auch garnicht mit den Spielen in Beziehung gebracht werden - dass könnte ich hinterher sowieso so lösen:
$abfrage = "SELECT * FROM jungscharspiele WHERE tags LIKE '%" . $_GET["tag"] . "%'";
Die Tags sollen nur nicht mehrmals ausgegeben werden und getrennt werden...
Grüßle Fabi -
lucas:
Ich weiß nicht, in wieweit der Vorteil, das es sich dabei um INT handelt, die zusätzliche Abfrage wett macht.
Nach deiner Lösung benötigst du ja eine Abfrage der Relationstabelle, und eine für die jeweils über diese verknüpfte Tabelle.
Damit kommen wir auf 3 Abfragen.
Am ende Fragst du aber doch auch die Strings ab.
Wenn du nur 2 Tabellen hast, spaarst du dir eine Abfrage.
Je nach Server könnte das Idealer sein.
Solange du keine weiteren Daten zum Tag hinzufügst (Kurzbeschreibungen o.Ä.) vermute ich,
das die benötigte Zeit des gesammten Prozesses geringer sein dürfte, als bei den 3 Tabellen.
Auch wenn dabei weniger Speicher benötigt wird.
Dazu hab ich aber noch keine Performance-Tests gesehen.
Es dürfte wohl auch von der Datenmenge abhängen.
Immerhin kommen noch die zusätzlichen Daten für die Tabellenstruktur dazu.
Auch da weiß ich aber nicht, in wie weit sich das auswirkt bei der Gesammtgröße der Datenbank.
Letzten Endes ist mir das aber egal...
Ich schätze das der Effekt der einen oder anderen Lösung sehr minimal Ausfallen dürfte, da es sich hier ja nur um eine einfache Abfrage handelt.
Deine Methode ist sicher die eher Standartisierte, da sie sich universell einsetzen lässt.
Ob es in diesem Fall zu einer besseren Performance beiträgt, kann fabian ja berichten, falls er umstellt, und beide möglichkeiten ausprobiert.
Oder mir irgendjemand hier vorrechnen...
@Fabian: Ja: unique_array sorgt genau dafür DAS ES NICHT mehrmals ausgegeben wird.
Der Rest hier ist eine Diskussion was eine bessere lösung wäre.
Es wäre wohl auch nicht schwer, deine Tabelle entsprechend zu konvertieren.
Willst du das nicht: unique_array macht dein leben schöner.
lg,
Antagonist
Beitrag zuletzt geändert: 25.1.2010 15:08:05 von frodo89 -
@frodo: lucas Herangehensweise ist korrekt. Ich hab auch immer gedacht, dass man IDs nicht zu verteilen hat, aber dem ist nicht so.
Erstmal musst du bedenken, dass einem Tag weitere Informationen zugeordnet werden können. Beispielsweise eine Beschreibung, Bewertung, usw. Nur weil es zur Zeit nicht so ist, heißt es nicht, dass es sich nie ändern wird. Wenn du dann plötzlich eine Beschreibung speichern willst, dann speicherst du große Mengen an Information redundant.
Sprich, du kommst nicht darum herum eine Tag-Relation anzulegen.
Wenn diese nun besteht, ist es nicht klug ein VARCHAR als PRIMARY zu setzen.
EIN UNSIGNED (...)INT als PRIMARY mit AUTO_INCREMENT ist schneller und platzsparender, da ein INT, bei Tags vielleicht sogar ein SMALLINT kleiner ist als ein VARCHAR(30). (Und noch ein Paar MySQL-interne Vorteile, die es zwar gibt und die entscheidend sind, ich sie aber ohne längeres Suchen nicht belegen könnte.) -
frodo89 schrieb:
lucas:
Ich weiß nicht, in wieweit der Vorteil, das es sich dabei um INT handelt, die zusätzliche Abfrage wett macht.
[...]
Du vergisst den Vorteil von SQL im Bezug auf simple Textdateien.
SQL unterstützt JOINS, d.h. du kannst Tabellen im Query verknüpfen und musst keine zusätzliche Abfrage generieren.
Es wird nur eine Abfrage an den MySQL Server gesendet, der diese dann verarbeitet. Was im Bezug auf die Abfragen letztendlich deinem Vorschlag gleichen würde. Der MySQL Server mag zwar etwas länger brauchen, um die erste Abfrage auszuführen, das sollte aber marginal sein.
[...]
Immerhin kommen noch die zusätzlichen Daten für die Tabellenstruktur dazu.
Auch da weiß ich aber nicht, in wie weit sich das auswirkt bei der Gesammtgröße der Datenbank.
Die Tabellenstruktur ist - theoretisch gesehen - sicherlich kein ausschlaggebendes Kriterium.
Letzten Endes ist mir das aber egal...
Ich schätze das der Effekt der einen oder anderen Lösung sehr minimal Ausfallen dürfte, da es sich hier ja nur um eine einfache Abfrage handelt.
Bei großen Datenmengen und vor allem vielen gleichen Tags wird bei deiner Methode die Tabelle sehr redundant werden und somit auch langsamer als bei meiner Methode.
Beitrag zuletzt geändert: 25.1.2010 20:55:35 von lucas9991 -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage