Vinzenz Mai: Normalisierung und Abfrage (MySQL)

Beitrag lesen

Hallo,

Nun gibt es noch eine Feinheit, die mich zwar nicht sehr stört, aber die ich trotzdem gerne verstehen/beheben würde. Mein Query ist folgender:

das Statement wird nur von MySQL akzeptiert, da Du nicht nach allen Spalten gruppierst, auf die Du keine Aggregatsfunktion anwendest.

SELECT
    t.id,

-- im Falle der direkt von t.id abhängigen Spalten ist das kein echtes Problem
-- da die Werte eh' alle die gleichen sind.

t.datum,
    t.referenz,
    t.preis,

-- für die folgende Spalte bekommst Du selbstverständlich irgendeinen
-- beliebigen möglichen Wert. Bei mehrfachem Ausführen der gleichen Abfrage
-- kann dieser durchaus unterschiedlich sein

tb.id,
    GROUP_CONCAT( distinct(b.beschreibung) ) Besonderheiten,
FROM
    tour t
LEFT OUTER JOIN
    tour_besonderheit tb
ON
    t.id = tb.tour_id
LEFT OUTER JOIN
    besonderheit b
ON
    b.id = tb.besonderheit_id
WHERE t.firma_id = 4
GROUP BY
    t.id
ORDER BY
    t.id


>   
> Wenn ich nun alle Touren mit einer bestimmten Besonderheit anzeigen lassen möchte, erweitere ich die WHERE-Bedingung um ein  
  

> `AND b.id = 4`{:.language-sql}  
  
Nein. Wie Du gemerkt hast, liefert dies nicht das gewünschte Ergebnis. Außerdem gibt's noch ein paar andere Kleinigkeiten :-)  
  
Fangen wir an: Du suchst alle Touren mit einer bestimmten Besonderheit. Daraus folgt, dass Dich Touren \*ohne\* Besonderheit \*nicht\* interessieren. Du weißt, dass die Dich interessierenden Touren mindestens eine Entsprechung in der Tabelle tour\_besonderheit haben. Alle Datensätze der Tabelle tour\_besonderheit haben eine Entsprechung in der Tabelle besonderheiten (das solltest Du über referentielle Integrität sicherstellen :-)  
  
Statt OUTER JOINS kannst Du somit zwei INNER JOINS verwenden, was Die Sache nur schneller machen kann :-)  
  
Wenn es nun nur um eine Besonderheit geht und außerdem gilt, dass die gleiche Besonderheit in der gleichen Tour maximal einmal vorkommen kann (UNIQUE-Index über die Spaltenkombination (tb.tour\_id, tb\_besonderheit\_id), dann kannst Du das Problem mit einem Join erledigen. Allerdings wirst Du sehen, dass diese Lösung nicht flexibel ist und sich nicht leicht erweitern läßt.  
  
~~~sql
  
SELECT  
    t.id,  
    t.datum,  
    t.referenz,  
    t.preis,  
    GROUP_CONCAT( distinct(b.beschreibung) ) Besonderheiten,  
FROM  
    tour t  
-- wir joinen ein zweites Mal mit den tour_besonderheiten,  
-- um nur die Touren zu erhalten, die die Besonderheit mit der  
-- id 4 enthalten.  
INNER JOIN  
    -- wir müssen daher einen anderen Aliasnamen verwenden,  
    -- als im Join für die Detais  
    tour_besonderheit tb2  
ON  
    t.id = tb2.tour_id  
AND  
    -- und packen auch die Einschränkung in die Joinbedingung  
    tb2.besonderheit_id = 4  
  
-- und schauen uns von diesen Touren  
-- alle passenden Einträge an  
INNER JOIN  
    tour_besonderheit tb  
ON  
    t.id = tb.tour_id  
INNER JOIN  
    besonderheit b  
ON  
    b.id = tb.besonderheit_id  
WHERE  
    t.firma_id = 4  
GROUP BY  
    t.id  
    t.datum,  
    t.referenz,  
    t.preis  
-- in MySQL ist diese ORDER-BY-Klausel überflüssig, da MySQL ohnehin  
-- in der Reihenfolge der Spalten der GROUP-BY-Klausel sortiert  
ORDER BY  
    t.id  

Dein Problem, wenn zwei verschiedene Besonderheiten erfüllt sein sollen, könntest Du nun mit einem weiteren INNER JOIN auf die zweite gewünschte Besonderheit (und einem dritten Alias) erweitern.

Vom Grundsatz her ist es das gleiche Problem, das asmodin in diesem Archivthread hatte. Schau Dir meine dortigen Vorschläge an und wende sie auf Dein Problem an. Vergiss nicht das Messen mit einer signifikanten Zahl von Datensätzen :-)

Freundliche Grüße

Vinzenz