Torsten: Abfrage über 2 Tabellen, die nur Nichtübereinstimmungen liefert

Hallo,
folgendes Problem.
Ich habe zwei MySQL-Tabellen, mit folgender Struktur

Archiv:
ArchivID
LiteraturID
LagerortID (wird aus einer 3. Tabelle gespeist)

Literatur:
LiteraturID
LiteraturBeschreibung

Das Archiv, weist einer Literaturstelle somit einen Lagerort zu. Eine Literatur kann (auf Grund ihrer Größe) auch an mehreren Lagerorten auftauchen.

Gewünscht ist jetzt eine Abfrage, die mir alle Literaturstellen angibt, die noch nicht eingelagert sind. Ich habe bis jetzt leider keinen geeigneten Ansatz gefunden. DISTINCT und NOT in der Abfrage auf archiv.LiteraturID = Literatur.LiteraturID liefert natürlich alle Literaturstellen zurück. Mit JOIN konnte ich auch kein Ergebnis produzieren.

Als Workaround habe ich mir folgendes gebastelt:
eine zusätzliche Spalte "AnzahlLagerplätze" in der Tabelle Literatur anlegen, die mit jedem Literatureintrag hochgezählt bzw. mit jeder Auslagerung wieder runtergezählt wird. Ist der Wert gleich 0, dann ist die Literatur nicht eingelagert.

Jetzt bleibt aber das Interesse, wie eine direkte Lösung aussieht.

Vielen Dank für eure Hilfe.

