Oktober 22, 2021, 20:25:48

Neuigkeiten:

Ist euer Problem gelöst, dann bitte den Knopf "Thema gelöst" drücken!


Abfrage liefert keine Ergebnisse

Begonnen von Xoar, September 14, 2021, 11:45:00

⏪ vorheriges - nächstes ⏩

Xoar

Hallo zusammen,

ich verstehe gerade nicht warum meine Abfrage keine Ergebnisse liefert, könnt ihr mir da helfen?

T-SQL
select mitarbeiterid
from dbo.tblMitarbeiter
where  not exists
(
SELECT MitarbeiterID_F
FROM dbo.tblMitarbeiterLoeschzug
WHERE LoeschzugID_F In (select value from string_split('1,3',','))
)

Die Unterabfrage isoliert, liefert folgende Werte
MitarbeiterID, LoeschzugID
14                 1
79                 1
79                 3

Jetzt sollen alle MitarbeiterID aus tblMitarbeiter angezeigt werden, die NICHT in der Unterabfrage vorkommen.

Ich habe leider keine Ahnung was falsch ist.....

Grüße

PhilS

Zitat von: Xoar am September 14, 2021, 11:45:00Jetzt sollen alle MitarbeiterID aus tblMitarbeiter angezeigt werden, die NICHT in der Unterabfrage vorkommen.
Ein NOT EXISTS Kriterium ist dann erfüllt, wenn die Unterabfrage gar keine Ergebnisse liefert.
In der Regel muss die Unterabfrage zur Hauptabfrage korrelieren, damit das sinnvoll ist.

select mitarbeiterid
from dbo.tblMitarbeiter m
where  not exists
(
SELECT MitarbeiterID_F
FROM dbo.tblMitarbeiterLoeschzug ml
WHERE LoeschzugID_F In (select value from string_split('1,3',','))
AND   ml.MitarbeiterID_F = m.mitarbeiterid
)
Access DevTools - Find and Replace
Komfortables Suchen und Ersetzen in den Entwurfseigenschaften von Access-Objekten. In Abfragen, Formularen, Berichten und VBA-Code - Überall und rasend schnell!

Xoar

September 14, 2021, 12:26:48 #2 Letzte Bearbeitung: September 14, 2021, 12:32:38 von Xoar
Super danke @PhilS, es klappt.

Leider hab ich es noch nicht ganz verstanden, das ist schlecht....
Also die Unterabfrage selbst liefert Datensätze, wenn ich diese aber als Filterung für die Hauptabfrage nutzen will, muss ich die Schlüsselfelder verknüpfen.

Irgendwie ergibt das für mich gerade keinen Sinn warum man die verknüpfen muss, ist was NOT EXISTS spezifisches, oder?

Mein Verständnis wäre eigentlich so:
WÄHLE alle MitarbeiterIDs
AUS tblMitarbeiter
  DIE NICHT EXISTIEREN in
    ( -- Abfrage aller IDs
    WÄHLE MitarbeiterID_F
    AUS MitarbeiterLoeschzug
    WO LoeschzugID_F in (Liste)
    )

Jetzt muss man die IDs aus der Unterabfrage noch verknüpfen, damit NOT EXISTS weiß, welche IDs gefiltert werden müssen, weil sonst immer NULL bei rauskommt?!


Gibt es einen sinnvolleren Weg das umzusetzten, oder frei dem Motto: Viele Wege führen nach Rom...

PhilS

Zitat von: Xoar am September 14, 2021, 12:26:48Irgendwie ergibt das für mich gerade keinen Sinn warum man die verknüpfen muss, ist was NOT EXISTS spezifisches, oder?
Ja, schon.
Dein "Code"-Beispiel sollte man vielleicht besser so formulieren:
WÄHLE alle MitarbeiterIDs
AUS tblMitarbeiter
  WO DIE FOLGENDE ABFRAGE KEINE ERGEBNISSE LIEFERT
    ( -- Abfrage aller IDs
    WÄHLE MitarbeiterID_F
    AUS MitarbeiterLoeschzug
    WO LoeschzugID_F in (Liste)
    )

