PDA

Vollständige Version anzeigen : Denksportaufgabe: Knifflige SQL-Formulierung


Rockaga
24.03.2006, 15:48
Guten Tag, Forum,

ich hoffe, Ihr könnt mir bei folgendem SQL-Problem helfen:

Ich verwalte in einer Datenbank Existenzgründer mit Vorhaben (z.B. das Vorhaben, ein Unternehmen zu gründen) und zu diesen Vorhaben entsprechende Kontakte (in denen bspw. über die Gründung gesprochen wird; Vorhaben und Kontakte sind n:m verknüpft: tabKontakt-1-n-relVorKon-n-1-tabVorhaben). Jeder Kontakt hat ein Feld "Dauer", in dem die Länge des Kontakts in Minuten festgehalten wird.

Ich möchte nun für einen definierten Zeitraum (z.B. 1 Monat, 1 Quartal, 1 Jahr etc.) zunächst die Minuten-Summe aller Kontakte pro Vorhaben bilden - das habe ich so gelöst (z.B. für den Zeitraum 2005; diese Summe habe ich "Zeitkonto" genannt):

SELECT Sum(tabKontakt.Dauer) AS Zeitkonto
FROM tabKontakt INNER JOIN relVorKon ON tabKontakt.pkKon = relVorKon.fkKon
WHERE (((tabKontakt.Datum) Between #1/1/2005# And #12/31/2005#))
GROUP BY relVorKon.fkVor;


Diese Abfrage habe ich als Unterabfrage gespeichert ("uabf"). Dann habe ich folgendes Statement gebaut, das mir genau das liefert, was ich benötige:

SELECT uabf.Zeitkonto, Count(uabf.Zeitkonto) AS AnzVor
FROM uabf
GROUP BY uabf.Zeitkonto;


Hierdurch erhalte ich eine Auflistung, wieviele Vorhaben eine Zeitsumme von 10 Minuten, 20 Minuten etc. im betreffenden Zeitraum aufweisen:

Zeitkonto (Min.) Anzahl Vorhaben
10 40
20 33
30 23 etc.

Mein Problem ist nun, dass ich das ganze dynamisch in VBA verarbeiten möchte, um das Ergebnis als Datenbasis eines UFOs zu benutzen. Hierzu müsste ich das Zeitstatement in der uabf nach den Usereingaben umbauen (der User möchte bspw. nur Zeitkonten < 30 Min. betrachten). Das Problem ist, dass die zeitliche Eingrenzung in der gespeicherten uabf vollzogen wird, ich jedoch mit der Oberabfrage im Code arbeite. Weiß jemand, wie man ggf. die beiden obigen Abfragen zu einem Statement, das ich dann dynamisch im Code verarbeiten kann, zusammenführen kann? (hier hört meine SQL-Kenne einfach auf ...) :(
Oder gibt es eine andere Lösung des Problems?
Vielen Dank für Euer Mitdenken! :rolleyes:

Großer Meister
24.03.2006, 18:03
probier es mal hiermit:
SELECT (SELECT Sum(tabKontakt.Dauer) AS Zeitkonto FROM tabKontakt INNER JOIN relVorKon ON tabKontakt.pkKon = relVorKon.fkKon WHERE (((tabKontakt.Datum) Between #1/1/2005# And #12/31/2005#)) GROUP BY relVorKon.fkVor;) AS Zeitkonten, Count((SELECT Sum(tabKontakt.Dauer) AS Zeitkonto FROM tabKontakt INNER JOIN relVorKon ON tabKontakt.pkKon = relVorKon.fkKon WHERE (((tabKontakt.Datum) Between #1/1/2005# And #12/31/2005#)) GROUP BY relVorKon.fkVor;)) AS Zeitkonten
GROUP BY (SELECT Sum(tabKontakt.Dauer) AS Zeitkonto FROM tabKontakt INNER JOIN relVorKon ON tabKontakt.pkKon = relVorKon.fkKon WHERE (((tabKontakt.Datum) Between #1/1/2005# And #12/31/2005#)) GROUP BY relVorKon.fkVor;);
wenn du z.B. diese Abfrage im Code ausführst mit Currentdb.execute "Select (...", dann hast du Kontrolle über die Zeiträume, die der User dann eingeben kann.

Rockaga
24.03.2006, 20:31
:boah: Vielen Dank für die Mühe, doch leider funktioniert es nicht ...

Access meldet: Die Select-Anweisung schließt ein reserviertes Wort oder einen Argumentnamen ein, das/der falsch, mit falscher Zeichensetzung oder überhaupt nicht eingegeben wurde.

Vielleicht hilft es, wenn ich die mdb einmal zur Verfügung stelle?

Großer Meister
24.03.2006, 21:47
Also hier mal eine Option, du rufst die Daten der Abfrage abf so ab:
Function abfrageaufruf()
Dim qdf As DAO.QueryDef, rst As DAO.Recordset
Set qdf = CurrentDb.QueryDefs("abf")
qdf.Parameters!Datumvon = "01.01.2005"
qdf.Parameters!Datumbis = "31.12.2005"
Set rst = qdf.OpenRecordset(dbOpenDynaset)
Do
Debug.Print rst("zeitkonto") & " " & rst("anzvor")
rst.MoveNext
Loop While Not (rst.EOF)
End Function

wobei du in der Unterabfrage die beiden Parameter setzt:
PARAMETERS Datumvon DateTime, Datumbis DateTime;
SELECT Sum(tabKontakt.Dauer) AS Zeitkonto
FROM tabKontakt INNER JOIN relVorKon ON tabKontakt.pkKon = relVorKon.fkKon
WHERE (((tabKontakt.Datum) Between [Datumvon] And [Datumbis]))
GROUP BY relVorKon.fkVor;

Großer Meister
24.03.2006, 21:50
anstatt 01.01.2005 bzw. 31.12.2005 kannst du das Datum jeweils aus einem Textfeld holen, das der User füllen kann.
Damit das ganze funktioniert, musst du natürlich noch einen Verweis auf Microsoft DAO setzen.

Rockaga
25.03.2006, 11:27
Hallo, Markus,

ich habe das Problem jetzt folgendermaßen gelöst:

'Zeitkonto 2: Zeitkonto nur der Kontakte aus Zeitraum zum Vorhaben
'tmpZeitkonto als uabf erzeugen
strSQL = "SELECT Sum(tabKontakt.Dauer) AS Zeitkonto " _
& "FROM tabKontakt INNER JOIN relVorKon ON tabKontakt.pkKon = relVorKon.fkKon " _
& "WHERE (((tabKontakt.Datum) Between #" & strVon & lngJahr & "# And #" & strBis & lngJahr & "#)) " _
& "GROUP BY relVorKon.fkVor;"

Set db = CurrentDb
'alte abf löschen
DoCmd.DeleteObject acQuery, "tmpZeitkonto"
'neue abf erstellen
Set qry = db.CreateQueryDef("tmpZeitkonto", strSQL)

strSQL = "SELECT tmpZeitkonto.Zeitkonto AS Minuten, Count(tmpZeitkonto.Zeitkonto) AS AnzVor FROM tmpZeitkonto " _
& "GROUP BY tmpZeitkonto.Zeitkonto " _
& "HAVING (((tmpZeitkonto.Zeitkonto)>=" & intMinVon & " And (tmpZeitkonto.Zeitkonto)<" & intMinBis & "));"

Me!ufrmExiStatKonVoriZ.Form.RecordSource = strSQL

Erläuterung: Zunächst baue ich die uabf zusammen, incl. des vom User gewählten Zeitraums. Diese speichere ich als Abfrage, um sie dann in der Oberabfrage zu benutzen, die ich wiederum auf zeitliche Intervalle eingrenze. Den daraus entstandenen SQL-String übergebe ich an das ufrm zur Anzeige ... eigentlich ganz einfach ;) - danke für den Schubs in die richtige Richtung! :grins: