SQL: SELECT WHERE über ein bzw. zwei Ebenen nach oben

tomm1984

Lt. Junior Grade
Registriert
Juni 2016
Beiträge
329
Hallo werte Community.

Ich habe folgende, grundlegende Access-Datenbank-Idee (kein Hit, Standard).
2020-09-23 SQL SELECT WHERE_01.PNG


Nun möchte ich die Datenbank um Zeitabhängigkeiten erweitern, also zumindest das Auswahlfeld bei einem Angebot.

Dazu folgender, realer Hintergrund:
  • Kontakte (Mitarbeiter) wechseln schon mal die Firma und dazu möchte ich - warum auch immer - den Kontakt sozusagen mitnehmen, anstatt den Kontakt unter der neuen Firma / dem neuen Kunden ein weiteres Mal anzulegen
  • So bin ich auf die Gültigkeit gekommen; jener Kontakt ist bei Kunde / Firma XY vom 01.01.2020 bis 31.12.9999 hinterlegt.
  • Scheidet der Mitarbeiter aus, so wird 31.12.9999 durch den letzten Arbeitstag ersetzt.
  • Angenommen, derselbe Kontakt fängt am folgenden Tag woanders an, so ergibt das das neuen "gültig-von"-Datum bis 31.12.9999 usw.
  • Therotisch sind sogar überschneidende Zeiträume möglich; das ist auch nicht weiter wild, könnte - zumindest theoretisch - auch real der Fall sein (arbeitet in zwei Firmen jeweils Teilzeit) usw. ... also hier geht es nicht darum, dass die Zeiträume richtig bzw. gar überschneideungsfrei gesetzt werden sollen ... das wird an anderer Stelle behandelt. Es geht ausdrücklich nun um den richtigen Select.
  • Es geht ebenfalls nicht über die eigentliche Verbindung der Daten: Schaue ich mir ein Angebot an, bei dem jener Kontakt mal gültig war, aber HEUTE nicht mehr gültig ist, so soll dieser Kontakt da natürlich nach wie vor drinstehen (unter all den Kontakten dieser Firma würde dieser Kontakt dann bspw. als inaktiv angezeigt werden).
  • ABER: Wenn ich nun bei demselben Kunden (also - aus heutiger Sicht - dem ehemaligen Arbeitgeber) ein Angebot anlege, dann sollte ich diesen Kontakt nicht mehr selektieren dürfen / können.

Dazu ist meiner Meinung nach die folgende Zwischentabelle nötig, die zum einen eine m:n-Beziehung herstellt, zum anderen die Gültigkeit von / bis ausgibt. Eine Abfrage ermittelt bereits, ob dieser Kontakt HEUTE gültig ist.

2020-09-23 SQL SELECT WHERE_02.PNG


Nun scheitere ich am Select, da dieser, meiner Meinung nach, ein Bisschen ums Eck geht. So, wie der Select im Moment aufgebaut ist, liefert er mir ALLE Kontakte (unabhängig der Gültigkeit und unabhängig der Gültigkeit bei diesem Kunden).

Code:
SELECT [t_Kontakt].[tf_KontaktID], [t_Kontakt].[tf_Name] FROM [t_Kontakt] ORDER BY [tf_Name];


Der Select müsste sinngemäßg wie folgt ergänzt werden:
Code:
 ... WHERE "Kontakt ist heute ein gültiger Kontakt des Kunden, bei dem ich gerade das Angebot anlege"


Namenskonvention (über die sich sicher diskutieren ließe, aber so ist sie halt im Moment):
t_ = table
qt_ = query on table

tf_ = table field
qfc_ = query field calculated


Vielen Dank vorab für Input. :)

NACHTRAG:
Vielleicht ist auch das die bessere Darstellung...
2020-09-23 SQL SELECT WHERE_03.PNG
 
Zuletzt bearbeitet:
Code:
select angebot.angebotid kunde.kundeid kontakt.kontaktid
from angebot as angebot
inner join kontakt as kontakt on kontakt.kontaktid = angebot.kontaktid
inner join zwischentabelle as zwischentabelle on zwischentabelle.kontaktid = kontakt.kontaktid
inner join Kunde as kunde on kunde.kundeid = zwischentabelle.kundeid
Where zwischentabelle.gültigvon < datum
And zwischentabelle.gültigbis > datum
And angebot.angebotid = angebot