Der wesentliche Punkt bei (NOT) EXISTS ist, dass es nicht um konkrete Werte aus der Unterabfrage geht, sondern nur darum ob diese Datensätze liefert oder nicht.
Verdeutlichen kann man das, wenn man die Abfrage so schreibt:
select mitarbeiterid
from dbo.tblMitarbeiter m
where  not exists
(
SELECT 'X'
FROM dbo.tblMitarbeiterLoeschzug ml
WHERE LoeschzugID_F In (select value from string_split('1,3',','))
AND   ml.MitarbeiterID_F = m.mitarbeiterid
)
Das funktioniert genauso wie vorher. Das 'X' macht deutlich, dass die Werte aus der Unterabfrage komplett irrelevant sind.

Alternativ kannst du deine Abfrage auch mit NOT IN formulieren. Dann werden tatsächlich die Werte der Ergebnismenge geprüft.
select mitarbeiterid
from dbo.tblMitarbeiter
where  mitarbeiterid NOT IN
(
SELECT MitarbeiterID_F
FROM dbo.tblMitarbeiterLoeschzug
WHERE LoeschzugID_F In (select value from string_split('1,3',','))
)

Eine weitere Möglichkeit das gewünschte Ergebnis zu bekommen, wäre ein OUTER JOIN auf das Sub-Select kombiniert mit einem IS NULL Kriterium auf die Schlüsselspalte der äußerem Abfrage.
Ungeprüft:
SELECT mitarbeiterid
FROM dbo.tblMitarbeiter m
LEFT JOIN (
SELECT MitarbeiterID_F
FROM dbo.tblMitarbeiterLoeschzug
WHERE LoeschzugID_F In (select value from string_split('1,3',','))
) as ml
ON m.mitarbeiterid  = ml.MitarbeiterID_F
WHERE ml.MitarbeiterID_F IS NULL
Access DevTools - Find and Replace
Komfortables Suchen und Ersetzen in den Entwurfseigenschaften von Access-Objekten. In Abfragen, Formularen, Berichten und VBA-Code - Überall und rasend schnell!

ebs17

September 14, 2021, 14:55:21 #4 Letzte Bearbeitung: September 14, 2021, 15:01:10 von ebs17
Mit anderen Worten:

WHERE prüft auf True. Was diese Prüfung erfüllt, kann dann im SELECT angezeigt werden. Alle vorhandenen Ausdrücke in der Klausel werden logisch verknüpft.

EXISTS als möglicher Teil davon prüft ebenfalls auf True, also ist etwas in der Unterabfrage oder nicht.
In Deiner ursprünglichen Abfrage gibt es Datensätze oder nicht, damit über alles True oder False. Das hattest Du bemerkt. Für eine Spezifik braucht man die Korrelation zwischen Schlüssel Unterabfrage und Schlüssel Hauptabfrage.
Durch die Prüfung nur auf True  ist diese Gestaltung auch recht schnell. Zumindest in Jet geht aber bei Korrelation über mehr als ein Feld die Indexnutzung verloren mit folgendem Performanceverlust. Also Einzelfall prüfen.
Vorteil des Ganzen: Die Hauptabfrage bleibt hier uneingeschränkt editierbar.
Weiter: Bei komplexeren Anforderungen kann man EXISTS-Gestaltungen und anderes bausteinhaft zusammensetzen bei Beibehaltung einer einfachen übersichtlichen Logik.

Bevorzugt würde ich die OUTER JOIN-Variante (letzte Variante von Philipp) verwenden. Die Unterabfrage, die im FROM-Teil liegt, wird nur einmal ausgeführt, während Korrelation ja heißt, die Unterabfrage wird zu jedem Wert in der Hauptabfrage ausgeführt, also mehr- bis vielfach. Das kann fallabhängig intern aufwändig sein mit Folgen für Performance.
In der OUTER JOIN-Variante wird man aber schnell die Editierbarkeit der Abfrage verlieren.

Das ebenfalls gezeigte NOT IN-Konstrukt ist das schlechteste, wird aber gerne benutzt.
Das NOT wird eine Indexnutzung verhindern. Außerdem werden NULL-Inhalte des verglichenen Feldes der Unterabfrage nicht wie erwartet ausgewertet. Bei einem Schlüssel wie hier im Code dürften jetzt aber keine NULL-Inhalte auftreten, aber im Hinterkopf solle man ein Achtung haben.
Mit freundlichem Glück Auf!

Eberhard

Xoar

@PhilS @ebs17

Ich muss mich für eure Antworten bedanken, jetzt fängt alles an Sinn zu ergeben.

Wirklich super Erklärungen. Danke