Access 97: Komplexe Abfragen als Listenfelder

Ich habe folgende Problem zu Access 97:

Ich habe eine sehr komplexe Abfrage, die im Access-VB als SQL-String realisiert werden muss. Das Resultat dieser Abfrage soll in einem Listenfeld dargestellt werden (es sind 5 Spalten).

Wie kann dies am einfachsten realisiert werden? Ich kann mir folgende Möglichkeiten vorstellen (ich weiss nicht, ob dies in VB/Access möglich ist):

  • Dem Feld Datenherkunft des Listenfeldes soll eine Funktion zugrunde liegen. Diese Funktion „baut“ den Sql-String auf.
  • Ich kreiere eine temporäre Datenbank, die ich manuell fülle und die auch die Datenherkunft des Listenfeldes ist.
  • Ich baue eine Funktion, welche das Listenfeld manuell füllt (ich glaube, das heisst Callback-Funktion). Ich habe dies kurz angeschaut es sieht sehr kompliziert aus.

Welche dieser drei Varianten ist (überhaupt) machbar und welche ist am einfachsten? Gibt es noch andere Varianten?
Was vielleicht noch anzufügen ist: Das ganze soll auch noch auf Knopfdruck als Report ausdruckbar sein. Es sollte also igendwie „wiederverwendbar“ sein.

Danke für Eure Hilfen und Meinungen.

Stephan

Wie kann dies am einfachsten realisiert
werden? Ich kann mir folgende
Möglichkeiten vorstellen (ich weiss
nicht, ob dies in VB/Access möglich ist):

  • Dem Feld Datenherkunft des Listenfeldes
    soll eine Funktion zugrunde liegen. Diese
    Funktion „baut“ den Sql-String auf.

Verstehe ich nicht so ganz. Du hast doch schon irgendwo den SQL-String. Den kannst du der RowSource des Listenfelds zuweisen. Das ist wohl am einfachsten.

  • Ich kreiere eine temporäre Datenbank,
    die ich manuell fülle und die auch die
    Datenherkunft des Listenfeldes ist.

Wenn du „temporäre Tabelle“ meinst: Ja, so geht’s auch. (Ist aber nicht einfacher als der erste Fall)

  • Ich baue eine Funktion, welche das
    Listenfeld manuell füllt (ich glaube, das
    heisst Callback-Funktion). Ich habe dies
    kurz angeschaut es sieht sehr kompliziert
    aus.

Ist es in der Tat - und passt auch nicht so ganz.

Denkbar wäre noch Variante 4: Du erzeugst eine Werteliste mit deiner SQL - ist aber auch nicht gerade einfach…

Welche dieser drei Varianten ist
(überhaupt) machbar und welche ist am
einfachsten? Gibt es noch andere
Varianten?
Was vielleicht noch anzufügen ist: Das
ganze soll auch noch auf Knopfdruck als
Report ausdruckbar sein. Es sollte also
igendwie „wiederverwendbar“ sein.

Wenn du den SQL-String hast, kannst du den ja auch z.B. in der Recordsource des Berichts verwenden - oder zumindest seine WHERE-Klausel…

Reinhard

  • Dem Feld Datenherkunft des Listenfeldes
    soll eine Funktion zugrunde liegen. Diese
    Funktion „baut“ den Sql-String auf.

Verstehe ich nicht so ganz. Du hast doch
schon irgendwo den SQL-String. Den kannst
du der RowSource des Listenfelds
zuweisen. Das ist wohl am einfachsten.

Der SQL-String muss zuerst erstellt werden. Vielleicht muss ich hier weiter ausholen: Ich habe eine Personentabelle (als Master) und 5 „angehängte Tabellen“ (jeweils 1:n, also z.B. Sprachen, Skills, Kurse, Karriereplanung, Ausbildung). Es können 0-n Werte aus diesen jeweils 5 Tabelle ausgesucht werden.
Das sieht dann ungefähr so aus (jetzt mal auf eine Tabelle reduziert):

SELECT * FROM Pers, Skills WHERE Pers.Id = Skills.Id AND Skills.Desc IN (abc, xyz)

wobei abc, xyz dann Werte sind, die auf dem Formular markiert wurden (Mehrfachselektion auf einem Listenfeld). Wenn Mehrfachselektion nicht möglich wäre, dann könnte ich einfach sagen:

… AND Skills.Desc = [Forms]![TestForm]![listSkills]

Leider geht das bei Mehrfachselektionen (oder etwa doch, wie?) nicht. Hier kommt auch noch hinzu, dass wenn in einer dieser fünf „angehängten Tabellen“ nichts selektiert wurde, dann soll dieser Teil der Abfrage gar nicht in den SQL-String fliessen, also auch kein Join gemacht werden.

  • Ich kreiere eine temporäre Datenbank,
    die ich manuell fülle und die auch die
    Datenherkunft des Listenfeldes ist.

Wenn du „temporäre Tabelle“ meinst: Ja,
so geht’s auch. (Ist aber nicht einfacher
als der erste Fall)

Kann ich dann dem Listenfeld eine temporäre Tabelle als Quelle zuweisen, obwohl diese beim ersten öffnen des Formulars noch gar nicht besteht? Oder brauche ich dort bereits das Tabellegerüst, das halt leer ist?