So in etwa müsste deine Abfrage unter Berücksichtigung deiner Zwischentabelle aussehen. Du brauchst hierfür einfach ein paar joins :)
 
@blablub1212 : Wow, beeindruckend. Zunächst einmal ein großes Danke. Ja, ja ... diese niedlichen JOINS 😁🙈

Die Where-Bedingung habe ich mal umgestellt, da die Info, ob der Kontakt heute gültig ist, bereits in einer Abfrage enthalten ist. Ferner greife ich ausschließlich auf Abfragen zu (was hoffentlich keinen Unterschied macht, nur eben die zuvor genannte Bedingung beantwortet; alle Abfragen sind 1:1-Wiedergaben der dazugehörigen Tabellen, ggf. um weitere Felder ergänzt, so z.B. die "istheutegültig?"-Logik). Dennoch bekomme ich einen Syntax-Fehler.

Zur besseren Leserlichkeit habe ich die Tabellen mal um "tbl" als Präfix erweitert und hoffe, dass ich Deinen Code somit richtig übersetzt habe, bzw. im zweiten Code-Block alles mit Abfragen (Präfix = qry) ersetzt habe.

Code:
select tblAngebot.angebotid, tblKunde.kundeid, tblKontakt.kontaktid from tblAngebot as tblAngebot
inner join tblKontakt as tblKontakt on tblKontakt.kontaktid = tblAngebot.kontaktid
inner join tblZwischentabelle as tblZwischentabelle on tblZwischentabelle.kontaktid = tblKontakt.kontaktid
inner join tblKunde as tblkunde on tblKunde.kundeid = tblZwischentabelle.kundeid
Where tblZwischentabelle.gültigheute* = true;

* = kommt eigentlich nicht aus der Tabelle

deshalb hier mit Abfragen (qry) anstatt Tabellen (tbl):

select qryAngebot.angebotid, qryKunde.kundeid, qryKontakt.kontaktid from qryAngebot as qryAngebot
inner join qryKontakt as qryKontakt on qryKontakt.kontaktid = qryAngebot.kontaktid
inner join qryZwischentabelle as qryZwischentabelle on qryZwischentabelle.kontaktid = qryKontakt.kontaktid
inner join qryKunde as qrykunde on qryKunde.kundeid = qryZwischentabelle.kundeid
Where qryZwischentabelle.gültigheute = true;
 
Die Abfrage ergibt mMn keinen Sinn.
Du benötigst doch die zur Auswahl verfügbaren Kontakte, oder nicht? Die JOINs da oben suchen den bereits zum Angebot verknüpften Kontakt heraus und filtern dann nochmal auf das Datum, was irgendwie unsinnig ist - der Kontakt ist ja bereits dem Angebot zugeordnet. In deiner Oberfläche wäre dann die eigentlich vorhandene Verknüpfung zwischen Kontakt und Angebot ausgeblendet, wenn er heute nicht mehr dem Kunden zugeordnet ist.

Benötigst du nicht eigentlich eine Abfrage, die dir die "verfügbaren" Kontakte für eine KundenID gibt? Da ist das Angebot völlig außen vor, das willst du ja erst noch anlegen.

Code:
SELECT kontakt...
FROM dbo.Kunde kunde
JOIN dbo.Zwischentabelle zwischen ON kunde.kundeid = zwischen.kundeid AND zwischen.gueltigheute = 1
JOIN dbo.Kontakt kontakt ON kontakt.kontaktid = zwischen.kontaktid
WHERE kunde.kundeid = {inputKundeId}
 
hmm, ich verstehe ... zumindest ansatzweise.

Der Prozess wäre, frei gesprochen, wie folgt:
  1. Ich habe Kunde A geöffnet (im Formular)
  2. dazu lege ich ein neues Angebot an (die Verknüpfung zwischen AngebotID und KundeID ist damit hergestellt)
  3. Im Auswahlfeld "Ansprechpartner" (dieses Angebots) möchte ich nun alle Kontake von Kunde A, die heute gültig sind

