php.de

Zurück   php.de > Webentwicklung > Datenbanken

Datenbanken SQL und Co

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 04.02.2008, 15:57  
Erfahrener Benutzer
 
Benutzerbild von stefanjann
 
Registriert seit: 02.08.2005
Beiträge: 252
PHP-Kenntnisse:
Fortgeschritten
stefanjann
Standard [gelöst]LEFT JOIN, DINSTINCT und trotzdem doppelte?!?!

Hallo,

ich habe einen Fall den ich mir nicht erklären kann. Folgendes:

Ich schreibe gerade eine Suche dir mir viele viele Datenbanktabellen miteinander verknüpft und zusammen die Ergebnisse anzeigen soll. Mit PHP erzeuge ich dynamisch den Query.

Z.B. folgenden:
Code:
SELECT DISTINCT k.ident, k.anrede, k.vorname, k.nachname, k.kundennummer, k.plz, k.ort,
       j1.fullshort AS kat_kurz_1, j1.fulllang AS kat_lang_1
  FROM kundenstamm_kunden k
  LEFT JOIN kundenstamm_kat_to_kunde i1, kundenstamm_kategorien j1
    ON ((i1.zukunde=k.ident) AND (j1.ident=i1.zukat))
  WHERE ((LOWER(j1.fulllang) LIKE LOWER('%sn / gs%')) OR (LOWER(j1.fullshort) LIKE LOWER('%sn / gs%')))
  ORDER BY k.nachname ASC, k.vorname ASC
  LIMIT 0, 10;
Wie man sieht sollen hier Kunden verwaltet werden.
Ich habe die Datenbanktabellen mit LEFT JOIN verknüpft, weil ich nur jeweils einen Eintrag aus der Tabelle kundenstamm_kunden möchte.
Trotzdem bekomme ich Einträge doppelt. Also habe ich sogar noch das Feld k.ident (also der PRIMARY aus k) auf DISTINCT gesetzt. Das heisst doppelte Einträge aus dem Feld k.ident sollten rausgerechnet werden. Trotzdem bekomme ich immer noch doppelte Felder.

Mein Ergebnis ist z.B.
Code:
ident | anrede | vorname | nachname | kundennummer | plz   | ort      | kat_kurz_1    | kat_lang_1
1     | herr   | Stefan  | Jann     | 0000000008   | 00000 | Einort   | sn / gs / fds | son / Gesang / Fidelstimme
1     | herr   | Stefan  | Jann     | 0000000008   | 00000 | Einort   | sn / gs / tn  | son / Gesang / Tenor
6     | herr   | Hans    | Huber    | 0000000003   | 12345 | Nochnort | sn / gs / fds | son / Gesang / Fidelstimme
Wie man sieht ist k.ident = 1 doppelt vorhanden. Aber wieso. Sind LEFT JOIN und DISTINCT nicht genug anweisung die Doppelten rauszurechenen?
Verstehe ich leider nicht und bitte um Hilfe.

Ich hatte auch schon die LEFT JOIN i1, j2 ON ... auf LEFT JOIN i1 ON ... LEFT JOIN j1 ON ... mit keinem anderen Ergebnis.
Auch die WHERE-Anwisung habe ich schon mal testweise ins ON mit aufgenommen. Leider mit noch schlechterem Erfolg, weil dann plötzlich alle Datensätze angezeigt wurden. (Was auch klar ist, weil ja der Where nichts mehr filtert *g*). Aber auch da waren die doppelten vorhanden.

MySQL-Version: 4.1.13-Max unter LINUX SUSE 10

Danke,
Stefan
__________________
SELECT * benutze ich nur um den Post kurz zu halten.
stefanjann ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 04.02.2008, 16:20  
Erfahrener Benutzer
 
Benutzerbild von lazydog
 
Registriert seit: 02.04.2008
Beiträge: 4.034
lazydog befindet sich auf einem aufstrebenden Ast
Standard Re: LEFT JOIN, DINSTINCT und trotzdem doppelte?!?!

