Vinzenz Mai: MySQL: keine Subselects, sondern GROUP BY und HAVING

Beitrag lesen

Hallo Markus,

Tabelle: geschaeft
+-------+--------+---------+
| ge_id | art_id | ge_name |
+-------+--------+---------+
|     1 |      4 | Hallo   |
|     2 |      2 | Test    |
+-------+--------+---------+

Tabelle: rating
+-------+--------+---------+
| ge_id | usr_id | ra_wert |
+-------+--------+---------+
|     1 |      3 |       4 |
|     1 |      7 |       2 |
|     2 |      5 |       1 |
+-------+--------+---------+

Bei meiner Datenbankabfrage versuche ich die ge_id und die art_id auszulesen, von z.B. Geschäften mit einer durchschnittlichen Bewertung von größer gleich als 3 Sternen.

Das ist doch gar kein Problem :-)

1. Schritt: Join der beiden Tabellen:

  
SELECT             -- Gib mir  
    g.ge_id,       -- die ID der Geschäfte,  
    g.art_id,      -- ihre Art,  
    g.ge_name,     -- ihren Namen und  
    r.usr_id,      -- den Benutzer, der eine Bewertung vorgenommen hat und  
    r.ra_wert      -- die Bewertung  
FROM               -- aus den Tabellen  
    geschaefte g   -- geschaefte  
                   -- Aliasnamen zum besseren Zugriff auf die Tabellen  
INNER JOIN         -- die mit der Tabelle  
    rating r       -- rating (der Bewertungen)  
ON                 -- über die Bedingung  
    g.ge_id = r.ge_id  -- gleicher ge_id verknüpft ist  

Ergebnis:

+-------+--------+---------+--------+---------+
 | ge_id | art_id | ge_name | usr_id | ra_wert |
 +-------+--------+---------+--------+---------+
 |     1 |      4 | Hallo   |      3 |       4 |
 |     1 |      4 | Hallo   |      7 |       2 |
 |     2 |      2 | Test    |      5 |       1 |
 +-------+--------+---------+--------+---------+

2. Schritt:
Gib mir die Geschäfte samt durchschnittlicher Bewertung.
Die Benutzer-Id interessiert beim Mittelwert nicht mehr.

  
SELECT  
    g.ge_id,  
    g.art_id,  
    g.ge_name,  
    AVG(r.ra_wert) AS rating  
                   -- Achtung, Aggregatsfunktion, daher GROUP BY erforderlich  
                   -- es muss nach allen anderen Spalten gruppiert werden  
FROM  
    geschaefte g   -- Aliasnamen zum besseren Zugriff auf die Tabellen  
INNER JOIN  
    rating r  
ON  
    g.ge_id = r.ge_id  
GROUP BY  
    g.ge_id,  
    g.art_id,  
    g.ge_name  

Ergebnis:

+-------+--------+---------+--------+
 | ge_id | art_id | ge_name | rating |
 +-------+--------+---------+--------+
 |     1 |      4 | Hallo   |      3 |
 |     2 |      2 | Test    |      1 |
 +-------+--------+---------+--------+

3. Schritt:
Du möchtest nur die haben, deren Mittelwert größer gleich 3 ist.
Dazu ist die HAVING-Klausel zuständig:

  
SELECT               -- Gib mir  
    g.ge_id,         -- die ID der Geschäfte  
    g.art_id,        -- ihre Art     (direkt von der ge_id abhängig)  
    g.ge_name,       -- ihren Namen  (direkt von der ge_id abhängig)  
    AVG(r.ra_wert) AS rating  
                     -- und den Durchschnitt ihrer Bewertungen  
                     -- Achtung, Aggregatsfunktion, daher GROUP BY erforderlich  
                     -- es muss nach allen anderen Spalten gruppiert werden  
FROM                 -- aus der Tabelle  
    geschaefte g     -- geschaefte, die über den Aliasnamen g angesprochen wird  
INNER JOIN           -- und verknüpft ist mit der Tabelle  
    rating r         -- rating, die über r angesprochen wird  
ON                   -- mit der Bedingung  
    g.ge_id = r.ge_id  -- dass die ge_id-Werte übereinstimmen  
GROUP BY             -- gruppiert, d.h. je Gruppe nur ein Wert, nach  
    g.ge_id,         -- Identifikation des Geschäfts  
    g.art_id,        -- Art des Geschäfts  
    g.ge_name        -- Name des Geschäfts  
HAVING               -- wobei die durchschnittliche Bewertung mindestens den  
    rating >= 3      -- Wert 3 haben muss  
                     -- Du kannst hier auch einen Aliasnamen verwenden im  
                     -- Gegensatz zur WHERE-Klausel, die dies nicht erlaubt.  

liefert das gewünschte Ergebnis:

+-------+--------+---------+--------+
 | ge_id | art_id | ge_name | rating |
 +-------+--------+---------+--------+
 |     1 |      4 | Hallo   |      3 |
 +-------+--------+---------+--------+

Überhaupt keine Subselects nötig, liefe sogar unter MySQL 3.23 :-)
Zur HAVING-Klausel gibt es einen Artikel in SELFHTML aktuell:
Datensätze gruppieren mit SQL.

Freundliche Grüße

Vinzenz