asmodin: Mehrere Bedingungen über mehrere Datensätze verteilt Gruppieren

Hallo,

mir wurde bereits heute schon mal geholfen, bei einem anderen Problem mit einer Datenbank.

Jetzt habe ich noch eine Frage, ich hoffe das ist jetzt kein Doppelposting.

Ausgangslage: MySQL
Ich habe 3 Tabellen die ich per LEFT JOIN verbinde (also 2 Tabellen über eine Beziehungstabelle), soweit alles in Ordnung.

Ohne weitere Bedingung sieht das etwa so aus:

titel | filter
------+-------
abc1  | 10
abc1  | 20
abc2  | 10
abc2  | 20
abc2  | 30
abc3  | 10
abc3  | 40
abc4  | 20
abc4  | 50

Jetzt möchte ich alle Titel deren Filter ZUMINDEST (10 UND 20) ist. Sprich, das Ergebnis sollte so aussehen:

titel
-----
abc1
abc2

Probiert habe ich das so:
GROUP BY titel HAVING filter = 10 OR filter = 20

Gruppiert ist es richtig, allerdings sieht das so aus:

titel
-----
abc1
abc2
abc3
abc4

Nächster Versuch:
GROUP BY titel HAVING filter = 10 AND filter = 20

Da bekomme ich keine Ergebnisse mehr, was ich auch nachvollziehen kann.

Ein Titel kann übrigens einen oder mehrere Filter haben. Leider bin ich aus der MySQL-Doku nicht schlau geworden, der Abschnitt zu HAVING ist sehr kurz. Zudem bin ich mir nicht sicher, ob das überhaupt das Richtige für mich ist.

Gibts statt dem OR oder AND einen "ZUMINDEST" Operator oder ähnliches, bzw. wie kann ich mein Problem sonst lösen?

  1. Hallo,

    mir wurde bereits heute schon mal geholfen, bei einem anderen Problem mit einer Datenbank.

    Jetzt habe ich noch eine Frage, ich hoffe das ist jetzt kein Doppelposting.

    grundsätzlich hätte ich Dir dazu geraten, diese Frage hier in Deinem alten Thread unterzubringen - und zwar als Antwort auf Dein Ausgangsposting. Du sparst Dir die Hinweise auf die darunterliegenden Daten.

    titel | filter
    ------+-------
    abc1  | 10
    abc1  | 20
    abc2  | 10
    abc2  | 20
    abc2  | 30
    abc3  | 10
    abc3  | 40
    abc4  | 20
    abc4  | 50

    Jetzt möchte ich alle Titel deren Filter ZUMINDEST (10 UND 20) ist. Sprich, das Ergebnis sollte so aussehen:

    titel

    abc1
    abc2

    Mir gefällt Deine Art der Fragenstellung.

    Gibts statt dem OR oder AND einen "ZUMINDEST" Operator oder ähnliches, bzw. wie kann ich mein Problem sonst lösen?

    Drei Möglichkeiten kommen mir spontan in den Sinn:

    1. Nutze einen Selfjoin:

      
    SELECT                   -- Gib mir  
        t1.titel             -- die Titel  
    FROM                     -- aus meiner  
        test t1              -- Tabelle, die hier über t1 angesprochen wird  
    INNER JOIN               -- die mit  
        test t2              -- sich selbst verknüpft ist  
    ON                       -- über  
        t1.titel = t2.titel  -- gleiche Titel  
    WHERE                    -- wobei  
        t1.filter = 10       -- der Filter in der "ersten" Tabelle den Wert 10  
    AND                      -- und  
        t2.filter = 20;      -- in der "zweiten" Tabelle den Wert 20 hat.
    

    Wie ich in meinem Artikel anmerke, skaliert der Selfjoin nicht gut, insbesondere, wenn ich an

    Ein Titel kann übrigens einen oder mehrere Filter haben.

    denke. Die Erweiterung auf drei Filter wäre vom Prinzip her einfach.

    2. Nutze Subselects:

      
    SELECT                     -- Gib mir  
        t1.titel               -- die Titel,  
    FROM  
        test t1  
    WHERE                      -- die den  
        t1.filter = 10         -- Filterwert 10 haben,  
    AND                        -- und  
        t1.titel IN (          -- in der  
            SELECT             -- Liste  
                t2.titel       -- der Titel enthalten sind,  
            FROM  
                test t2  
            WHERE              -- die  
                t2.filter = 20 -- den Filterwert 20 haben  
        );
    

    Die Erweiterung auf weitere Filter erfolgt analog.

    3. Nutze COUNT(*) in einem Subselect:

      
    SELECT                         -- Gib mir  
        v.titel                    -- die Titel,  
    FROM (                         -- die in der  
        SELECT DISTINCT            -- Liste der eindeutigen Einträge  
            t1.titel,              -- der Titel  
            t1.filter              -- und Filterwerte auftreten,  
        FROM  
            test t1  
        WHERE                      -- die die  
            t1.filter IN (10, 20)  -- Filterwerte 10 oder 20 haben  
        ) v                        -- (Das Subselect benötigt zwingend einen Namen)  
    GROUP BY                       -- wobei wir  
        v.titel                    -- nach den Titeln gruppieren  
    HAVING                         -- und nur die haben möchten  
        COUNT(*) = 2               -- die genau zweimal vorkommen.
    

    Diese dritte Variante lässt sich offensichtlich am einfachsten erweitern.

    Deine Aufgabe wäre es, die Performance der verschiedenen Versionen mit Deinen Daten zu prüfen. Bestimmt gibt es noch weitere Möglichkeiten, zu dem von Dir gewünschten Resultat zu gelangen.

    Freundliche Grüße

    Vinzenz

    1. grundsätzlich hätte ich Dir dazu geraten, diese Frage hier in Deinem alten Thread unterzubringen - und zwar als Antwort auf Dein Ausgangsposting. Du sparst Dir die Hinweise auf die darunterliegenden Daten.

      Die Daten sind ja andere, das vorherige war ein MSSQL-Problem :) das hier ist eine andere Baustelle, darum war ich mir nicht sicher.

      Mir gefällt Deine Art der Fragenstellung.

      Danke. Das ist aber purer Eigennutz. Mit ordentlicher Fragestellung und Problembeschreibung kommt man schneller zum Ziel!

      1. Nutze COUNT(*) in einem Subselect:
        Diese dritte Variante lässt sich offensichtlich am einfachsten erweitern.

      Das sieht mir für meine Zwecke am vernünftigsten aus. Ich denke ich werde mich mit dieser Methode beschäftigen. Ich melde mich dann wieder. Danke vorerst für deine Hilfe.

        1. Nutze COUNT(*) in einem Subselect:
          Diese dritte Variante lässt sich offensichtlich am einfachsten erweitern.
          Das sieht mir für meine Zwecke am vernünftigsten aus. Ich denke ich werde mich mit dieser Methode beschäftigen. Ich melde mich dann wieder. Danke vorerst für deine Hilfe.

        Hallo nochmal,

        die Lösung #3 funktioniert wunderbar.

        Vielen Dank