Gruß
Torsten

  1. Archiv:
    ArchivID
    LiteraturID
    LagerortID (wird aus einer 3. Tabelle gespeist)

    Literatur:
    LiteraturID
    LiteraturBeschreibung
    Gewünscht ist jetzt eine Abfrage, die mir alle Literaturstellen angibt, die noch nicht eingelagert sind.

    Wenn ich die Struktur richtig verstehe, dann dürfte doch in diesem Fall für LiteraturID kein Eintrag in der Tabelle Archiv vorhanden sein, oder? Da könnte eine Unterabfrage helfen, sofern dein DBMS das unterstützt:

    SELECT  
      LiteraturID AS Id  
      LiteraturBeschreibung AS Beschreibung  
    FROM  
      Literatur AS t1  
    WHERE  
      t1.Id NOT IN (SELECT LiteraturID FROM Archiv)
    

    Syntaktische Fehler bitte ich nachzusehen und durch Berufenere zu korrigieren, aber prinzipiell müsste es so funktionieren.

    Siechfred

    --
    Ich bin strenggenommen auch nur interessierter Laie. (molily)
    1. Hallo Siechfred,

      SELECT

      LiteraturID AS Id
        LiteraturBeschreibung AS Beschreibung
      FROM
        Literatur AS t1
      WHERE
        t1.Id NOT IN (SELECT LiteraturID FROM Archiv)

      
      > Syntaktische Fehler bitte ich nachzusehen und durch Berufenere zu korrigieren, aber prinzipiell müsste es so funktionieren.  
        
      ~~~sql
      SELECT  
          LiteraturID AS Id,       -- Beachte: Spalten werden durch Komma getrennt  
          LiteraturBeschreibung AS Beschreibung  
      FROM Literatur l             -- MySQL unterstützt hier auch AS, aber nicht jedes  
                                   -- DBMS, daher lasse ich grundsätzlich AS weg :-)  
      WHERE  
          l.LiteraturID NOT IN (   -- Beachte: Auf Spalten-Aliasnamen kann in WHERE-  
                                   --          und ORDER-BY-Klausel nicht zugegriffen werden  
              SELECT  
                  a.LiteraturID  
              FROM archiv a  
      )
      

      Bei dieser speziellen Abfrage wären Tabellen-Aliasnamen nicht erforderlich gewesen. Und nochmals der Hinweis: Subselects werden ab MySQL 4.1 von MySQL unterstützt.
      Welche Lösung das DBMS weniger belastet, kann man mit EXPLAIN ermitteln.

      Berufene Grüße

      Vinzenz

      1. Syntaktische Fehler bitte ich nachzusehen und durch Berufenere zu korrigieren, aber prinzipiell müsste es so funktionieren.
        Beachte: Spalten werden durch Komma getrennt

        Hehe, ja, diese vergessenen Kommata, die sind mindestens genauso nervig wie vergessene Klammern :)

        Beachte: Auf Spalten-Aliasnamen kann in WHERE- und ORDER-BY-Klausel nicht zugegriffen werden

        Oh, danke, das war mir noch nicht bekannt.

        SELECT
          a.LiteraturID
        FROM archiv a

        Ist der Aliasname hier zwingend erforderlich (wegen der Gleichnamigkeit der Spalten in Tabelle Literatur und Archiv)?

        Bei dieser speziellen Abfrage wären Tabellen-Aliasnamen nicht erforderlich gewesen.

        Aber hallo, du schriebst selber, dass sie Tipparbeit ersparen :)

        Berufene Grüße

        Wusste ich's doch ;)

        Siechfred

        --
        Ich bin strenggenommen auch nur interessierter Laie. (molily)
        1. Hallo Siechfred,

          Beachte: Auf Spalten-Aliasnamen kann in WHERE- und ORDER-BY-Klausel nicht zugegriffen werden
          Oh, danke, das war mir noch nicht bekannt.

          dies ist insbesondere bei komplexeren Ausdrücken lästig, da Du diese Ausdrücke wiederholen musst. Es gibt auch DBMS, die sich in dieser Beziehung nicht an den Standard halten, MySQL 4.1.x meckert jedenfalls definitiv den Aliasnamen in Deiner WHERE-Klausel an.

          SELECT
            a.LiteraturID
          FROM archiv a

          Ist der Aliasname hier zwingend erforderlich (wegen der Gleichnamigkeit der Spalten in Tabelle Literatur und Archiv)?

          Nein. Äußere und innere Abfrage sind in diesem Fall unabhängig. Zumindest MySQL 4.1.x kommt bei diesem Statement komplett ohne Aliasnamen aus. Dennoch halte ich es für eine gute Idee, die Spaltenherkunft explizit anzugeben und dafür Aliasnamen zu verwenden. Ich mag Namen, die mich noch ein ganz klein wenig daran erinnern, welcher vollständige Name dahinter steckt.

          Freundliche Grüße

          Vinzenz

  2. Hallo

    Ich habe zwei MySQL-Tabellen, mit folgender Struktur

    welche MySQL-Version?
    Subselects, wie von Siechfred vorgeschlagen, unterstützt MySQL ab Version 4.1.

    Archiv:
    ArchivID
    LiteraturID
    LagerortID (wird aus einer 3. Tabelle gespeist)

    Literatur:
    LiteraturID
    LiteraturBeschreibung

    Das Archiv, weist einer Literaturstelle somit einen Lagerort zu. Eine Literatur kann (auf Grund ihrer Größe) auch an mehreren Lagerorten auftauchen.

    Gewünscht ist jetzt eine Abfrage, die mir alle Literaturstellen angibt, die noch nicht eingelagert sind. Ich habe bis jetzt leider keinen geeigneten Ansatz gefunden. DISTINCT und NOT in der Abfrage auf archiv.LiteraturID = Literatur.LiteraturID liefert natürlich alle Literaturstellen zurück. Mit JOIN konnte ich auch kein Ergebnis produzieren.

    Warum nicht? Jede mir bekannte MySQL-Version unterstützt den LEFT JOIN und den Vergleich mit NULL-Werten. Selbst mit MySQL 3.23 kannst Du Dein Problem lösen:

    Gib mir alle Literaturstellen, für die kein Eintrag im Archiv existiert:

    SELECT  
        l.LiteraturID     -- Alle Einträge aus Literatur, gern mit weiteren Details  
    FROM Literatur l      -- Aliasnamen ersparen Schreibarbeit :-)  
    [link:http://aktuell.de.selfhtml.org/artikel/datenbanken/joins/#leftright_join@title=LEFT JOIN] Archiv a  
    ON l.LiteraturID = a.LiteraturID  
    WHERE a.LiteraturID [link:http://dev.mysql.com/doc/refman/4.1/en/comparison-operators.html#id2943620@title=IS NULL]   -- für die kein korrespondierender Eintrag in der Tabelle Archiv existiert  
    
    

    Freundliche Grüße

    Vinzenz

    1. Hi,

      bist Du sicher, daß das funktioniert?

      ON l.LiteraturID = a.LiteraturID
      WHERE a.LiteraturID IS NULL

      a.LiteraturID soll also NULL sein. Außerdem soll l.LiteraturID = a.LiteraturID sein. Demzufolge muß auch l.LiteraturID NULL sein ...

      cu,
      Andreas

      --
      Warum nennt sich Andreas hier MudGuard?
      Schreinerei Waechter
      O o ostern ...
      Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
      1. Hallo

        bist Du sicher, daß das funktioniert?

        Ja.

        ON l.LiteraturID = a.LiteraturID
        WHERE a.LiteraturID IS NULL

        a.LiteraturID soll also NULL sein. Außerdem soll l.LiteraturID = a.LiteraturID sein. Demzufolge muß auch l.LiteraturID NULL sein ...

        Nein. Deine Schlussfolgerung ist falsch, weil Du den

        LEFT JOIN Archiv a

        unterschlagen hast. An der verlinkten Stelle kann man nachlesen, wie das funktioniert :-)

        Freundliche Grüße

        Vinzenz