Thomas: Hilfe bei Select über 2 Tabellen

Hallo,

ich bräuchte Hilfe bei einer Abfrage.
Und zwar sollen bei dieser Abfrage nur Einträge aus 'ticket' gezeigt werden, die keinen verknüpften Eintrag in 'antwort' haben.
Hier meine Query:
select A.* from ticket A JOIN antwort B ON B.ticket != A.id WHERE A.status = 'open' order by A.timestamp asc

Leider erhalte ich die Einträge sogar doppelt, da es noch einen Eintrag in 'ticket' gibt (welcher nicht angezeigt wird) und 2 Einträge in der Tabelle 'antwort' hat.

Könnte mir da jemand behilflich sein?

Vielen Dank
Thomas

  1. Nachtrag: Es handelt sich um MySQL.

  2. Tach auch.

    ich bräuchte Hilfe bei einer Abfrage.
    Und zwar sollen bei dieser Abfrage nur Einträge aus 'ticket' gezeigt werden, die keinen verknüpften Eintrag in 'antwort' haben.
    Hier meine Query:
    select A.* from ticket A JOIN antwort B ON B.ticket != A.id WHERE A.status = 'open' order by A.timestamp asc

    Leider erhalte ich die Einträge sogar doppelt, da es noch einen Eintrag in 'ticket' gibt (welcher nicht angezeigt wird) und 2 Einträge in der Tabelle 'antwort' hat.

    Dieser einfache JOIN wird dich nicht weiterbringen. Versuche etwas in die Richtung (ungetestet):

      
    SELECT A.*  
      FROM ticket A  
      WHERE NOT EXISTS (SELECT B.ticket FROM antwort B WHERE B.ticket = A.id)  
    
    

    Mit deinem JOIN würde es so funktionieren:

      
    SELECT A.*  
      FROM ticket A  
        LEFT OUTER JOIN antwort B ON B.ticket = A.id  
      WHERE B.ticket IS NULL  
    
    

    Bis die Tage,
    Matti

    1. Hi!

      Da hätte ich gleich mal eine Folgefrage. Gegenüber dieser EXISTS-Variante

      SELECT A.*

      FROM ticket A
        WHERE NOT EXISTS (SELECT B.ticket FROM antwort B WHERE B.ticket = A.id)

        
      gibt es ja auch noch die IN-Variante  
        
      `SELECT * FROM ticket WHERE id NOT IN(SELECT ticket FROM antwort)`{:.language-sql}  
        
      Abgesehen davon, dass die IN-Variante kürzer zu notieren ist, welche ist aus DBMS-Sicht die bessere? (Lässt sich das überhaupt so generell klären?)  
        
      Meine Gedanken dazu sind: Bei der IN-Variante muss das DBMS einmalig die Ergebnismenge der Subquery ermitteln. Dabei kann es je nach Art der Daten sicherlich auch vorkommen, dass einige Werte mehrfach vorkommen. (Zusatzfrage: Lohnt sich da ein DISTINCT, um die Menge einzudampfen oder ist das nur unnötiger Aufwand?) Die A-Datensätze müssen nun gegen diese temporäre Liste geprüft werden.  
        
      Die EXISTS-Variante würde für jeden A-Datensatz die Bedingung B.ticket = A.id testen, wofür sie einen Index verwenden kann, wenn einer auf B.ticket liegt. Das dürfte die weniger Speicher verbrauchende Variante sein, weil sie keine temporäre Liste erzeugen muss. Viele Plattenzugriffe dürften nicht anfallen, weil bestimmt irgendwelche Caching-Mechanismen greifen.  
        
        
      Übrigens, da bei Verwendung von [EXISTS](http://dev.mysql.com/doc/refman/5.1/en/exists-and-not-exists-subqueries.html) die SELECT-Klausel der Subquery nicht ausgewertet wird, kann da auch der Kürze wegen einfach ein \* stehen. Macht vermutlich jedes DBMS so.  
        
        
      Lo!
      
  3. Hallo,

    ich bräuchte Hilfe bei einer Abfrage.
    Und zwar sollen bei dieser Abfrage nur Einträge aus 'ticket' gezeigt werden, die keinen verknüpften Eintrag in 'antwort' haben.

    ja dann mach' das doch:

    Gib mir
        alle Spalten
    aus
        Tabelle A
    wobei mich nur die Datensätze interessieren,
        deren ID nicht in der Liste
            der ticket-Einträge
        aus
            Tabelle B
        vorkommen

    Subselects unterstützt MySQL schon seit Version 4.1

    Alternativ könntest Du einen LEFT JOIN mit Prüfung auf IS NULL der ticket-Spalte aus Tabelle B nehmen.

    Freundliche Grüße

    Vinzenz

  4. Hi!

    Und zwar sollen bei dieser Abfrage nur Einträge aus 'ticket' gezeigt werden, die keinen verknüpften Eintrag in 'antwort' haben.

    Dann mach das doch auch so, wie du es sagst: SELECT * FROM ticket WHERE id NOT IN(SELECT ticket FROM antwort)

    Hier meine Query:
    select A.* from ticket A JOIN antwort B ON B.ticket != A.id WHERE A.status = 'open' order by A.timestamp asc
    Leider erhalte ich die Einträge sogar doppelt, da es noch einen Eintrag in 'ticket' gibt (welcher nicht angezeigt wird) und 2 Einträge in der Tabelle 'antwort' hat.

    Du erzeugst einen Inner Join. Die Bedingung B.ticket != A.id passt auf alle anderen Datensätze, nur nicht auf die korrespondierenden. Soweit so richtig. Der Inner Join jedoch bewirkt, dass vom Rest ein kartesisches Produkt angefertigt wird. Das heißt, alle übrig gebliebenen B-Datensätze werden mit den übrig gebliebenen A-Datensätzen multipliziert. Wenn A1 mit B1 verknüpft ist, so landet der Datensatz nicht im Ergebnis. Allerdings landet A1 trotzdem in der Ergebnismenge, wenn er nicht mit B2 verknüpft ist, denn dann erfüllt sich die Join-Bedingung. Wenn A2 weder mit B1 noch mit B2 verknüpft ist, erfüllt sich die Bedingung gleich zweimal. Und so weiter.

    Mit einem Join müsstest du einen Left Join nehmen, der auf Gleichheit prüft:

    a LEFT JOIN b ON a.id = b.ticket

    Damit bekommst du alle A mit ihrem zugehörigen B und - dank des Left Joins - auch alle A zu denen kein B existiert. Da du nur letztere haben möchtest, musst du nun nur die Einträge der JOIN-Zwischenergebnismenge wählen, die keine B-Daten haben.

    WHERE b.irgendeinfeld IS NULL

    Das nur zur Erklärung. Du solltest lieber die obige Subquery-Lösung nehmen, denn die dürfte einfacher verständlich als die Join-Lösung sein.

    Lo!

  5. Hallo nochmal,

    hat geklappt, vielen lieben Dank an euch alle!!!