Aus meiner Sicht braucht es deshalb den InputKundeID nicht, da dieser ja bekannt ist (kurz um: ich wundere mich lediglich über Zeile 5 Deines Codes, @Enurian )
 
Wozu willst du diese Abhängigkeit reinbringen? Ja, du kannst dir die KundenID natürlich auch aus einem Angebot holen. Hängt letztendlich von deiner Applikation ab, du solltest das ja jetzt wie benötigt zusammensetzen können.
 
Enurian schrieb:
... du solltest das ja jetzt wie benötigt zusammensetzen können.

Etwas kryptisch, also für mich. Ich bin mit dem ganzen SQL-Thema und die vereinfachte Darstellung des Codes (einschließlich meiner mäßigen Namenskonvention, wie ich jetzt merke) noch nicht so vertraut. Ich probiere es mal :-D
Ergänzung ()

So habe ich es jetzt umgesetzt bzw. nach bestem Wissen und Gewissen "übersetzt" ... scheinbar mit Fehlern ("Syntax-Fehler in der FROM-Klausel")

Code:
SELECT [qryKontakt].[KontaktID], [qryKontact].[KontaktName], [qryKontact].[KontaktVorname]
FROM [qryKunde].[KundeID]
JOIN [qryZwischentabelle].[KundeID] ON [qryKunde].[KundeID] = [qryKontakt].[KundeID] AND [qryKontakt].[Kontaktvalidtoday] = TRUE
JOIN [qryZwischentabelle].[KontaktID] ON [qryKontakt].[KontaktID] = [qryZwischentabelle].[KontactID]
WHERE [qryKunde].[KundeID] = [qryZwischentabelle].[KundeID];

(Da es keinen Widerspruch dazu gab, ob ich das Statement auf tbl oder qry aufbaue, habe ich das alles basierend auf den Abfragen gemacht)
 
Zuletzt bearbeitet:
Hallo nochmal,

ich habe mir ein paar youtubes zu SQL gesehen und nun (endlich mal) den Aufbau im groben verstanden und kann jetzt eure Hinweise nachvollziehen. Mittlerweile habe ich mir auch eine Abfrage erstellt, die mir - auf Basis der Zwischentablle und dem Datum HEUTE - alle verfügbaren Kontakte liefert (gejoint mit tblKunde, so dass ich auch die Kunden-Informationen habe).

Der Select, den ich mir wünsche, soll in eine Auswahl-Box an der Tabelle "Angebot". Die Auswahl-Box funkioniert schon mal inoweit, als dass ich nur die heute-gültigen Kontakte angezeigt bekomme, aber eben noch nicht gefiltert auf den Kunden, bei ich gerade das Angebot anlegen. Ich befürchte nun, dass hier eine Art Zirkelbezug entsteht oder ein Henne-Ei-Problem.

Und zwar:
  1. In dem Augenblick, wie in einem Kunden ein Angebot anlege, erhält die tblAngebot eine ID und im Bezugsfeld KundeID erscheint die KundeID.
  2. In der selben Zeile will ich nun in der Auswahl-Box den zuvor erwähnten SELECT verwenden, aber nur auf jene Einträge filtern, dessen KundeID der KundeID meiner aktuellen Zeile entspricht. ...und das ist mir bisher nicht gelungen, die Information als WHERE an den Select zu übergeben (evtl. deshalb Dein Vorschlag zur Input-Variablen, @Enurian ?).
Vielleicht geht es auch gar nicht, weil in diesem Augenblick der Datensatz nur scheinbar angelegt, aber noch nicht wirklich gespeichert ist (sprich: ich glaube völlig andere Abfrage wird mir auch diese Angebots-ID nicht zurückgeben, solange ich noch in der Zeile bin).

Darf ich nochmal die Runde um Ideen bitten?
 
