Abfrage über 2 Tabellen, die nur Nichtübereinstimmungen liefert
Torsten
- datenbank
0 Siechfred0 Vinzenz Mai
0 Vinzenz Mai0 MudGuard
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
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
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
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
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 aIst 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
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
LiteraturBeschreibungDas 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
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
Hallo
bist Du sicher, daß das funktioniert?
Ja.
ON l.LiteraturID = a.LiteraturID
WHERE a.LiteraturID IS NULLa.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