Wie baue ich die MySQL-Abfrage am Besten?
Klaus
- datenbank
Hallo,
ich habe 1 Tabelle Personen und eine Tabelle mit den Informationen in einer 1-zu-N-Beziehung, soll heissen, in der Tabelle können pro Person aus jeder Tabelle beliebig viele Einträge stehen.
Jetzt möchte ich natürlich eine Suche ermöglichen, in der nach Werten aus jeder der Personen-Tabelle und auch aus der Info-Tabelle gesucht wird, aber nicht für jeden gefundenen Wert aus der Info-Tabelle ein neuer Satz wird, sondern in der Ergebnistabelle pro Person nur eine Zeile gezeigt wird, alle Werte aus der Info-Tabelle in einem Feld in der Tabelle.
Die Abfrage sieht derzeit so aus:
select p.*,i.* from personen as p left join infos as i on p.idnr = i.typnr where concat_ws (' ',i.information,p.name,p.ort,p.kategorie) like '%$wert%'
Dabei wird aber noch für jeden Eintrag aus Infos auch ein Satz erzeugt.
Ich habe noch versucht, dies dann in der Schleife bei der Ausgabe zu berücksichtigen, aber es scheint mir sehr aufwändig, zu prüfen ob sich der Name geändert hat und wenn dann erst die Informationen des Eintrags davor auszugeben.
Eine zweite Idee ist, mit einer Single-Abfrage zu garantieren, dass nur 1 Satz pro Person gesammelt wird und in der Schleife dann mit einem neuen Select immer wieder neu die Daten aus der Tabelle Infos zu holen.
Habt ihr vielleicht bessere Ideen?
Klaus
Hi,
Dabei wird aber noch für jeden Eintrag aus Infos auch ein Satz erzeugt.
Soweit, so normal.
Ich habe noch versucht, dies dann in der Schleife bei der Ausgabe zu berücksichtigen, aber es scheint mir sehr aufwändig, zu prüfen ob sich der Name geändert hat und wenn dann erst die Informationen des Eintrags davor auszugeben.
Dieser sog. Gruppenwechsel/Gruppenbruch ist ein absolut grundlegendes Prinzip in der Programmierung – und unter „aufwendig“ verstehe ich nun wirklich was anderes. (Zumal wenn er nur auf einer Ebene stattfindet.)
Eine zweite Idee ist, mit einer Single-Abfrage zu garantieren, dass nur 1 Satz pro Person gesammelt wird und in der Schleife dann mit einem neuen Select immer wieder neu die Daten aus der Tabelle Infos zu holen.
Datenbankabfragen in Schleifen == so gut wie immer Pfui Bah.
(P.S. MySQL kennt z.B. noch GROUP_CONCAT – aber abgesehen davon, dass das in der möglichen Länge der Daten beschränkt ist, haftet dem für mich auch immer ein bisschen was „unsauberes“ an. Der Gruppenwechsel ist hier für mich der way to go.)
MfG ChrisB
Hi ChrisB und Dedlfix,
Dieser sog. Gruppenwechsel/Gruppenbruch ist ein absolut grundlegendes Prinzip in der Programmierung – und unter „aufwendig“ verstehe ich nun wirklich was anderes. (Zumal wenn er nur auf einer Ebene stattfindet.)
Das Prinzip des Gruppenwechsels kenne ich und wende ich auch schon immer dann an, wenn ich die Ausgabe nach einem Kriterium kategorisieren möchte.
Da ich ich erst beim Gruppenwechsel weiß, ob ich jetzt die Zeile komplett ausgeben kann oder nicht, müsste ich mir alle immer alle Felder des vorangehenden Satzes gemerkt haben und nicht nur das eine Kategoriefeld.
Eine zweite Idee ist, mit einer Single-Abfrage zu garantieren, dass nur 1 Satz pro Person gesammelt wird und in der Schleife dann mit einem neuen Select immer wieder neu die Daten aus der Tabelle Infos zu holen.
Datenbankabfragen in Schleifen == so gut wie immer Pfui Bah.
Ich habe es jetzt im Moment so gelöst, dass ich mittels "group by idnr" nur einen Satz erhalte und dann mit einem zusätzlichen Select dann die zustäzlichen Infos abrufe. Zumindest funktioniert es.
(P.S. MySQL kennt z.B. noch GROUP_CONCAT – aber abgesehen davon, dass das in der möglichen Länge der Daten beschränkt ist, haftet dem für mich auch immer ein bisschen was „unsauberes“ an. Der Gruppenwechsel ist hier für mich der way to go.)
GROUP_CONCAT werde ich mir noch anschauen, kenne ich bisher nicht.
Vielleicht lässt sich damit die Abfrage doch etwas eleganter lösen und ich kann auf den Select in der Schleife verzichten.
Klaus
Tach!
Jetzt möchte ich natürlich eine Suche ermöglichen, in der nach Werten aus jeder der Personen-Tabelle und auch aus der Info-Tabelle gesucht wird, aber nicht für jeden gefundenen Wert aus der Info-Tabelle ein neuer Satz wird, sondern in der Ergebnistabelle pro Person nur eine Zeile gezeigt wird, alle Werte aus der Info-Tabelle in einem Feld in der Tabelle.
Um mehrere Datensätze zu einem zusammenzufassen gibt es (außer selbst geschriebenen Routinen) die Funktion GROUP_CONCAT(). Dazu erstellst du eine gejointe Abfrage und gruppierst über die Werte aus der Personentabelle. Das Ergebnis davon ist ein Info-Feld, in dem alle Daten trennzeichensepariert stehen. Das ist gut so, wenn du sie sowieso in der Form brauchst, bei Einzelverarbeitung aber eher ungünstig.
Ich habe noch versucht, dies dann in der Schleife bei der Ausgabe zu berücksichtigen, aber es scheint mir sehr aufwändig, zu prüfen ob sich der Name geändert hat und wenn dann erst die Informationen des Eintrags davor auszugeben.
Sowas nennt sich Gruppenwechsel und ist nicht gerade unüblich. Dazu braucht man eigentlich nur eine Variable zum Merken des vorhergehenden Wertes und ein if zum Vergleichen des aktuellen mit diesem.
Eine zweite Idee ist, mit einer Single-Abfrage zu garantieren, dass nur 1 Satz pro Person gesammelt wird und in der Schleife dann mit einem neuen Select immer wieder neu die Daten aus der Tabelle Infos zu holen.
Rekursive Abfragen sind nicht sehr beliebt, weil sie viele Roundtrips verursachen. Mit zwei Abfragen kommst du aus, wenn du zunächst die Personen abfragst, dir deren Daten erstmal zwischenspeicherst und dabei die IDs extra aufhebst. Die zweite Abfrage holt zu diesen IDs die Infotabellendaten. Diese sortierst du in ein Array of Arrays. Im äußeren sind die Keys die IDs der Personen und die Wete sind wiederum Arrays, in deren Elemente du die einzelnen Info-Daten schreibst. Am Ende kannst du durch deine gemerkten Personen "foreachen" und hast dazu jeweils einen Eintrag in der Info-Tabelle, durch den du ebenfalls durchlaufen kannst.
dedlfix.