Denkbar wäre noch Variante 4: Du erzeugst
eine Werteliste mit deiner SQL - ist aber
auch nicht gerade einfach…

? Wie genau geht das? Was ist eine Werteliste?

Danke für Deinen Input, ich hoffe, Du kannst mir weiterhelfen.

Stephan

Der SQL-String muss zuerst erstellt
werden. Vielleicht muss ich hier weiter
ausholen: Ich habe eine Personentabelle
(als Master) und 5 „angehängte Tabellen“
(jeweils 1:n, also z.B. Sprachen, Skills,
Kurse, Karriereplanung, Ausbildung). Es
können 0-n Werte aus diesen jeweils 5
Tabelle ausgesucht werden.
Das sieht dann ungefähr so aus (jetzt mal
auf eine Tabelle reduziert):

SELECT * FROM Pers, Skills WHERE Pers.Id
= Skills.Id AND Skills.Desc IN (abc, xyz)

wobei abc, xyz dann Werte sind, die auf
dem Formular markiert wurden
(Mehrfachselektion auf einem Listenfeld).
Wenn Mehrfachselektion nicht möglich
wäre, dann könnte ich einfach sagen:

… AND Skills.Desc =
[Forms]![TestForm]![listSkills]

Das ist eine sehr schlechte Lösung - besser ist es, die Vergleichswerte als Literale in den SQL-String aufzunehmen:

… AND Skills.Desc = "’ & [Forms]![TestForm]![listSkills] & „’“

bzw. wenn es um das aktuelle Formular geht:
… AND Skills.Desc = "’ & Me![listSkills] & „’“

Leider geht das bei Mehrfachselektionen
(oder etwa doch, wie?) nicht.

Mehrfachselektionen gehen mit meinem Vorschlag auch. Du musst halt die ListItems abgrasen und auf Selected prüfen…

Hier kommt
auch noch hinzu, dass wenn in einer
dieser fünf „angehängten Tabellen“ nichts
selektiert wurde, dann soll dieser Teil
der Abfrage gar nicht in den SQL-String
fliessen, also auch kein Join gemacht
werden.

Dann musst du das halt beim Aufbauen des Strings berücksichtigen - z.B.

If Not Isnull(Me!Test1) then _
SQL = SQL & " AND Test1 =’" & Me!Test1 & „’ "
If Not Isnull(Me!Test2) then _
SQL = SQL & " AND Test2 =’“ & Me!Test2 & „’ "
If Not Isnull(Me!Test3) then _
SQL = SQL & " AND Test3 =’“ & Me!Test3 & "’ "
SQL = Mid(SQL,5)

  • Ich kreiere eine temporäre Datenbank,
    die ich manuell fülle und die auch die
    Datenherkunft des Listenfeldes ist.

Wenn du „temporäre Tabelle“ meinst: Ja,
so geht’s auch. (Ist aber nicht einfacher
als der erste Fall)

Kann ich dann dem Listenfeld eine
temporäre Tabelle als Quelle zuweisen,
obwohl diese beim ersten öffnen des
Formulars noch gar nicht besteht?

Das geht schon…

Oder
brauche ich dort bereits das
Tabellegerüst, das halt leer ist?

In der Tat: warum legst du die Tabelle nicht dauerhaft an und löschst die Datensätze bzw. füllst sie halt nur nach Bedarf?

Denkbar wäre noch Variante 4: Du erzeugst
eine Werteliste mit deiner SQL - ist aber
auch nicht gerade einfach…

? Wie genau geht das? Was ist eine
Werteliste?

rtfm - schau mal in der Hilfe unter „Werteliste“ bzw. beim Listenfeld unter „Listenfeld, das auf einer Werteliste basiert“ nach…

Reinhard

Das ist eine sehr schlechte Lösung -
besser ist es, die Vergleichswerte als
Literale in den SQL-String aufzunehmen:

Wieso, läuft der
WHERE text = „Wert1“ AND text = „Wert2“
schneller als ein
WHERE text IN („Wert1“, „Wert2“)
?

Ich habe es jetzt so gelöst: Ich stelle mit den SQL-String in einer Funktion zusammen und überschreibe damit den RowSource meines Listenfeldes.

Danke für Deine Bemühungen.
Stephan

Das ist eine sehr schlechte Lösung -
besser ist es, die Vergleichswerte als
Literale in den SQL-String aufzunehmen:

Wieso, läuft der
WHERE text = „Wert1“ AND text = „Wert2“
schneller als ein
WHERE text IN („Wert1“, „Wert2“)

Das erstere ist ja eine Schnittmenge - der Query-Optimizer wählt (wenn er die nötigen Daten hat) die trennschärfere Bedingung zuerst aus, die andere wird dann auf die Ergebnismenge angewandt.

Das zweite ist ein „ODER“, also die Vereinigung zweier Mengen, die erst einmal separat gefunden werden müssen. Das ist natürlich langsamer.

Reinhard

Das ist eine sehr schlechte Lösung -

WHERE text = „Wert1“ AND text = „Wert2“

Das erstere ist ja eine Schnittmenge

die, so formuliert, immer Null Datensätze liefern wird :smile:

Gruß
J.

Tja - und dank eines von Microsoft patentierten Verfahrens (flushmoose optimization) lassen sich Nullmengen in Access besonders schnell ermitteln ;=)

Reinhard