Vinzenz Mai: Verzwicktes PRoblem mit Select

Beitrag lesen

Hallo,

MySQL-Client-Version: 5.1.41
phpMyAdmin Versionsinformationen: 3.2.4

nach diesen Angaben darfst Du Dich nicht über Antworten wundern, die PHP als Umgebung annehmen bzw. Anwendungscode aus der PHP-Welt. Die MySQL-Client-Version ist übrigens nicht so wichtig wie die MySQL-Server-Version :-)

ich bin gerade dabei SQL zu lernen und habe mir dafür eine Beispieldatenbank gebastelt.

Das halte ich für eine gute Idee, eine noch bessere wäre es gewesen, wenn Du die paar Beispieldaten mitgepostet hättest.

z.Z. bin ich dabei, mir eingehendes Verständnis zum Select Befehl zu schaffen und habe dazu auch gleich eine Frage:

das ist auch eine gute Idee, allerdings solltest Du Dir grundsätzlich bessere SQL-Grundlagen verschaffen, bevor Du - meiner Meinung nach seltsamen - Code wie den folgenden schreibst:

Ich tätige z.Z. folgende Abfrage:

SELECT LEHRERNAMEN.Nachname,LEHRERNAMEN.Vorname,Name FROM

(SELECT DISTINCT Name,FachID FROM fach INNER JOIN lehrerfach USING (FachID)) AS FACH,
(SELECT FachID,LehrerID from lehrerfach INNER JOIN lehrer USING (LehrerID)) AS LF,
(SELECT Nachname,Vorname,AngestellterID FROM person INNER JOIN angestellter USING(PersonID)) AS LEHRERNAMEN,
(SELECT AngestellterID,LehrerID FROM lehrer INNER JOIN angestellter USING(AngestellterID)) AS LEHRERID
WHERE LEHRERNAMEN.AngestellterID = LEHRERID.AngestellterID AND LF.LehrerID = LEHRERID.LehrerID AND LF.FachID = FACH.FachID

  
Du vermischst hier implizite (WHERE-Klausel) und explizite Joins mit der recht neuen USING-Klausel (SQL:2003), die noch besser unterstützt sein könnte. Willst Du Dir vernünftige Grundlagen zu Joins aneignen, so empfehle ich Dir zwei Artikel in SELFHTML aktuell bzw. dem SELFHTML-Wiki, auch wenn diese kein Wort über die USING-Klausel verlieren:  
  
 - [Einführung in Joins](http://aktuell.de.selfhtml.org/artikel/datenbanken/joins/)  
 - [Fortgeschrittene Jointechniken](http://wiki.selfhtml.org/wiki/Artikel:DBMS_und_SQL/Fortgeschrittene_Jointechniken)  
  
Ich persönlich würde hier kein einziges Subselect verwenden, keinen impliziten Join, sondern hübsch normale INNER JOINs mit ON-Klausel :-)  
  
Warum verwendest Du bei Deinem JOIN der Tabellen "lehrerfach" und "lehrer" ein DISTINCT?  
  
Du solltest statt dessen per UNIQUE-Index dafür sorgen, dass die gleiche Kombination von Lehrer und Fach nur ein einziges Mal vorkommt. Sie sollte angeben, welche Fächer ein Lehrer unterrichten kann.  
  
Zum Stil: ich nähme keine Großschreibung für Aliasnamen, Großschreibung behalte ich mir - wie sehr weit üblich - für SQL-Schlüsselwörter und -Funktionen vor.  
  

> Das Ergebnis der Abfrage lautet:  
  

> Nachname  Vorname   Name  
> ------------------------------  
> Lehrer    Klaus     Mathematik  
> Lehrer    Klaus     Deutsch  
> Lehrer    Klaus     Englisch  
> Lehrer    Mathilde  Erdkunde  
> Lehrer    Mathilde  Geschichte  
> Lehrer    Georg     Mathematik  
  

> Nun liegt der nächste Schritt nahe - Ich hätte gerne Pro Nachname Vorname Kombination alle zugehörigen Fächer in einer Zeile, und nicht pro Zeile einen Lehrer und ein Fach.  
  
Wie die [bei weitem beste Antwort](https://forum.selfhtml.org/?t=202857&m=1370743), die von Alex, es Dir sagte, ist das Problem alles andere als verzwickt, es ist simpel: einfach eine GROUP-BY-Klausel mit der entsprechenden Aggregatsfunktion, fertig.  
  
Ich käme somit zu  
  
~~~sql
SELECT  
    p.Nachname,  
    p.Vorname,  
    GROUP_CONCAT(f.Name SEPARATOR ', ')  
FROM  
    fach f  
INNER JOIN  
    lehrerfach lf  
ON  
    f.FachID = lf.FachID  
INNER JOIN  
    angestellter a  
ON  
    lf.LehrerID = a.AngestellterID  
INNER JOIN  
    person p  
ON  
    a.PersonID = p.PersonID  
GROUP BY  
    p.Nachname,  
    p.Vorname  

und stelle dabei fest, dass ich für diese Abfrage die Lehrertabelle überhaupt gar nicht benötige, weil sie für das Herausfinden von Vornamen, Nachnamen und der Liste der möglichen Unterrichtsfächer aller Lehrer völlig irrelevant ist. Das geht in Deiner unnötig komplexen Schreibweise einfach unter.

Meiner Meinung nach ist plattformübergreifendes SQL kein besonders wichtiges Ziel. Will man's plattformübergreifend haben, so sollte man einen entsprechenden Abstraktionslayer nutzen und nicht das SQL auf den kleinsten gemeinsamen Nenner reduzieren, der verdammt klein ausfällt.

Sobald Du die eine oder andere Funktion nutzen willst, sobald Du Datumsliterale verwendest, sobald Du so etwas nettes wie LIMIT ... OFFSET haben willst (siehe zum Beispiel diesen Archivthread), überschreitest Du die Plattformunabhängigkeit. Also mach' Dir dazu nicht allzu viel Gedanken außer dem, dass der SQL-Code, den Du gerade schreibst, genau auf dem DBMS das von Dir gewünschte Ergebnis liefert, das Du gerade nutzt - und anderswo Syntaxfehler liefern kann. Das ist in der Welt der relationalen Datenbanksysteme leider Gottes normal.

Nochmals: es geht nicht um Performance, es geht nicht um irgendwelche Applikationen, es geht um SQL. Konzentriere Dich auf SQL und lass solche Sachen mit API-Code wie einem Gruppenwechsel außen vor. Wenn mir SQL genau das liefert, was ich haben will, schreibe ich einfachen SQL-Code statt unnötigem API-Code (solange nicht klare Performancegründe für die API sprechen) :-)

Wenn ich SQL lernen will, schreibe ich SQL-Code von Hand, in einem entsprechenden Client wie zum Beispiel der MySQL-Workbench. Die Darstellung ist mir dabei genauso gleichgültig wie die Performance - es sei denn, ich will etwas über die Performance unterschiedlicher Herangehensweisen an das gleiche Problem lernen.

Freundliche Grüße

Vinzenz