Was steht denn zu diesem Zeitpunkt schon alles in der Datenbank?
Wenn der Insert des neuen Angebots nicht schon sofort am Anfang geschieht (was eher normal wäre), steht in der Datenbank noch nichts von diesem Angebot. Alle Werte die du dann auf deiner Maske sehen kannst, sind lediglich lokal in deinen Tables oder Querys vorhanden.
In die Datenbank kommen sie dann erst über den eigentlichen Insert. (Also beim Speichern.)

Analog dazu, sollte der Insert des neuen Angebots doch schon zu Beginn der Bearbeitung statt finden (was man machen kann, manchmal ergibt sowas sinn, generell ist das aber eher unüblich), weitere Bearbeitungen aber erst mit einem weiteren Post in die Datenbank gelangen (also beim ersten manuellen Speichern), steht in der Datenbank u.U. noch nichts von der Verknüpfung von Angebot und Kunde.

Wenn die Informationen zum Filtern deiner Kontakte noch nicht in der Datenbank stehen, musst du sie als Parameter in dein entsprechendes SQL einfließen lassen.
Die Werte dafür musst du aus den zuständigen Feldern deiner Tables oder Querys der Maske beziehen.
 
@Enurian + @AW4 :
Ich glaube mittlerweile, dass der gesamte Post falsch ist. Die Logik, die Abhängigkeiten über JOINS und die WHERE-Bedingungen abzubilden, habe ich jetzt verstanden und ist auch gar nicht so wild (danke für euren Input ... so habe ich mich endlich mal tiefgehender mit SQL-Befehlen auseinandergesetz und, muss sagen, fange langsam an sie zu mögen :))

Das Problem dürfte tatsächlich das Henne-Ei-Problem sein. Womöglich kommt noch hinzu, dass es sich um MS Access handelt. Hier kann man - ich weiß nicht, wie es sich mit anderen Datenbanken verhält - nämlich in der normalen Tabellenansicht / -Anlage in einem Feld (in diesem Fall zum Beispiel ID des Kontakts des Kunden) einen Nachschlage-Assistentin verwenden, sprich ein DropDown-Feld, einbauen, welches dann einen Select ausführen kann.

Wenn ich jetzt ein neues Angebot direkt in der Tabelle anlegen, dann kommt die Angebots-Nr. über den "Autowert" und muss entweder die Kunden-Nr. händisch eintragen oder habe eben auch hier den Nachschlage-Assistentin drin, der bspw. auf alle Kunden-Nr. oder eben weiteren Einschränkungen selektiert.

Im Formular wird die Kunden-Nr. automatisch gefüllt, da "ein neues Angebot" ein Unterformular eines jeden Kunden ist und über "Bezug" dieses Feld versorgt wird.

Auf Hinweis von AW4 habe beide Vorgehen überprüft: Es sieht zwar so aus, als wenn die Zeile mit Leben gefüllt wird, aber so lange ich sie nicht verlasse / speichere, ist diese neue Zeile nicht reportbar - auch für ganz andere Abfragen nicht, die z.B. nur "alle Angebots-Nr." abfragen. Erst beim Verlassen / Speichern wird der Datensatz tatsächlich in die Tabelle geschrieben. Damit kann - mal unabhängig davon, ob es überhaupt ginge - der Wert (also die Kunden-Nr.), die ich für meine Where-Bedingung brauche, noch gar zurückgeliefert werden (nochmal auf gut deutsch: Zeige mir alle Kontakte, die aktuell gültig sind und zu diesem Kunden gehören, für den ich das Angebot gerade anlege).

Dabei wurde mir klar, dass dies in der Tabellensicht nicht wirklich wichtig ist, da die Anlage immer über Formulare erfolgen sollte. In den Formularen hingegen schwirrt die Kunden-Nr. schon irgendwo rum (sie ist ja bspw. am Hauptformular sichtbar) und ich muss dieses Feld nur noch irgendwie anzapfen und als Parameter an die Where-Bedingung im Formular-Dropdown-Feld übergeben. Dazu habe ich auch schon verschieden Sachen gefunden, gleichwohl ich noch keinen Plan habe, wie ich das zusammenbasteln soll 😁

Danke für eure Hilfe + @blablub1212
 
Zurück
Oben