Zitat:
Zitat von stefanjann
Ich hatte auch schon die LEFT JOIN i1, j2 ON ... auf LEFT JOIN i1 ON ... LEFT JOIN j1 ON ... mit keinem anderen Ergebnis.
Auch die WHERE-Anwisung habe ich schon mal testweise ins ON mit aufgenommen. Leider mit noch schlechterem Erfolg, weil dann plötzlich alle Datensätze angezeigt wurden. (Was auch klar ist, weil ja der Where nichts mehr filtert *g*). Aber auch da waren die doppelten vorhanden.
Wie wärs mal mit etwas systematischerm Vorgehen, statt willkürlichem try and error? Ganz offensichtlich bestehen zum Kunden mehrere Einträge in kundenstamm_kategorien. Und da dann die Auswertungen unterschiedlich sind, ist auch klar, dass beide ausgegeben werden. Distinct filtert nur die ganzen identischen Rows raus!
Das kann eventuell auch an den JOINS liegen, die du sicher nicht so mit AND verknüpfen kannst.
Ausserdem macht der Verglich LIKE LOWER('%sn / gs%') definitif keinen Sinn (was soll denn in diesem String noch auf Kleinbuchstaben umgesetzt werden?), aber daran liegt es nicht.
Falls nicht mehrer Beziehungen existieren, müsste folgende Abfrage funktionieren. Falls doch, macht sie so oder so keinen Sinn.
Code:
SELECT DISTINCT 
	k.ident, k.anrede, k.vorname, k.nachname, k.kundennummer, k.plz, k.ort,
	j1.fullshort AS kat_kurz_1, j1.fulllang AS kat_lang_1
  FROM 
  	kundenstamm_kunden k
  LEFT JOIN 
  	kundenstamm_kat_to_kunde i1 ON i1.zukunde = k.ident
  LEFT JOIN
  	kundenstamm_kategorien j1 j1.ident = i1.zukat
  WHERE 
  	((LOWER(j1.fulllang) LIKE '%sn / gs%') OR (LOWER(j1.fullshort) LIKE '%sn / gs%'))
  ORDER BY 
  	k.nachname ASC, k.vorname ASC
  LIMIT 0, 10;
__________________
Gruss
L
lazydog ist offline   Mit Zitat antworten
Alt 04.02.2008, 17:34  
Erfahrener Benutzer
 
Benutzerbild von stefanjann
 
Registriert seit: 02.08.2005
Beiträge: 252
PHP-Kenntnisse:
Fortgeschritten
stefanjann
Standard

Zitat:
Wie wärs mal mit etwas systematischerm Vorgehen, statt willkürlichem try and error?
Nunja, ich wollte damit nur zeigen, dass ich nicht gleich beim ersten Versuch schon ins Forum poste, sondern schon versucht habe die Funktionen von MySQL zu testen, bevor ich hier was schreibe.

Zitat:
Ausserdem macht der Verglich LIKE LOWER('%sn / gs%') definitif keinen Sinn (was soll denn in diesem String noch auf Kleinbuchstaben umgesetzt werden?), aber daran liegt es nicht.
Ähh, ja! Stimmt, macht keinen Sinn, das ist noch von der PHP-Programmierung, da der User ins Formular ja auch Was Großes schreiben kann. (Z.B. "SN / GD") und das sollte ja auch gleich getested werden. Das kommt noch raus. Das ganze ist ja noch im Aufbau und sicherlich noch nicht optimiert.


Zitat:
Falls nicht mehrer Beziehungen existieren, müsste folgende Abfrage funktionieren. Falls doch, macht sie so oder so keinen Sinn.
Also der Aufbau ist:

Kunden | n:m | Kategorien
Also habe ich 3 Tabellen
Kunden
Kunden zu Kategroein
Kategorien

Wo bin ich "sinnlich" daneben? Vertsehe noch nich worauf du da raus willst.


Zitat:
Aus dem MySQL-Manual:
DISTINCT und DISTINCTROW sind Synonyme; sie legen fest, dass doppelte Datensätze aus der Ergebnismenge entfernt werden.
Hatt ich wohl falsch verstanden, da ich es so interpretiert hatte, das sich DISTINCT nur auf EIN Feld bezieht. Aber so wie ich es nach deiner Erklärung gelesen habe, bezieht sich das auf die ganze Zeile.

Zitat:
Das kann eventuell auch an den JOINS liegen, die du sicher nicht so mit AND verknüpfen kannst.
Die machen das: http://dev.mysql.com/doc/refman/5.1/de/join.html
Zitat:
Dies ist eine konservative Erweiterung, sofern wir jedes Komma in einer Liste mit table_reference-Elementen als äquivalent zu einem inneren Join betrachten. Zum Beispiel:

SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

ist äquivalent mit

SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

In MySQL ist CROSS JOIN syntaktisch ein Äquivalent zu INNER JOIN (diese lassen sich gegeneinander austauschen). Nach SQL-Standard hingegen sind beide nicht äquivalent. INNER JOIN wird bei einer ON-Klausel und CROSS JOIN andernfalls verwendet.
Wie gesagt, dass ich hier irgendwo mit meiner Logik nicht weiter komme sehe ich ja ein. Ich finde nur keinen Ansatz das ganze richtig zu machen. Vielleicht sehe ich ja den Wald vor lauter Bäumen nicht.

Im Endeffekt sollte mir bei meiner Anfrage jeder Kunde gegeben werden, der in einer der angegebenen Kategorien ist. Die Kategroie muss halt mit Volltextsuche stattfinden. Z.B. katname LIKE '%sn / gs%' OR katname LIKE '%tkf /%', etc
__________________
SELECT * benutze ich nur um den Post kurz zu halten.
stefanjann ist offline   Mit Zitat antworten
Alt 05.02.2008, 08:12  
Erfahrener Benutzer
 
Benutzerbild von lazydog
 
Registriert seit: 02.04.2008
Beiträge: 4.034
lazydog befindet sich auf einem aufstrebenden Ast
Standard

Ok, mag sein, dass diese Art von Joins funktioniert. Ich habs so nocht nicht gesehen, und es ist sicher nicht Standard-SQL. Deshalb würde ich davon abraten.
Aber dein Problem ist ein anderes:
Du hast eine 1:n Beziehung zwischen Kunden und Kategorien, d.h. ein Kunde kann in mehreren Kategorien sein. Wenn du nun einen solchen Kunden nur einmal haben willst, woher soll nun die DB wissen, welche Kategorie sie ausgeben soll? Also gibst du entweder die Kategorie nicht aus, dann funktioniert das mit DISTINCT, oder du gibst den Kunden halt mehrfach mit der jeweiligen Kategorie aus, wie du es schon hast.
__________________
Gruss
L
lazydog ist offline   Mit Zitat antworten
Alt 06.02.2008, 09:16  
Erfahrener Benutzer
 
Benutzerbild von stefanjann
 
Registriert seit: 02.08.2005
Beiträge: 252
PHP-Kenntnisse:
Fortgeschritten
stefanjann
Standard

Ich glaub ich hab das Problem verstanden und nach mehreren Stunden durchdenken des Problems mein Problem erkannt.

Es ist klar, das die Einträge doppelt kommen, weil ja 2 Treffer in der Kategorie sind. Meine Anzeige soll egal welche Kategorie anzeigen. Ich brauche Kunden und irgendeine Kategorie in der er ist. Und dafür benötige ich den GROUP BY. Dann kann ich nach Kunden-ID Gruppieren und habe in Kategorie eine Kategorie stehen und alle Einträge nur einmal. So wie ich es mir wünsche (ich es brauche).

Zitat:
SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)
Nun, da es von der offizielle MySQL-Homepage kommt dachte ich schon dass es Standard ist. Allerdings weiß cih nicht ob das auch schon für 4.1 gilt oder erst ab 5. Ich habs aus dem Manula von 5.1. Und auf einem anderen Server der 5.1 hat auch erfolgrich gestestet. Ich hatte nur nicht bedacht, das in meiner echten Umgebung dann 4.1 läuft (weil es dort auch noch PHP4-Seiten gibt). Aber ich werde es wohl über CROSS JOIN einbinden. Dann dürfte die Anfrage auch schneller werden.

Danke für deine Hilfe.
__________________
SELECT * benutze ich nur um den Post kurz zu halten.
stefanjann ist offline   Mit Zitat antworten
Alt 06.02.2008, 09:37  
Erfahrener Benutzer
 
Benutzerbild von lazydog
 
Registriert seit: 02.04.2008
Beiträge: 4.034
lazydog befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von stefanjann
Ich brauche Kunden und irgendeine Kategorie in der er ist.
Wenn du einfach irgendeine Kategorie brauchst, kannst du sie auch weg lassen, da sie sowieso nichts aussagt (ausser deine DB wäre nicht normalisiert). Dann kannst du auch guten Gewissens GROUP BY verwenden, sonst brauchst du mindestens einen Subselect.
Zitat:
Zitat von stefanjann
Nun, da es von der offizielle MySQL-Homepage kommt dachte ich schon dass es Standard ist.
Das ist wahrscheinlich schon MySQL-Standard, aber nicht SQL-Standard, und damit nicht portabel.
__________________
Gruss
L
lazydog ist offline   Mit Zitat antworten
Alt 06.02.2008, 10:04  
Erfahrener Benutzer
 
Benutzerbild von stefanjann
 
Registriert seit: 02.08.2005
Beiträge: 252
PHP-Kenntnisse:
Fortgeschritten
stefanjann
Standard

Nunja, für meine Anzeige ist es egal welche Kategorie er anzeigt.
Der Auftrag ist:
Gib mir alle Kunden die in (Kat1 oder Kat2 oder Kat3) UND (Kat4 oder Kat5 oder Kat6)
Und eine Kombination muss angezigt werden.
z.B. Kunde 1 in Kat2 UND kat5.
Das der Kunde auch noch in kat6 ist interessiert keinen.
Daher benötige ich GROUPY BY. Auch wenn dadurch die Abfrage deutlich langsamer ist. Da es ein EXPORT nach CSV ist, ist aber die Zeit relativ.

Ich hab mich mal ins SQL gelesen und festgestellt das es das dort wirklich nicht gibt. In anderen MySQL-Documentationen habe ich auch das Symbol "MySQL only!" gefunden. Also werde ich mit INNER JOIN die Tabellen verknüpfen (ist einfacher, das ich den Query aus verschiedenen PHP-Funktionen zusammen baue).

Danke nochmal.
__________________
SELECT * benutze ich nur um den Post kurz zu halten.
stefanjann ist offline   Mit Zitat antworten
Alt 06.02.2008, 10:14  
Erfahrener Benutzer
 
Benutzerbild von lazydog
 
Registriert seit: 02.04.2008
Beiträge: 4.034
lazydog befindet sich auf einem aufstrebenden Ast
Standard

Die Aufgabe hat nun aber fast nichts mehr mit derjenigen im ersten Post zu tun, dort hast du ja nur zwei Kategorien
__________________
Gruss
L
lazydog ist offline   Mit Zitat antworten
Alt 06.02.2008, 10:49  
Erfahrener Benutzer
 
Benutzerbild von stefanjann
 
Registriert seit: 02.08.2005
Beiträge: 252
PHP-Kenntnisse:
Fortgeschritten
stefanjann
Standard

Nunja, im ersten Post war das mein "Grob-Entwurf" für den Weg. Die Anzahl für die Kat-Verknüpfung ist dynamisch aus PHP5. Das kann auf (kat1 oder Kat2) UND (kat3 oder kat4 oder kat5) UND (kat6), etc...
Im ersten Post war ein Beispiel wo ich das Problem gefunden hatte. Ich wollte den Query nicht zu voll machen und die Übersichtlichkeit waren, damit sich den Query ja noch jemand durchlesen kann.

Ein andere dynamischer Query jetzt ist z.B.
Code:
SELECT ca40Felder
  FROM kundenstamm_kunden k
  INNER JOIN kundenstamm_kat_to_kunde i1
    ON i1.zukunde=k.ident
  INNER JOIN kundenstamm_kategorien j1
    ON j1.ident=i1.zukat
  INNER JOIN kundenstamm_kat_to_kunde i2
    ON i2.zukunde=k.ident
  INNER JOIN kundenstamm_kategorien j2
    ON j2.ident=i2.zukat
  INNER JOIN kundenstamm_kat_to_kunde i3
    ON i3.zukunde=k.ident
  INNER JOIN kundenstamm_kategorien j3
    ON j3.ident=i3.zukat
  WHERE (
         (
          (LOWER(k.nachname) LIKE '%huber%')
       OR (LOWER(k.internet) LIKE '%huber%')
         )
        )
    AND (k.ort='Regensburg')
    AND (k.land='Deutschland')
    AND (k.plz BETWEEN '93047' AND '93050')
    AND (
         ((j1.fulllang='tf / perc') OR (j1.fullshort='tf / perc'))
      OR ((j1.fulllang='tf / gt') OR (j1.fullshort='tf / gt'))
        )
    AND (
         ((LOWER(j2.fulllang) LIKE '%gesang%') OR (LOWER(j2.fullshort) LIKE LOWER('%gesang%')))
      OR ((LOWER(j2.fulllang) LIKE '%tenor%') OR (LOWER(j2.fullshort) LIKE LOWER('%tenor%')))
      OR ((LOWER(j2.fulllang) LIKE '%alt%') OR (LOWER(j2.fullshort) LIKE LOWER('%alt%')))
      OR ((LOWER(j2.fulllang) LIKE '%sopran%') OR (LOWER(j2.fullshort) LIKE LOWER('%sopran%')))
        )
    AND (
         ((LOWER(j3.fulllang) LIKE '%jersey / gesang%') OR (LOWER(j3.fullshort) LIKE LOWER('%jersey / gesang%')))
        )
  GROUP BY k.ident
  LIMIT 0,30;
Jetzt soll er alle Huber finden, die in Deutschland in Regensburg im PLZ-Bereich von 93047 bis 93050 (Regensburg hat von 93047 bis 93059) wohnen und die gewünschten Kategorien haben, etc...
__________________
SELECT * benutze ich nur um den Post kurz zu halten.
stefanjann ist offline   Mit Zitat antworten
Alt 06.02.2008, 11:21  
Erfahrener Benutzer
 
Benutzerbild von lazydog
 
Registriert seit: 02.04.2008
Beiträge: 4.034
lazydog befindet sich auf einem aufstrebenden Ast
Standard

Wenn das für dich funktioniert, ist es ja ok. Du hast allerdings Glück, dass du mit MySQL arbeitest, jedes andere RDBMS würde diese Abfrage nicht akzeptieren, weil alle Attribute, die in einer Abfrage mit GROUP BY vorkommen auch in der GROUP BY-Klausel stehen müssen. Nach meiner Meinung ist es ein Fehler von MySQL, dass das möglich ist. Alle Werte, die in deinem Beispiel nicht direkt von k.ident abhänging sind, sind ja Zufallsresultate. Da dir aber diese Kategorien ja egal sind, hast du Glück gehabt.
Ausserdem liege ich wahrscheinlich auch richtig, mit der Vermutung, dass deine DB nicht normalisiert ist, wenn ich Dinge wie j1.fulllang = 'tf / perc' sehe.
Aber was solls, wenn dein Problem gelöst ist.
__________________
Gruss
L
lazydog ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Mehrfach Join lazydog Datenbanken 2 08.05.2008 16:09
Frage zu meinem JOIN Statement Benjamin Such Datenbanken 4 12.04.2008 13:20
JOIN Problem pPanther Datenbanken 7 06.03.2008 17:26
performance problem mit join leo Datenbanken 4 14.01.2008 22:31
JOIN / LEFT JOIN und Co prinzli Datenbanken 12 05.11.2007 22:15
[solved] LEFT JOIN - #1066 - Not unique table/alias moose Datenbanken 6 12.12.2006 06:41
SQL-Abfrage evt. mit JOIN mariohaehni Datenbanken 4 07.09.2006 14:26
Join auf 2 verschiedene Felder Tommek Datenbanken 6 25.07.2006 20:39
Problem mit Inner join Jabi Datenbanken 15 09.05.2006 14:10
INNER JOIN + Suchkriterien + Abfrage duerov PHP Tipps 2006 4 04.04.2006 12:47
inner join zeigt gleiche spalten nur 1x Datenbanken 3 22.02.2006 17:11
inner join aus db PHP Tipps 2006 8 22.01.2006 01:23
Select Problem Datenbanken 17 16.01.2006 21:54
[Erledigt] Abfrageproblem mit Inner Join Datenbanken 15 29.11.2005 18:17
[Erledigt] Join Datenbanken 15 09.03.2005 08:44

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
doppelter left join, left join doppelt, left join doppelte datensätze, doppelt left join, doppeltes left join, left join, mysql join doppelte einträge, mysql left join doppelte einträge, mysql join doppelte, left join doppelte ergebnisse, http://www.php.de/datenbanken/45440-geloest-left-join-dinstinct-und-trotzdem-doppelte.html, mysql join doppelt, left join doppelte zeilen, left join nur bestimmte felder, left join doppelte, mysql join einträge mehrfach, left join nur erster datensatz, left join nur ein datensatz, inner join mysql distinct, mysql 2 mal left join

Alle Zeitangaben in WEZ +1. Es ist jetzt 21:05 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum

Creative Commons License
Dieser Inhalt ist unter einer Creative Commons-Lizenz lizenziert.