Das Access-Magazin für alle, die schnell von 0 auf

Transcription

Das Access-Magazin für alle, die schnell von 0 auf
Access [basics]
www.access-basics.de
Das Access-Magazin für alle, die schnell von 0 auf 100 wollen
Abfragen für die
­Datenauswahl
Teil III: Filtern von Textfeldern
Im vorliegenden und den folgenden Teilen dieser
Artikelserie zum Thema Abfragen beschäftigen wir
uns mit den verschiedenen Möglichkeiten zum Auswählen von Daten über verschiedene Kriterien. Den
Start machen einfache Textkriterien.
Sie erinnern sich noch an den Chef unserer kleinen
Beispielfirma Schwuppdiwupp? Der saß doch am
Wochenende immer am Computer und hat die Daten
der verschiedenen Mitarbeiter zusammengeführt.
Inzwischen hat ihm sein neuer Mitarbeiter die Daten ja in Access-Tabellen zusammengefasst, aber so
richtig glücklich ist er noch nicht. Jetzt will er doch
wieder einzelne Daten sehen...
Beispielsweise konnte er früher einfach in der jeweiligen Excel-Tabelle nachgucken, welche Projekte Tabea Neukirch bearbeitet hat. Jetzt stehen alle
Mitarbeiter zusammen in der gleichen Tabelle und er
muss die erst wieder herausfiltern. Dabei ist das gar
nicht so schwierig: in 03/2010 haben wir schon gezeigt, wie so eine Auswahlabfrage aussieht. Es geht
aber noch besser.
Basisabfrage erstellen
Erstellen Sie also zuerst einmal eine neue Abfrage
mit den drei Tabellen tblProjekte, tblMitarbeiterProjekte und tblMitarbeiter. Aus diesen fügen Sie
per Doppelklick die Felder Projektbezeichnung, Vorname und Nachname zum Entwurfsraster der Abfrage hinzu.
Auch wenn Sie aus der Tabelle tblMitarbeiterProjekte selber gar kein Feld brauchen, erinnern Sie
sich sicher, dass diese als Verbindung zwischen den
beiden anderen Tabellen notwendig ist (siehe auch
Tabellen entwerfen - Teil III: Mitarbeiter per m:nBeziehung zu Projektteams zusammenstellen).
Was Sie in diesem Artikel lernen
»» Textfelder nach einfachen Zeichenketten filtern
»» Platzhalter für das Filtern einsetzen
»» Und- und Oder-Verknüpfungen verwenden
Abfragen im Griff
Diese Ausgabe von Access [basics] stellt einerseits das
Thema Abfrage und andererseits eine Lösung zum Verwalten von m:n-Beziehungen mit Listenfeldern in den
Mittelpunkt. Nebenher lernen Sie noch den Umgang
mit VBA-Variablen kennen.
Doch zunächst zu den Abfragen: Zu diesem Thema finden Sie gleich drei Artikel. Im ersten zeigen wir Ihnen,
wie Sie die Datensätze der Abfrage nach dem Inhalt
von Textfeldern filten können. Es geht allerdings nicht
nur um den einfachern Vergleich mit Zeichenketten,
denn wir nehmen auch Spezialitäten wie die Platzhalter
unter die Lupe. Außerdem erfahren Sie, wie Sie verschiedene Kriterien mit Operatoren wie OR oder AND
verknüpfen können.
Der zweite Artikel zum Thema Abfragen beschäftigt
sich mit Abfrageparametern: Sie können eine Abfrage
nämlich so anlegen, dass der Benutzer beim Ausführen
selbst die Kriterien festlegen kann – ohne selbst den
Entwurf zu ändern! Und schließlich schauen wir uns
an, wie Sie Daten nach Zahlenfeldern filtern können –
einen kleinen Abstecher in die Welt der Unterabfragen
inklusive.
Wer mit VBA programmiert, kommt selten ohne den
Einsatz von Variablen aus. Dabei handelt es sich um
Platzhalter für Werte, die während des Ablaufs einer
VBA-Routine gefüllt und auch wieder ausgelesen werden können. Alles zu diesem Thema finden Sie hier.
Und schließlich wollen wir am Beispiel der Projektzeiterfassung zeigen, wie Sie die Werte aus per m:n-Beziehung verknüpften Tabellen mit Hilfe eines einfachen
Formulars und zweier Listenfelder verwalten können.
Viel Spaß beim Lesen!
[André Minhorst]
In dieser Ausgabe:
Abfragen für die D
­ atenauswahl - Teil III: Filtern
von Textfeldern
Abfragen für die D
­ atenauswahl – Teil IV: Einsatz
von Parametern
Abfragen für die Datenauswahl – Teil V: Filtern
nach Zahlen
VBA-Programmierung – Teil II: Variablen in VBA
Formulare für die Datenbearbeitung – Teil V: m:nBeziehungen in Listenfeldern darstellen
ISSN: 2190-8761
Access [basics]
8/2010
www.access-basics.de
der Nachname eben nicht eindeutig ist,
müssen Sie mit dem Vornamen ein weiteres Kriterium hinzufügen.
Es ist übrigens wichtig, dass der Vorname
als zweites Kriterium in der gleichen Zeile steht. Nur dann liefert die Abfrage alle
Datensätze, die beide Kriterien gleichzeitig erfüllen.
Und-Verknüpfung
Bild 1: Der Entwurf der Abfrage, um die Projekte bestimmter Mitarbeiter zu finden
Bild 2: Das Abfrage-Ergebnis für Tabea Neukirch
Kriterien definieren
Jetzt tragen Sie nur noch den Wert Tabea als Kriterium in die Spalte Vorname und Neukirch in die Spalte
Nachname ein und die Abfrage ist fertig. Sie können
diese direkt als qryProjekteMitMitarbeiternTabea
speichern (s. Bild 1).
Access erkennt automatisch, dass es sich bei beiden
Feldern um Textfelder handelt. Daher werden die
Kriterien beim Verlassen der Zelle oder beim Speichern der Abfrage automatisch in Gänsefüßchen gesetzt, damit es syntaktisch korrekt ist.
Das nennt sich in mathematischer Logik
eine UND-Verknüpfung: Beide Kriterien
müssen gleichzeitig erfüllt werden. Leider spielt uns da unser täglicher Umgang
mit der Sprache einen Streich. Wenn Frau
Köhler aus unserer Beispielfirma morgens in der Küche erzählt, dass Sie am
Wochenende in einem Konzert mit Musik
von Bach und Bartók gewesen war, dann
mag sie das für einen unvergesslichen
Abend halten.
Ein Logiker hingegen wundert sich, denn
Béla Bartók wurde erst rund 200 Jahre
nach Johann Sebastian Bach geboren.
Wie können die beiden zusammen Musik
komponiert haben? Oder wurden im Konzert die Stücke der beiden Komponisten gleichzeitig gespielt?
Das muss ja furchtbar geklungen haben!
Oder-Verknüpfung
Selbstverständlich meinte Frau Köhler nicht, dass
die Musik von Bach und Bartók war, sondern dass
es entweder ein Stück von Bach oder von Bartók
war. Das sprachliche „und“ ist im logischen Sinne
in den meisten Fällen ein ODER. Warum das hier
so wichtig ist? Na, dann suchen Sie doch mal nach
den Projekten der Kollegen Fischer und Schneider!
Wenn der Chef nun diese Abfrage ausführt, sieht er
tatsächlich die beiden Projekte, an denen die Mitarbeiterin arbeitet (s. Bild 2).
Es ist wichtig, dass Sie sowohl den Vor- als auch den
Nachnamen in den Filterkriterien angeben. Lassen
Sie das Kriterium Tabea für Vorname weg, sehen Sie
insgesamt vier Ergebnisse (s. Bild 3).
Da auch Tabeas Bruder Erich in der Firma arbeitet,
werden nun die Projekte der beiden angezeigt. Da
Seite 2
Bild 3: Das Abfrage-Ergebnis nur für Neukirch
Access [basics]
8/2010
www.access-basics.de
Mal abgesehen davon, dass wir derzeit
noch gar keine Möglichkeit kennen, zwei
Kriterien für das gleiche Feld unterzubringen, wäre es falsch. In Wirklichkeit
suchen Sie nämlich nach den Projekten
der Kollegen Fischer oder (!) Schneider.
Bild 4: Die Suche nach den Mitarbeitern Fischer beziehungsweise
Schneider
Erst wenn Sie das genauer formulieren,
fällt die vorherige Unmöglichkeit auf. Sie
hätten nämlich alle Datensätze gesucht,
deren Nachname Fischer und gleichzeitig Schneider lautet. Es gibt aber nur Datensätze, deren Nachname Fischer oder
Schneider ist.
Um mehrere Kriterien mit ODER zu verknüpfen, schrei­ben Sie diese in untereinander liegende Zeilen. Am linken Rand
zeigt Access dort für die erste Folgezeile
schon ein oder: an. Es sind aber beliebige
weitere Zeilen für eine ODER-Verknüpfung nutzbar (s. Bild 4).
Das Ergebnis liefert in diesem Fall je ein
Projekt pro Mitarbeiter (s. Bild 5).
Bild 5: Die Abfrage mit ODER-Verknüpfung arbeitet korrekt.
Automatische ­
Abfrage-Umgestaltung
Sobald Sie eine Abfrage wie diese (unter
dem Namen qryProjekteMitMitarbeiternFischerOderSchneider) zuerst gespeichert, geschlossen und dann wieder
in der Entwurfsansicht geöffnet haben,
sieht sie anders aus als zuvor (s. Bild 6).
Die beiden Filterkriterien stehen nicht
mehr untereinander, sondern in der gleichen Zelle nebeneinander und sind durch
das Schlüsselwort ODER verbunden.
Bild 6: Nach dem Speichern sieht der Abfrage-Entwurf anders aus.
Damit haben wir auch die Lösung gefunden, wie mehrere Kriterien für eine einzige Spalte durch ein logisches UND verbunden werden können.
Sie können ja mal testen, was passiert,
wenn Sie die Suchbegriffe Fischer und
Schneider tatsächlich mit UND verknüpfen (s. Bild 7).
Wie schon vorausgesagt, gibt es keinen
Datensatz, dessen Nachname beide Kriterien gleichzeitig erfüllt. Wofür es dieses
logische UND dann gibt?
Bild 7: So suchen Sie nach Fischer und Schneider gleichzeitig.
Seite 3
Jedenfalls nicht für Textfelder, dort können Sie praktisch immer von einem logischen ODER ausgehen, aber in Zahlen-
Access [basics]
8/2010
www.access-basics.de
• Das Doppelkreuz oder Rautenzeichen (#) steht
noch genauer für exakt eine Ziffer an dieser Stelle.
Um nun also den so unscharf beschriebenen Nachnamen zu finden, können Sie darauf bauen, dass
praktisch alle Berufsbezeichnungen auf „er“ enden.
Erstellen Sie eine neue Abfrage basierend auf tblMitarbeiter und geben für das Feld Nachname als Kriterium *er ein. Access korrigiert das beim Verlassen
der Zelle direkt in die vorgeschriebene Syntax Wie
„*er“ (s. Bild 8).
Und siehe da, es war kein Jäger, sondern wohl die
Frau Förster, die gemeint war (s. Bild 9)!
Bild 8: Diese Abfrage findet alle Nachnamen, die auf „er“
enden.
Bild 9: Da haben
wir alle Nachnamen, die so ähnlich wie ein Beruf
klingen.
Mit dem Sternchen, also der sehr unscharfen Suche,
kommen wir aber nicht weiter, wenn sich jemand nur
daran erinnert, dass irgendwie der vorletzte Buchstabe im Vornamen ein „i“ gewesen war. Eine Suche
nach Wie „*i*“ würde nämlich auch Erich und Dirk
nennen.
Hier muss das Kriterium daher so lauten (s. Bild 10):
Wie „*i?“
feldern wird es wichtig werden, wie Sie im Beitrag
Abfragen für die Datenauswahl - Teil V: Filtern nach
Zahlen sehen.
Einsatz von Platzhaltern
Bisher haben wir aber immer exakte Suchkriterien
gehabt. Was ist, wenn Sie es nur ungefähr wissen?
Der gesuchte Mitarbeiter hatte irgendwie so einen
Nachnamen, der wie ein Beruf klingt: Jäger oder
so... Auch das können Abfragen leisten, nämlich mit
dem Wie-Operator und drei Joker-Zeichen.
• Das Sternchen (*) erlaubt beliebig viele Zeichen
an dieser Position, es kann aber eben auch gar
keines dort sein.
• Das Fragezeichen (?) verlangt, dass dort genau
ein Zeichen stehen muss.
Seite 4
Bild 10: Mit diesem Kriterium finden Sie alle Vornamen,
deren vorletzter Buchstabe ein „i“ ist.
Bild 11: David und
Julia sind die einzigen Vornamen,
die dieses Kriterium erfüllen
Access [basics]
8/2010
www.access-basics.de
Das bedeutet, dass vor dem „i“ beliebig viele Buchstaben stehen dürfen, danach aber genau ein Buchstabe stehen muss. So ermitteln Sie, dass nur noch
David und Julia in Frage kommen, wie Bild 11 zeigt.
Für ein Beispiel mit der Raute (#) braucht es vor allem einen Text, der auch Ziffern enthält. Tragen Sie
also zuerst in der Tabelle tblKunden einen neuen
Datensatz ein für die Firma pro9 in 52099 Aachen,
Hauptstraße 1, mit Frau Julia Meier als Ansprechpartnerin.
Auf dieser Tabelle basierend erstellen Sie anschließend eine neue Abfrage mit dem Feld Kunde und
dem Kriterium Wie „*#*“. Dieses Kriterium verlangt, dass irgendwo im Kundennamen eine Ziffer
vorkommt (s. Bild 12).
Natürlich ist es keine wirklich große Überraschung,
dass nun die frisch hinzugefügte Firma pro9 angezeigt wird, denn genau das sollte ja gelingen.
Bild 12: So finden Sie einen Text mit einer Ziffer darin.
Mit diesen Techniken können Sie sehr flexibel nach
Texten filtern. Mit Zahlen werden wir uns im Artikel
Abfragen für die Datenauswahl - Teil V: Filtern nach
Zahlen beschäftigen und in einem Artikel in einer der
kommenden Ausgaben geht es um das Filtern nach
Datumswerten.
Bild 13: Diese
Firma enthält wie
gesucht eine Ziffer
im Namen.
Impressum
Access [basics] wird monatlich herausgegeben von:
André Minhorst | Fachverlag für Softwareentwicklung | Borkhofer Straße 17 | 47137 Duisburg
Die hier veröffentlichten Texte sind urheberrechtlich geschützt. Übersetzung und Vervielfältigung bedürfen der ausdrücklichen schriftlichen Genehmigung des Verlages. Sämtliche Veröffentlichungen in Access [basics] erfolgen ohne Berücksichtigung eines eventuellen Patentschutzes, auch werden Warennamen ohne Gewährleistung einer freien Verwendung
benutzt.
André Minhorst Fachverlag für Softwareentwicklung übernimmt für beschriebene oder zum Download bereitstehende
Programme weder Gewähr noch Haftung, außer für Vorsatz oder grobe Fahrlässigkeit. Bezugspreise erfahren Sie auf
www.access-basics.de.
Redaktion:
André Minhorst (V.i.S.d.P) | Telefon: 0203/4495577 | E-Mail: [email protected] | Internet: www.access-basics.de
Geschäftsführung, Herstellung, Text- und Schlussredaktion, Layout von Magazin und Webseite: André Minhorst
Autoren: Lorenz Hölscher, André Minhorst
ISSN: 2190-8761
Seite 5
Access [basics]
8/2010
www.access-basics.de
Abfragen für die ­Datenauswahl
Teil IV: Einsatz von Parametern
Der Aufbau von Abfragen ist gar nicht so schwer – zumindest wenn Sie sich auf Abfragen mit einer überschaubaren Anzahl verknüpfter Abfragen beschränken. Allein eines nervt: Wenn Sie mal die Kriterien
für die Auswahl der gesuchten Datensätze ändern möchten, müssen Sie jedesmal in den Abfrageentwurf
wechseln, dort die gewünschten Einstellungen vornehmen und wieder zur Datenblattansicht zurückkehren.
Damit dies etwas einfacher wird, stellt Ihnen dieser Artikel Abfrage-Parameter vor.
Finden Sie es praktisch, durch
ständige Anpassung der Kriterien
nach den Mitarbeitern zu suchen?
Wenn das so bliebe, müsste der
Chef jedes Mal in die Entwurfsansicht wechseln, dort den Namen
eintragen und erst dann diese Abfrage ausführen.
Alternativ kommen viele AccessNutzer jetzt auf die Idee, für jeden Mitarbeiter eine Abfrage zu
speichern, also qryXYZ_Fischer,
qryXYZ_TabeaNeukirch, qry­XYZ_
ErichNeukirch und so weiter.
Bild 1: So geben Sie einen Parameter an.
Parameter-Abfrage
Das heißt, dass Sie für jeden Mitarbeiter eine eigene Abfrage anlegen müssten – und das für jede gewünschte Information.
Vom Platzbedarf in der Access-Datenbank her ist das
relativ unproblematisch. Abfragen brauchen nur wenig Speicher, denn sie speichern nur die Frage (Sie
werden beim Stichwort SQL sehen, das es sich nur
um einen schlichten Text handelt) und nicht die Antwort (die aus Millionen Datensätzen bestehen könnte).
Manch ein Entwickler nutzt dies ohne Rücksicht aus
und erstellt Abfragen nach diesem Muster: qryUmsatzJanuar, qryUmsatzFebruar bis qryUmsatzDezember.
Aber wo bleibt da die Übersicht für Sie als Nutzer der
Datenbank? Sie müssten mit zehn Mal so vielen Abfragen zurechtkommen und für jeden neuen Mitarbeiter außerdem eine neue Abfrage anlegen.
Was Sie in diesem Artikel lernen
»» Wozu brauche ich Parameter-Abfragen?
»» Wie formulare ich eine Parameter-Abfrage?
»» Wie kann ich mit einer Parameter-Abfrage viele gleichartige
Abfragen ersetzen?
Seite 6
Es gibt in Access einen besonderen Typ Auswahl-Abfragen, dessen Kriterien flexibel sind: die Parameter-Abfragen. Sie fragen bei jeder Ausführung immer
nach, welches Kriterium dieses Mal berücksichtigt
werden soll. Das ist genau für den Fall gedacht, dass
Sie bei jedem neuen Aufruf der Abfrage die Daten
zu einem anderen Mitarbeiter in Erfahrung bringen
möchten.
Bauen wir doch gleich eine erste Parameter-Abfrage. Dazu kopieren Sie die bereits erstellte Abfrage
qry­Projekte­Mit­Mit­ar­bei­tern­FischerUndSchneider
und geben der Kopie den Namen qry­Pro­jekte­Mit­Mit­
ar­beiternParameter.
Dies erledigen Sie am schnellsten, indem Sie
qryProjekteMitMitarbeitern­Fischer­­Und­Schneider
im Datenbankfenster (Access 2003 und älter) beziehungsweise im Navigationsbereich (Access 2007 und
jünger) markieren und nacheinander die Tastenkombinationen Strg + C und Strg + V betätigen. Access
fragt dann nach dem Namen für die Kopie des Objekts.
Öffnen Sie die neue Abfrage und löschen Sie alle
bisherigen Kriterien. Dort, wo bisher der Text „Fi-
Access [basics]
8/2010
www.access-basics.de
scher“ Und „Schneider“ stand, fügen Sie nun einen
sogenannten Parameter ein. Der Parameter muss in
eckigen Klammern stehen und darf nicht den Namen
eines der in den zugrunde liegenden Tabellen enthalten. Wenn Sie nun beispielsweise
Bild 2: Eingabe des Parameters als Kriterium der
Abfrage
[Welcher Nachname?]
als Kriterium eingeben, sind Sie auf der sicheren
Seite (s. Bild 1): So heißt garantiert keines der Felder, zumindest, wenn Sie sich sich an die gängigen
Konventionen für die Benennung von Feldern halten
(siehe [basics] Konventionen).
Warum aber formulieren wir den Namen des Parameters als Frage? Nun: Access hat einen eingebauten Mechanismus, der alle Elemente einer Abfrage,
die nicht als Feldname oder Schlüsselwort erkannt
werden, entdeckt und den Benutzer fragt: „Diesen
Wert kenne ich nicht! Sag mir, welchen Wert ich dafür
annehmen soll!“
Sobald ein Benutzer diese Abfrage ausführt, erscheint ein kleiner Dialog mit dem Feldnamen darüber und einem Eingabefeld, damit der Benutzer den
Inhalt des Kriteriums angeben kann. Geben Sie nun
Fischer ein und bestätigen den Dialog (s. Bild 2), so
sehen Sie ein ganz normales Abfrage-Ergebnis in der
Datenblattansicht (s. Bild 3).
Seite 7
Bild 3: Die Parameter-Abfrage hat funktioniert und zeigt
die gefilterten Datensätze für Fischer an.
Sobald Sie wieder in den Entwurf der Abfrage zurückwechseln, ist der Parameter-Inhalt vergessen.
Sie müssen ihn daher bei jeder Ausführung erneut
eingeben. Damit haben wir uns erst einmal ganz
viele ähnliche Abfragen erspart.
Eine einzige Parameter-Abfrage ermöglicht die
wechselnde Eingabe von Kriterien zur Ausführungszeit. Der Chef muss also nicht mehr in den
Abfrage-Entwürfen herumbasteln, sondern braucht
diese einfach nur noch zu öffnen.
Access [basics]
8/2010
www.access-basics.de
Abfragen für die Datenauswahl
Teil V: Filtern nach Zahlen
Viele Auswertungen basieren auf Zahlenkriterien. Welche Artikel kosten mehr als 100,- Euro? Welcher
Kunde hat den größten Umsatz generiert? Welcher Artikelbestand erfordert eine Nachbestellung? Aber
auch: Welche Bestellungen gehören zum Kunden mit der Kundennummer 1234? Dieser Artikel zeigt, wie
Sie Daten mit Zahlenkriterien filtern.
Bild 1: Abfrage
aller Datensätze, deren
Lagerbestand
den Wert 0 hat
Da die Projektzeiterfassung als eigentliche Beispieldatenbank von Access [basics] zum aktuellen Zeitpunkt keine umfassenden Zahlenfelder bietet, die wir
nach Herzenslust für das Durchführen von Beispielen heranziehen können, weichen wir im Rahmen
dieses Artikels auf die Südsturm-Datenbank aus.
Südsturm-Datenbank? War da nicht was? Gibt es da
nicht eine Beispieldatenbank von Microsoft namens
Nordwind? Genau: Und eben dieser haben wir die Tabellen entnommen.
Bild 2: Ergebnis der
Abfrage aller
ausverkauften
Datensätze
Und nicht nur das: Wir haben auch noch einige Anpassungen durchgeführt, damit die Tabellen- und
Feldnamen den unter [basics] Konventionen beschriebenen Regeln entsprechen.
Doch zur Sache: Wir beginnen mit der Tabelle tblArtikel, die einige interessante Zahlenfelder enthält. Da
wäre zum Beispiel der Einzelpreis, der Bestand, die
bestellten Einheiten oder der Lagerbestand.
Feld mit bestimmtem Zahlenwert
Die einfachsten Abfragen mit Zahlenkriterien enthalten nur den Vergleichswert und liefern so alle Datensätze, bei denen etwa das Feld Lagerbestand den
Wert 0 aufweist.
Dazu legen Sie eine neue Abfrage mit der Tabelle
tblArtikel an und fügen die Felder ArtikelID, Artikelname und Lagerbestand zum Entwurfsraster hinzu
(siehe [basics] Abfrage erstellen) und speichern diese
unter dem Namen qryLagerbestandIstNull. Tragen
Sie in der Zeile Kriterien den Wert 0 für das Feld Lagerbestand ein (siehe Bild 1). Das Ergebnis liefert
genau die gewünschten Datensätze (siehe Bild 2).
Nur Zahlen!
Wenn Sie Vergleichswerte für Zahlenfelder angeben,
dürfen Sie ebenfalls nur Zahlen verwenden (abgesehen von den nachfolgend vorgestellten Operatoren).
Sie dürfen keine Texte wie beispielsweise Euro oder
% zusätzlich zum Zahlenwert eingeben – Access
meldet dann einen Fehler.
Größer, kleiner, gleich
Dieses Kriterium entspricht prinzipiell dem Ausdruck =0. Diesen können Sie alternativ eingeben. Von
dort aus kommen wir schnell auf die übrigen möglichen Operatoren für das Filtern von Zahlenwerten:
• Größer (>)
• Größer gleich (>=)
• Kleiner (<)
Was Sie in diesem Artikel lernen
»» Einsatz von Kriterien für Zahlenfelder
»» Verwendung von Operatoren wie AND, OR, BETWEEN oder
IN
»» Kombination mehrerer Kriterien in Abfragen
»» Einsatz des Schlüsselworts NULL
Seite 8
• Kleiner gleich (<=)
Statt =0 können Sie also beispielsweise Werte wie >0,
>=10 oder <100 eingeben.
Access [basics]
8/2010
www.access-basics.de
Ungleich
Für das Finden von Datensätzen, deren Feldwert
ungleich dem betreffenden Wert ist, haben Sie zwei
Möglichkeiten: Sie können erstens die Kombination
aus größer (>) und kleiner (<) verwenden, also <>,
aber auch den Operator NOT einsetzen. Dieser ist
übrigens mit beliebigen Ausdrücken kombinierbar.
Wenn Sie alle Artikel finden möchten, deren Lagerbestand ungleich 10 ist, verwenden Sie also entweder das Kriterium <>10 oder NOT 10. Lassen Sie sich
nicht täuschen, wenn Sie NOT 10 als Kriterium eintragen und Access dies gleich nach dem Verlassen
des Feldes in Nicht 10 umwandelt (siehe Bild 4): Dies
ist eine Eigenschaft der deutschsprachigen AccessVersion.
Im Hintergrund speichert Access ohnehin den SQLAusdruck, und zwar mit englischen Schlüsselwörtern. Zum Thema SQL kommen wir zu einem späteren Zeitpunkt.
Zwischen zwei Werten
Bild 3: Schlüsselwörter wie
NOT werden im
Abfrageentwurf
der deutschen
Access-Version
eingedeutscht.
Bild 4: Abfragen eines
Bereiches von
Werten
Bild 5: Bereichsabfrage,
diesmal mit
BETWEEN
Vielleicht möchten Sie auch einmal alle Artikel ermitteln, deren Preis zwischen 10,- Euro und 20,- Euro
liegt. Dann haben Sie ebenfalls zwei Möglichkeiten:
• Sie verwenden den AND-Operator, um die Kriterien >=10 und <=20 zu verknüpfen. Der Abfrage-Editor macht dann >=10 Und <=20 daraus (s.
Bild 5).
• Oder Sie verwenden direkt den für solche Fälle
vorgesehen BETWEEN ... AND ...-Operator. Dazu
geben Sie den Ausdruck BETWEEN 10 AND 20
als Kriterium, was umgehend in Zwischen 10
Und 20 umgewandelt wird (s. Bild 6).
Bild 6: Artikel,
die weniger als
10,- Euro oder
mehr als 20,Euro kosten
Englische und deutsche Operatoren
Warum führen wir immer die englischen Schlüsselwörter an, wenn der Abfrage-Editor diese doch
in die deutschen Pendants umwandelt – zumindest
in der deutschen Version von Access? Ganz einfach:
Access speichert die Ausdrücke intern in der englischen Version. Und das ist auch die Version, die
Sie später kennenlernen, wenn Sie einmal manuell
Abfrageausdrücke zusammenstellen. Das kommt
zwar kaum vor, weil Sie immer den Abfrage-Designer zu Hilfe nehmen können, aber es gibt auch Ausnahmen.
Seite 9
Werte außerhalb eines Bereichs
Vielleicht möchten Sie auch einmal alle Artikel auflisten, die gerade nicht im Preissegment zwischen
10,- Euro und 20,- Euro liegen. Dann hilft der ANDOperator nicht weiter: Er liefert nur Datensätze, für
die alle mit Und verknüpften Kriterien gelten. Hier
kommt der OR-Operator ins Spiel. Der Ausdruck <10
Access [basics]
8/2010
www.access-basics.de
Or >20 (zuverlässig umgewandelt in <10 Oder >20)
liefert alle Artikel, deren Preis nicht zwischen 10,Euro und 20,- Euro liegt (s. Bild 7).
Bild 7: Aufteilung der per
OR verknüpften
Kriterien auf
zwei Zeilen
Auch hier gibt es alternative Formulierungen des
Kriteriums, zum Beispiel:
NOT BETWEEN 10 AND 20
Nach dem gleichen Schema sollte sich der Ausdruck
>10 AND <20 negieren lassen:
Nicht >10 Und <20
Tut er aber nicht: Dieser Ausdruck liefert lediglich
die Datensätze, deren Preis kleiner gleich 10,- Euro
ist. Warum? Weil der AND-Operator nicht zuerst >10
und <20 verkettet und dann den gesamten Ausdruck
mit NOT negiert, sondern weil er Nicht >10 und <20
zusammenfasst. Unser Plan geht erst auf, wenn wir
>10 AND <20 in Klammern einfassen und diesen
Ausdruck mit NOT negieren:
Bild 8: Abfrage von Artikeln nach bestimmten Kategorien
NOT (>10 Und <20)
Für den ursprünglichen Ansatz des Kriteriums <10
OR >20 gibt es noch eine alternative Schreibweise im
Abfrage-Editor. Dabei verwenden Sie die oft vernachlässigte oder-Zeile unterhalb der Kriterien-Zeile
(siehe Bild 1). Beim Schließen wandelt Access dies
jedoch wieder in <10 OR >20 um.
Bild 9: Abfrage
von Artikeln
nach bestimmten Kategorien
per KategorieID
Mit Mengen vergleichen
Wenn Sie ein Feld nach einer ganzen Reihe von Kriterien filtern möchten, würden Sie normalerweise
entsprechend viele durch OR verknüpfte Vergleichswerte angeben. Wenn Sie beispielsweise alle Artikel
erhalten möchten, die zu den Kategorien Getränke,
Fleischprodukte oder Naturprodukte gehören, führen Sie die beiden Tabellen tblArtikel und tblKategorien wie in Bild 8 in einer Abfrage zusammen und
verwenden das Feld Kategoriename als Kriterienfeld. Der Vergleichswert heißt dann beispielsweise:
"Getränke" Oder "Fleischprodukte" Oder "Naturprodukte"
Alternativ zu dieser Schreibweise verwenden Sie das
IN-Schlüsselwort, das eine in Klammern angegebene Liste der mit OR verknüpften Vergleichswerte erwartet:
IN ("Getränke";"Fleischprodukte";"Naturprodukte")
Seite 10
Damit sind wir jedoch ein wenig vom Thema abgekommen, denn eigentlich behandeln wir hier ja die
Filtermöglichkeiten für Zahlenfelder. Also schnell
zurück: Eine Kategorie ist für einen Artikeldatensatz
nicht mehr als eine Zahl im Fremdschlüsselfeld KategorieID. Eine Abfrage wie oben, die Artikel nach
der Bezeichnung der Kategorie auswählt, werden Sie
in der freien Wildbahn hoffentlich nicht finden.
Dort können Sie vielleicht Kategorien aus einem
Steuerelement wie einem Listenfeld auswählen und
sich die entsprechenden Artikel anzeigen lassen.
Dabei wird die Abfrage jedoch nicht auf den Kategorienamen, sondern auf die im Listenfeld ausgeblendeten KategorieID zugreifen. Tun wir also so, als ob
wir gerade von einem solchen Listenfeld die Anfrage
nach allen Artikeln der Kategorien 1, 6 und 7 erhal-
Access [basics]
8/2010
www.access-basics.de
ten hätten. Die Abfrage benötigt die Tabelle tblKategorien nicht mehr, denn die KategorieID ist ja bereits
in der Artikeltabelle enthalten.
In Entwurf sieht die Abfrage nun wie in Bild 3 aus und
liefert genau die gewünschten Datensätze.
IN-Operator mit Abfrageergebnis
Der Clou beim IN-Operator ist, dass die Werte auch
aus einer weiteren Abfrage stammen können. Dummerweise ist bereits hier der Zeitpunkt gekommen,
zu dem Sie nicht mehr ohne eine in SQL formulierte
Abfrage herumkommen.
Bild 10: Abfrage von Artikeln nach bestimmten Kategorien
per KategorieID
Wenn Sie die Werte für den IN-Operator über eine
Abfrage erhalten möchten, müssen Sie diese in reinem SQL angeben. Dennoch erledigen wir die Vorarbeit mit Hilfe des Abfrage-Assistenten.
Dazu erstellen Sie eine neue Abfrage auf Basis der
Tabelle tblKategorien, welche die KategorieID für
drei Kategorien Getränke, Fleischprodukte und Naturprodukte liefert (siehe Bild 10).
Bild 11: SQL-Abfrage als Parameter der IN-Klausel
Die als Parameter der IN-Klausel angegebene Abfrage muss eine Bedingung unbedingt erfüllen: Sie
darf nur ein einziges Feld zurückgeben. Wenn Sie nur
das Feld KategorieID der Abfrage qryBestimmteKategorien erhalten möchten, verwenden Sie den folgenden SQL-Ausdruck:
SELECT KategorieID FROM qryBestimmteKategorien
Diese Abfrage liefert schlicht und einfach die drei
Werte 1, 6 und 7 als Ergebnis. Und genau das benötigen wir für die IN-Klausel. Also fügen wir den SQLAusdruck dort in die Klammern ein und erhalten einen Abfrage-Entwurf wie in Bild 11.
Ein interessantes Beispiel für den IN-Operator in
Kombination mit einer sogenannten Unterabfrage
finden Sie im Artikel Formulare für die Datenbearbeitung – Teil V: m:n-Beziehungen in Listenfeldern
darstellen.
Literale und Ausdrücke
Bislang haben wir nur feste Zahlen als Vergleichsoperatoren verwendet – mit Ausnahme der Unterabfrage, welche die Werte für den IN-Operator lieferte.
Es gibt jedoch noch viel mehr Möglichkeiten, Zahlenfelder mit Vergleichskriterien zu versehen.
Seite 11
Bild 12: Vergleich eines Zahlenfeldes mit dem Inhalt eines
anderen Feldes
Bild 13: Alle
Artikel, deren
Lagerbestand
kleiner oder
gleich dem
Mindestbestand ist
In der Tabelle tblArtikel finden Sie zum Beispiel
die Felder Lagerbestand und Mindestbestand. Wir
möchten zunächst alle Artikel ermitteln, bei denen
der Lagerbestand kleiner oder gleich dem Mindestbestand ist. Dazu fügen Sie dem Feld Lagerbestand
das Kriterium <=[Mindestbestand] hinzu (s. Bild 12).
Access [basics]
Sie müssen den Feldnamen des
Vergleichskriteriums unbedingt in
eckige Klammern setzen, da Access diesen sonst in ein Zeichenketten-Literal umwandelt (also
"Mindestbestand") – und das führt
zu einem Fehler. Genaugenommen
wäre es sogar sinnvoll, den Tabellen voranzustellen, also [tblArtikel].[Mindestbestand]. Auf diese
Weise schließen Sie bei Abfragen
auf Basis mehrerer Tabellen aus,
dass eventuell mehrfach vorkommende Felder nicht eindeutig referenziert werden. Ansonsten läuft
die Abfrage reibungslos, wie Bild 13
zeigt.
8/2010
www.access-basics.de
Bild 14: Tatsächlich zu bestellende Artikel
Allerdings enthält die Tabelle bereits ein Feld namens BestellteEinheiten und Auslaufartikel – der
Korrektheit halber sollten Sie also noch das Feld
BestellteEinheiten auf den Wert 0 und Auslaufartikel auf den Wert False prüfen, bevor Sie neue Artikel
bestellen.
Dies ist ein willkommener Anlass, den impliziten
AND-Operator des Abfrage-Editors zu erwähnen.
Zur obigen Abfrage fügen Sie nun noch die beiden
Felder BestellteEinheiten und Auslaufartikel hinzu.
Es sollen nur die Artikel tatsächlich bestellt werden,
die noch nicht bestellt wurden (BestellteEinheiten
= 0) und die nicht als Auslaufartikel gekennzeichnet
sind (Auflaufartikel = False). Zusammen mit dem
Vergleich von Lagerbestand und Mindestbestand
haben wir nun drei Kriterien, die im Abfrageentwurf
zwar in verschiedenen Spalten, aber alle in der gleichen Zeile landen (siehe Bild 14).
Dies bedeutet automatisch, dass diese Kriterien mit
dem AND-Operator verknüpft werden! Unser Kriterium heißt also eigentlich:
Bild 15: Suche
nach leeren
Feldern
Entfernen Sie zu Testzwecken beispielsweise einmal
den Inhalt des Feldes Einzelpreis eines Datensatzes der Tabelle tblArtikel. Ein Artikeldatensatz ohne
Preis führt früher oder später zu Problemen – wir
wollen solche Datensätze daher schnell identifizieren. Wie aber gestalten wir das Kriterium für diesen
Zweck? Folgendes funktioniert nicht:
• 0 (das Feld enthält nichts, also auch nicht den
Wert 0)
• leere Zeichenfolge, also "", liefert gar einen Fehler, weil ein Zeichenkettenliteral ein unzulässiger
Vergleichswert für ein Zahlenfeld ist
Was wir benötigen, ist ein ganz spezieller Ausdruck,
nämlich NULL. Diesen wandelt Access umgehend in
Ist Null um, wie Bild 15 zeigt. Dieser Ausdruck liefert
definitiv nur solche Datensätze, die keinen Wert für
das entsprechende Feld enthalten.
Lagerbestand<=Mindestbestand
AND BestellteEinheiten=0
AND Auslaufartikel=False
NULL-Werte ermitteln
Wenn wir mit Zahlenfeldern arbeiten, sind wir nicht
vor leeren Feldern gefeit (außer natürlich, Sie legen
im Tabellenentwurf fest, dass ein Feld nicht leer sein
darf).
Seite 12
Access [basics]
8/2010
www.access-basics.de
VBA-Programmierung
Teil II: Variablen in VBA
Eine der wichtigsten Techniken in Programmiersprachen besteht darin, dass Sie sich veränderliche Werte
zur Laufzeit merken können. Dazu dienen Variablen, in denen der Inhalt vorübergehend gespeichert wird.
VBA bietet die Möglichkeit zum Speichern von Werten wie beispielsweise von Berechnungsergebnissen
in sogenannten Variablen. Eine Variable ist im Prinzip
ein Aufbewahrungsort für einen Wert. Bevor Sie eine
Variable in einer VBA-Routine verwenden, sollten Sie
diese einen aussagekräftigen Namen geben. Im gleichen Zuge legen Sie die Art der darin gespeicherten
Daten fest. Es gibt beispielsweise Variablentypen
zum Speichern von Text, Zahlen oder Datumsangaben. Das Benennen und das Zuweisen des Datentyps
nennt sich Deklarieren und sieht beispielsweise so
aus:
Wenn Sie die drei Zeilen in eine Sub-Prozedur einfügen und diese ausführen ([basics] VBA-Prozedur
ausführen), erscheint im Direktfenster der Wert 100.
Dim intZahl As Integer
Debug.Print ingZahl
Diese Anweisung deklariert eine Variable namens
int­Zahl und weist ihr den Datentyp Integer zu. Der
Variablenname setzt sich aus einem Präfix (int) und
der Beschreibung des Inhalts (Zahl) zusammen.
Diese Zeile greift schlicht auf eine zuvor nicht gefüllte Variable zu. Solche Fehler vermeiden Sie auf einfache Weise. Schreiben Sie einfach die folgende Zeile
in den Modulkopf:
Durch den Einsatz des Präfix können Sie beim Programmieren gleich erkennen, welchen Datentyp eine
Variable besitzt und brauchen nicht erst die Deklarationszeile zu konsultieren.
Option Explicit
Hinter dem Präfix steht eine kurze Beschreibung des
Werts, den die Variable enthalten soll (hier schlicht
Zahl). Die Regeln zur Benennung von Variablen haben wir unter [basics] Konventionen zusammengefasst.
Variablendeklaration erzwingen
Wenn Sie Variablen auf die oben beschriebene Art
deklarieren, könnten einfache Tippfehler dazu führen, dass die Routine nicht mehr wie erwartet funktioniert. Wenn die dritte Zeile beispielsweise wie folgt
lautet, gibt die Prozedur gar keinen Wert mehr im
Direktfenste raus:
Bild 1: Ausgabe des in
einer Variablen
gespeicherten
Wertes im
Direktfenster
Wenn Sie eine Variable deklariert haben, können Sie
diese Werte zuweisen und über die Variable auf den
gespeicherten Wert zugreifen:
Dim intZahl As Integer
intZahl = 100
Debug.Print intZahl
Was Sie in diesem Artikel lernen
»» Welche Basisdatentypen stellt VBA bereit?
»» Wie speichere ich einen Wert in einer Variablen und rufen
ihn wieder ab?
»» Welchen Wertebereich haben die verschiedenen Datentypen?
»» Was ist der Unterschied zwischen Gleit- und Festkommazahlen?
Seite 13
Bild 2: Fehlermeldung beim Verwenden einer nicht deklarierten Variablen
Access [basics]
8/2010
www.access-basics.de
Der VBA-Editor prüft nun vor dem Ausführen der
Routine, ob alle verwendeten Variablen auch deklariert wurden.
Dies ist bei ingZahl nicht der Fall (deklariert wurde
ja nur intZahl). Der VBA-Editor liefert daraufhin eine
entsprechende Fehlermeldung und markiert die betroffene Zeile (s. Bild 2).
Diese Option gilt nicht anwendungsweit, sondern nur
in den Modulen, in denen diese enthalten ist. Wenn
die Option nicht in allen Modulendes VBA-Projekts
einer Access-Anwendung aktiv ist, sollten Sie dies
manuell nachholen.
Für neue Module können Sie dies automatisieren:
Dazu stellen Sie einfach eine Option des VBA-Editors
ein. Klicken Sie im VBA-Editor auf den Menüeintrag
Extras|Optionen und aktivieren Sie im nun erscheinenden Dialog die Option Variablendeklaration erforderlich (s. Bild 3). Fortan wird die Zeile Option
Explicit automatisch in alle neuen Module integriert.
Deklaration mehrere Variablen in einer
Zeile
Aus Gründen der Übersicht sollten Sie jede Variable
in einer eigenen Zeile deklarieren, also zum Beispiel
so:
Bild 3: Aktivieren des Kontrollkästchens Variablendeklaration erforderlich
Warum gibt es mehrere Datenzahlentypen? Nun:
Es gibt unterschiedlich große Zahlen mit und ohne
Nachkommastellen. VBA stellt für die verschiedenen
Fälle unterschiedliche Datentypen bereit.
Ganzzahlen
Bei den Zahlen gibt es zunächst die folgenden Ganzzahlentypen:
• Byte: Ganzzahlen von 0 bis 255 (ein Byte Speicherbedarf)
• Integer: Ganzzahlen von -32.768 bis 32.767 (zwei
Bytes Speicherbedarf)
Dim i As Integer
Dim strVorname As String
Dim datStart as Date
Sie können allerdings auch mehrere Deklarationen
in eine Zeile schreiben:
Dim i As Integer, j As Integer
Beachten Sie, dass Sie zu jeder Variablen den Datentyp angeben müssen – anderenfalls nimmt VBA automatisch den Variablentyp Variant an.
• Long: Ganzzahlen von -2.147.483.648 bis
2.147.483.647 (vier Bytes Speicherbedarf)
Achtung: Wenn Sie einer Ganzzahl-Variablen eine Zahl
mit Nachkommastellen zuweisen, werden diese kommentarlos abgeschnitten. Wenn Sie einer Zahl-Variablen einen Wert zuweisen, der außerhalt des angegebenen Wertebereichs liegt, löst dies einen Fehler aus. Das
wäre zum Beispiel hier der Fall – der Wertebereich für
den Datentyp Integer reicht nur bis 32.767:
Dies ist zwar nicht unbedingt fehlerhaft, aber Variablen dieses Datentyps nimmt den meisten Speicherplatz ein (mehr dazu weiter unten).
Dim intZuGross As Integer
intZuGross = 32768
Basisdatentypen
Gleitkommazahlen
Die Programmiersprache VBA kennt einige Basisdatentypen. Die meisten davon speichern Zahlen, aber
Sie können auch Zeichenketten in Variablen zwischenlagern.
Daneben gibt es zwei Gleitkommazahlentypen:
Seite 14
• Single: Gleitkommazahlen von -3,402823E38 bis
-1,401298E-45 für negative Werte und 1,401298E-
Access [basics]
8/2010
www.access-basics.de
45 bis 3,402823E38 für positive Werte (vier Bytes
Speicherbedarf)
• Double: Gleitkommazahlen von
-1,79769313486232E308 bis 4,94065645841247E324 für negative Werte und 4,94065645841247E324 bis 1,79769313486232E308 für positive
Werte (acht Bytes Speicherbedarf)
Festkommazahlen
Neben den Gleitkommazahlen gibt es auch einen
Festkommazahlentyp:
• Currency: Festkommazahlen im Bereich von -922.337.203.685.477,5808 bis
922.337.203.685.477,5807 (acht Bytes Speicherbedarf)
Der Unterschied zwischen Ganzzahlen auf der einen
und Gleitkomma- und Festkommazahlen auf der anderen Seite sollte klar sein, aber was unterscheiden
Gleitkomme- und Festkommazahlen voneinander?
Für den Einstieg reicht es zu wissen, dass Gleitkommazahlen grundsätzlich ungenau sind. Dies belegt
das folgende Beispiel:
Dim sng As Single
Dim i As Integer
For i = 1 To 30
sng = sng + 0.1
Debug.Print sng
Next i
ten. Die Bezeichnung Currency ist aber insofern irreführend, weil Sie natürlich beliebige Werte darin
speichern können – auch für Prozentzahlen bietet
sich dieser Datentyp an.
Datum
Im Prinzip ebenfalls ein Zahlentyp ist Date. Es enthält
immer ein Datum und eine Uhrzeit. Dabei speichert
dieser Datentyp Zahlenwerte, die dem Wertebereich
des Datentyps Double entsprechen. Wir kommen
später auf die genaue Speicherung von Werten in
Date-Variablen zu sprechen.
True/False
Auch der Datentyp Boolean speichert Zahlenwerte,
prinzipiell von -32.768 bis 32.766. Dabei entspricht -1
dem Wert True und 0 dem Wert False (auch alle übrigen Werte entsprechen False).
Zeichenketten
Variablen des Datentyps String verwenden Sie zum
Speichern beliebiger Texte. Die maximale Länge der
gespeicherten Zeichenkette hängt vom System ab
und durften auf unserem Testsystem beispielsweise
bis zu 326.500.333 Zeichen lang sein.
Mädchen für alles?
Im Direktfenster steht beispielsweise nach dem achten Durchlauf der Schleife der Wert 0,8000001. Wenn
Sie hier mit dem Festkommadatentyp Currency arbeiteten, erhielten Sie jeweils das richtige Ergebnis.
Wenn Sie keinen Datentyp angeben, verwendet VBA
automatisch den Datentyp Variant. Dieser kann alle
möglichen Werte aufnehmen, also zum Beispiel Zahlen oder Text. Auf die Besonderheiten gehen wir in
einem späteren Artikel ein.
Objektvariablen
Intern werden Nachkommastellen bei Gleitkommazahlen als Summe von Brüchen mit Zweierpotenzen dargestellt, 0,75 entspricht also beispielsweise
1/2 + 1/4. Eine Zahl wie 0,2 lässt sich so nie genau
abbilden. Festkommazahlen können wegen der maximalen Anzahl von vier Nachkommastellen intern
einfach mit dem Faktor 10.000 und somit als Ganzzahlen gespeichert werden. Der Wert 0,2 wird also
intern einfach als 0,2 x 10.000 = 2.000 gespeichert.
Ein Datentyp unterscheidet sich wesentlich von den
übrigen: Object nimmt nicht den eigentlichen Inhalt
auf, sondern nur einen Verweis auf den Ort im Speicher, an dem sich der Inhalt befindet.
Currency als Festkommazahl eignet sich prima für
Operationen im Finanzbereich, weil die durch Gleitkommazahlen verursachten Ungenauigkeiten sich
dort schnell unangenehm bemerkbar machen könn-
Speicherplatz von Variablen
Seite 15
Bei einem solchen Objekt kann es sich beispielsweise um die aktuelle Datenbank, ein Recordset oder
auch um ein Formular handeln. Wir gehen in einem
weiteren Artikel genauer auf dieses Thema ein.
VBA reserviert Speicherplatz für Variablen. Dies können Sie einfach nachvollziehen, indem Sie in einer
Access [basics]
8/2010
www.access-basics.de
Prozedur beispielsweise eine große Menge DoubleVariablen deklarieren (zum Beispiel 1.000):
Sie können auch gleich Berechnungsergebnisse zuweisen:
Public Sub Speicherplatz
Dim dbl1 As Double
Dim dbl2 As Double
Dim dbl3 As Double
...
Dim dbl1000 As Double
Stop
End Sub
lngBeispiel = 1 + 2
Oder Sie verwenden den Wert einer Variablen in der
Zuweisung zu einer weiteren Variablen:
lngBeispiel1 = lngBeispiel + 3
Wenn Sie nun den Task Manager von Windows öffnen
(Strg + Alt + Entf) und dort zur Registerseite Prozesse wechseln, finden Sie dort auch einen Eintrag namens MSACCESS.EXE mit einem Wert in der Spalte
Arbeitsspeicher.
Merken Sie sich den aktuellen Wert und starten Sie
die obige Prozedur. Diese hält in der Stop-Zeile an.
Der Speicherbedarf im Task Manager wächst nun
sichtlich, was teilweise auch durch die Bereitstellung von Speicherplatz für die Variablen geschieht.
Die hier verwendete Double-Variable reserviert beispielsweise acht Bytes.
Sie können einer Variablen auch ihren eigenen Wert
zuweisen, zum Beispiel um den Wert innerhalb einer
Schleife schrittweise bis zum Wert 10 um 1 zu vergrößern:
Dim intSumme As Integer
Dim i As Integer
For i = 1 To 10
intSumme = intSumme + 1
Next i
Zeichenketten geben Sie prinzipiell genauso ein, allerdings müssen Sie die Zeichenkette in Anführungszeichen einfassen:
strVorname = "Andre"
Bei Verwendung von String-Variablen reserviert VBA
zehn Bytes plus zwei Byte pro Zeichen. Auch das können Sie leicht im Taskmanager beobachten, indem
Sie folgende Zeilen in einer Prozedur aufrufen:
Dim str As String
str = Space(2^24)
Debug.Print Len(str)
Die Space-Funktion weist der String-Variablen 224
Leerzeichen zu, was sich in einem Zuwachs von rund
32 Megabytes Speicherbedarf der Access-Anwendung manifestiert.
Typische Fehler
Fehler bei der Zuweisung von Variablenwerten entstehen, wenn Sie Werte eingeben, die den Wertebereich überschreiben oder wenn Sie einer Variablen
einen anderweitig ungültigen Wert zuweisen – beispielsweise wenn eine Integer-Variable eine Zeichenkette aufnehmen soll:
Dim intZahl As Integer
intZahl = "Zahl"
Dies löst eine Fehlermeldung aus.
Variablen einsetzen
Zusammenfassung und Ausblick
Bei allen Datentypen außer Object weisen Sie den
Wert einfach mit dem Gleichzeitszeichen zu. Bei Zahlendatentypen sieht das wie folgt aus:
lngBeispiel = 1000
dblBeispiel = 12.3456
curBeispiel = 12.3456
Beachten Sie: Als Dezimaltrennzeichen wird das in
der Systemsteuerung angegebene Zeichen eingesetzt, in Deutschland üblicherweise der Punkt.
Seite 16
Sie haben nun die Basisdatentypen von Access kennengelernt. Einen wichtigen, nämlich Object, haben
wir weitgehend ignoriert – ihn behandeln wir später
in Zusammenhang mit den übrigen Datentypen.
Access [basics]
8/2010
www.access-basics.de
Formulare für die Datenbearbeitung
Teil V: m:n-Beziehungen in Listenfeldern darstellen
m:n-Beziehungen kann man auf verschiedene Arten abbilden. Die Variante mit Haupt- und Unterformular haben Sie bereits kennengelernt. In der Variante dieses Artikels kommen zwei Listenfelder zum Einsatz. Das erste enthält alle Datensätze, die mit dem im Formular angezeigten Datensatz verknüpft sind und
das zweite alle übrigen. Das Hinzufügen und Entfernen verknüpfter Datensätze erledigen wir elegant per
Schaltfläche oder per Doppelklick.
Das Beispiel zu diesem Artikel soll mal wieder unsere Projektzeiterfassung in den Mittelpunkt stellen.
Wenn mal ein Kunde anruft und eine Frage zu einem
speziellen Thema hat, soll er bei der Firma Schwuppdiwupp gleich mit einem kompetenten Kollegen verbunden werden. Dummerweise weiß aber nicht jeder,
welcher Mitarbeiter sich mit welchen Themen beschäftigt. Was liegt also näher, als in der Datenbank
Informationen über die Fähigkeiten (neudeutsch
Skills) der einzelnen Mitarbeiter zusammeln?
Im Endergebnis soll dies wie in Bild 1 aussehen. Ein
Doppelklick auf einen Eintrag im linken Listenfeld
soll diesen ins rechte Listenfeld verschieben und umgekehrt. Mit den Schaltflächen mit dem Größer- und
dem Kleiner-Zeichen lässt sich der jeweils markierte
Eintrag verschieben. Die doppelten Größer/KleinerZeichen verschieben gleich alle Einträge zum jeweils
anderen Listenfeld.
Bild 1: Hinzufügen und Entfernen der Skills eines Mitarbeiters
Datenmodell
Für dieses Beispiel benötigen Sie zwei neue Tabellen.
Die erste heißt tblSkills und speichert die einzelnen
Skills. Sie enthält ein Primärschlüsselfeld namens
SkillID und ein Textfeld namens
Skill zum Eintragen der Skills.
Bild 2: Mitarbeiter und ihre Skills im Datenmodell
Die Zuordnung eines Skills zu einem Mitarbeiter erfolgt über die
m:n-Verknüpfungstabelle tblMitarbeiterSkills. Die Tabelle enthält
das Primärschlüsselfeld MitarbeiterSkillID sowie die beiden Felder MitarbeiterID und SkillID. Die
beiden Felder sind mit den jeweiliWas Sie in diesem Artikel lernen
»» m:n-Beziehungen mit Listenfeldern
verwalten
»» Daten zu einer m:n-Beziehung hinzufügen
»» Daten einer m:n-Beziehung löschen
»» Listenfelder mit Inhalten füllen
Bild 3: Festlegen eines zusammengesetzten eindeutigen Schlüssels für die
Tabelle tblMitarbeiterSkills
Seite 17
Access [basics]
8/2010
www.access-basics.de
gen Primärschlüsselfeldern der Tabellen
tblMitarbeiter und tblSkills verknüpft
(s. Bild 2).
Damit die Benutzer der Datenbank keinem Mitarbeiter den gleichen Skill zweimal zuweisen können, legen Sie einen
zusammengesetzten eindeutigen Index
für die beiden Felder MitarbeiterID und
SkillID der Tabelle tblMitarbeiterSkills
fest (s. Bild 3).
Wenn Sie die Tabellen angelegt haben, Bild 4: Zuordnen von Skills zu Mitarbeitern per Verknüpfungstabelle
geben Sie wie in Bild 4 ein paar Datensätze in die Tabelle tblSkills und tblMitarbeiterSkills
ein – dies erleichtert die Entwicklung auf Basis des
Formulars mit den beiden Listenfeldern.
Basisformular
Das Formular bauen Sie wie in [basics] Gebundenes
Formular anlegen beschrieben auf. Dabei verwenden Sie die Tabelle tblMitarbeiter als Datenherkunft
und ziehen die wichtigsten Felder, hier beispielsweise die MitarbeiterID, AnredeID, Vorname und Nachname in den Detailbereich. Speichern Sie das Formular unter dem Namen frmMitarbeiterSkills.
Damit ist die m-Seite der Beziehung bereits erledigt,
aber das ist bei weitem nicht der aufwendigste Teil
der Aufgabe. Nun folgen noch die beiden Listenfelder, die Schaltflächen zum Hin- und Herschieben der
Skills zwischen den Listenfeldern und die notwendigen VBA-Routinen.
Fügen Sie also zunächst zwei Listenfelder zum Formular hinzu und nennen Sie diese lstZugeordnet und
lstNichtZugeordnet. Dazwischen legen Sie gleich
vier Schaltflächen an, die folgende Namen erhalten: cmdEinzelnHinzufuegen, cmdAlleHinzufuegen,
cmdAlleEntfernen und cmdEinzelnEntfernen. Als
Beschriftung verwenden Sie der Einfachheit halber
entsprechende Größer/Kleiner-Zeichen (<, <<, >>
und >). Wie Bild 5 zeigt, ist das Formular nun bereits
mit allen notwendigen Steuerelementen ausgestattet.
Listenfeld mit zugeordneten Skills
Nun weisen Sie dem Listenfeld der für den aktuellen
Mitarbeiter ausgewählten Skills eine entsprechende
Datensatzherkunft zu. Die Besonderheit dieser Abfrage ist, dass sie einen Wert des aktuell im Formular
Seite 18
Bild 5: Entwurfsansicht des Formulars mit allen Steuerelementen
angezeigten Datensatzes als Kriterium verwenden
soll. Das Listenfeld soll schließlich nur die Skills für
den aktuell im Formular sichtbaren Mitarbeiter anzeigen. Wie muss die Datenherkunft nun aussehen?
Sie soll erstens die Skills anzeigen, also brauchen
wir zumindest die Tabelle tblSkills. Um aber nur die
Skills des aktuellen Mitarbeiters zu ermitteln, brauchen wir auch noch die Tabelle tblMitarbeiterSkills,
welche die Skills über das Fremdschlüsselfeld MitarbeiterID mit dem jeweiligen Mitarbeiter verbindet.
Die Tabelle tblMitarbeiter selbst brauchen wir nicht:
Wir wollen im Listenfeld ja keine der eigentlichen
Mitarbeiterdaten anzeigen, sondern nur die über die
Tabelle tblMitarbeiterSkills verknüpften Einträge
der Tabelle tblSkills.
Erstellen Sie also eine neue Abfrage und fügen Sie die
beiden Tabellen tblSkills und tblMitarbeiterSkills
zur Abfrage hinzu (siehe [basics] Abfrage erstellen).
Ziehen Sie die beiden Felder SkillID und Skill der
Tabelle tblSkills und das Feld MitarbeiterID der
Access [basics]
8/2010
www.access-basics.de
Tabelle tblMitarbeiterSkills in das Entwurfsraster.
Speichern Sie die Abfrage dann zunächst unter dem
Namen qrySkillsEinesMitarbeiters. Dieser Name ist
prinzipiell noch nicht korrekt: Die Abfrage zeigt nun
nämlich alle Skills aller Mitarbeiter an. Damit nur die
Skills des aktuell im Formular frmMitarbeiterSkills
angezeigten Mitarbeiters anzeigt, müssen wir der
Spalte MitarbeiterID der Abfrage ein Kriterium hinzufügen, das genau dem Wert von MitarbeiterID im
Formular entspricht. Zeigt also das Formular den
Mitarbeiter mit der MitarbeiterID 4711 an, soll die
Abfrage für das Feld MitarbeiterID als Parameter
den Wert 4711 erhalten. Die Abfrage sähe im Entwurf
dann wie in Bild 6 aus.
Bild 6: Datenherkunft des linken Listenfeldes mit vorläufigem Kriterium
Nun können Sie diesen Wert natürlich nicht fest dort
eintragen. Die Abfrage muss diesen Wert in Abhängigkeit des Wertes im Formular dort einsetzen. Das
erledigen Sie durch einen Verweis auf das entsprechende Formularfeld. In diesem Fall lautet dieser so:
Forms!frmMitarbeiterSkills!MitarbeiterID
Die einzelnen Bestandteile sind schnell erläutert:
Forms verweist auf die Auflistung aller geöffneten
Formulare. Wenn Sie auf ein Element einer Auflistung selbstgebauter Objekte, also beispielsweise das
Formular frmMitarbeiterSkills, zugreifen möchten,
hängen Sie dieses Element durch ein Ausrufezeichen
getrennt an die Auflistung an. frmMitarbeiterSkills
enthält wiederum benutzerdefinierte Objekte, in diesem Fall das Steuerelement MitarbeiterID – auch
diese hängen Sie mit führendem Ausrufezeichen an
den bestehenden Ausdruck an (weitere Informationen siehe [basics] Formularelemente referenzieren).
Bild 7: Endgültige Datenherkunft des Listenfeldes lstAusgewaehlt
Beachten Sie, dass wir den Haken in der Zeile Anzeigen für die Spalte MitarbeiterID entfernt haben – das
Feld dient nur als Kriterium und soll nicht im Listenfeld angezeigt werden.
Auch das Feld SkillID soll dort eigentlich nicht erscheinen. Dennoch benötigen wir es: Wenn der Benutzer einen Eintrag eines Listenfeldes markiert und
diesen zum anderen Listenfeld verschieben möchte,
müssen wir diesen Datensatz schließlich eindeutig
identifizieren können. Und das gelingt am besten mit
dem Primärschlüsselfeld.
Listenfeld füllen
Damit das Listenfeld lstAusgewaehlt gefüllt wird,
stellen Sie die Eigenschaft Datensatzherkunft des
Seite 19
Bild 8: Das Listenfeld zeigt vorerst nur die Primärschlüsselwerte der verknüpften Skills an.
Listenfeldes auf den Namen der soeben erstellten
Abfrage ein, also auf qrySkillsEinesMitarbeiters.
Ein Wechsel in die Formularansicht zeigt, dass wir
das Listenfeld noch optimieren müssen (s. Bild 7).
Da wir bereits einige Daten in die Tabellen tblSkills
Access [basics]
8/2010
www.access-basics.de
und tblMitarbeiterSkills eingetragen haben, zeigt
es zwar bereits einige Daten an, aber leider nur das
erste Feld der Datensatzherkunft. Es soll aber das
zweite Feld anzeigen. Dies ändern wir durch Ändern
der beiden Eigenschaften Spaltenanzahl und Spaltenbreiten auf die Werte 2 und 0cm. Ersteres sorgt
dafür, dass theoretisch beide Felder im Listenfeld
erscheinen, und Zweiteres blendet das erste der beiden Felder durch Einstellen der Breite auf 0cm gleich
wieder aus. Durch das Auslassen einer Breite für das
zweite, letzte Feld nimmt dieses den kompletten verbleibenden Platz ein. Das Ergebnis sieht nun schon
viel besser aus, wie Bild 9 zeigt.
Listenfeld mit den übrigen Skills
Bild 9: Listenfeld mit korrekter Anzeige der Skill-Einträge
Die Skills eines Mitarbeiters zu ermitteln war einfach: Wir brauchten einfach nur die aktuelle MitarbeiterID als Kriterium für das entsprechende Feld
der Datensatzherkunft des Listenfeldes einzutragen.
Das Auffinden der Einträge der Tabelle tblSkills, die
dem aktuell angezeigten Mitarbeiter nicht zugeordnet sind, ist etwas schwieriger. Wir beginnen mit einer Abfrage namens qrySkillsNichtZugeordnet, die
schlicht die Tabelle tblSkills enthält und beide Felder dieser Tabelle anzeigt. Bild 10 zeigt die Entwurfsansicht dieser Abfrage.
Nun liefert diese alle Skills. Die Skills, die dem aktuellen Mitarbeiter zugeordnet sind, soll sie jedoch
nicht anzeigen. Wie aber schließen wir genau diese
aus? Dazu verwenden wir eine Kriterium, das genau
die SkillIDs auflistet, die dem Mitarbeiter bereits zugeteilt wurden. Dieses Kriterium verwendet das INSchlüsselwort mit einer Abfrage als Parameter, die
genau die gewünschten Daten liefert (grundlegende
Informationen hierzu finden Sie in Abfragen für die
Datenauswahl – Teil V: Filtern nach Zahlen). Diese
Abfrage sieht als SQL-Ausdruck wie folgt aus:
Bild 10: Diese Abfrage gibt zunächst alle Datensätze der
Tabelle tblSkills zurück.
SELECT SkillID FROM qrySkillsEinesMitarbeiters
Die Abfrage liefert genau die gleichen Datensätze wie
die Abfrage, die als Datensatzherkunft des Listenfeldes lstAusgewaehlt dient – allerdings beschränkt
sie sich auf das Primärschlüsselfeld SkillID. Das ist
auch notwendig, denn die IN-Klausel, welche das Ergebnis der Abfrage weiterverwenden soll, kann nur
ein einziges Feld verarbeiten.
Durch die Verwendung des Ausdrucks NOT IN (...) als
Kriterium liefert die Abfrage qrySkillsNichtZugeordnet aus Bild 11 alle Datensätze der Tabelle tblSkills,
Seite 20
Bild 11: Diese Abfrage liefert alle Skills, die dem aktuellen Mitarbeiter nicht zugeordnet wurden.
deren SkillID nicht durch die in Klammern angegebene Abfrage geliefert werden.
Stellen Sie nun die Datensatzherkunft des Listenfeldes lstNichtZugeordnet auf den Namen der neuen
Abfrage qrySkillsNichtZugeordnet ein. Passen Sie
außerdem wie schon beim ersten Listenfeld die Ei-
Access [basics]
8/2010
www.access-basics.de
genschaften Spaltenanzahl und Spaltenbreiten auf
die Werte 2 und 0cm ein.
Das Ergebnis liefert ein erneuter Wechseln in die
Formularansicht (siehe Bild 12). Prima: Die Listenfelder zeigen bereits die richtigen Skills für den Mitarbeiter an und auch die nicht zugeordneten Skills
stimmen.
Listenfeldinhalte dynamisch anpassen
Der Wechsel zum nächsten Mitarbeiterdatensatz
bringt jedoch eine gewisse Enttäuschung mit sich:
Die Listenfelder zeigen nämlich immer noch die gleichen Daten an.
Das ist aber auch kein Wunder: Immerhin sind die
Listenfelder in keiner Weise an den aktuellen Mitarbeiter-Datensatz gebunden. Allein die Datensatzherkunft des linken Listenfelds wird einmalig beim Öffnen des Formulars nach der aktuellen MitarbeiterID
gefiltert und das rechte Listenfeld wird ebenfalls entsprechend gefüllt.
Im Beitrag Steuerelemente – Teil II: Das Listenfeld
haben Sie bereits einiges über Listenfelder erfahren.
Diese lassen sich zum Beispiel mit der RequeryMethode aktualisieren. Das brauchen wir! Und wann
wollen wir die Listenfelder aktualisieren? Immer
beim Wechseln des Mitarbeiter-Datensatzes des
Formulars.
Unter dem Titel Formulare mit VBA ­programmieren
– Teil I: Formularereignisse nutzen haben wir Ihnen
bereits gezeigt, wie Sie grundsätzlich mit dem Ereignissen eines Formulars umgehen und eigenen VBACode durch bestimmte Ereignisse ausführen lassen
können. In diesem Fall lernen Sie ein neues Ereignis
kennen, nämlich Beim Anzeigen. Es wird jedesmal
ausgelöst, wenn das Formular den angezeigten Datensatz wechselt. Dies geschieht einmal beim Öffnen
des Formulars und dann bei jedem Datensatzwechsel.
Fügen Sie gemäß der Anleitung in [basics] Ereignisprozedur hinzufügen eine Ereignisprozedur für das
Ereignis Beim Anzeigen des Formulars hinzu. Dieses
ergänzen Sie wie folgt:
Private Sub Form_Current()
Me!lstNichtZugeordnet.Requery
Me!lstZugeordnet.Requery
End Sub
Bild 12: Das Listenfeld zeigt für den ersten Datensatz
bereits die gewünschten Daten an.
Die Prozedur aktualisiert bei jedem Datensatzwechseln die Datensatzherkunft der beiden Listenfelder
– probieren Sie es aus!
Skills hinzufügen
Nun benötigen wir noch die Funktionen zum Hinzufügen und Entfernen der Skills eines Mitarbeiters.
Beginnen wir mit dem Hinzufügen. Dieses soll durch
entweder durch einen Klick auf die Schaltfläche mit
dem Kleiner-Zeichen oder durch einen Doppelklick
auf das rechte Listenfeld geschehen.
Die Ereignisprozedur für die Schaltfläche cmdEinzelnHinzufuegen soll durch einen Mausklick
ausgelöst werden. Wechseln Sie also in die Entwurfsansicht des Formulars, markieren Sie also
die Schaltfläche und wählen Sie für die Eigenschaft
Beim Klicken den Wert [Ereignisprozedur] aus. Die
nach einem Klick auf die Schaltfläche mit den drei
Punkten (...) erscheinende VBA-Prozedur erweitern
Sie wie folgt:
Private Sub cmdEinzelnHinzufuegen_Click()
Dim lngMitarbeiterID As Long
Dim lngSkillID As Long
lngMitarbeiterID = Me!MitarbeiterID
lngSkillID = Me!lstNichtZugeordnet
CurrentDb.Execute "INSERT INTO µ
tblMitarbeiterSkills(MitarbeiterID, µ
SkillID) VALUES(" & lngMitarbeiterID µ
& ", " & lngSkillID & ")", dbFailOnError
Me!lstZugeordnet.Requery
Me!lstNichtZugeordnet.Requery
End Sub
Uups! Das ist eine ganze Menge Code – zumindest,
wenn Sie mit Access [basics] in die Access-Pro-
Seite 21
Access [basics]
8/2010
www.access-basics.de
grammierung einsteigen. Aber wir schauen uns alles
in Ruhe an.
Eigentlich erledigt diese Prozedur nur die folgenden
Schritte: Sie deklariert zunächst zwei Variablen. Diese bekommen später den Primärschlüsselwert des
aktuell ausgewählten Mitarbeiters und des im rechten Listenfeldes markierten Skills zugewiesen:
Dim lngMitarbeiterID As Long
Dim lngSkillID As Long
Die MitarbeiterID erhalten wir über das gleichnamige Steuerelement des Formulars. Es wird in der
Variablen lngMitarbeiterID gespeichert (mehr zu Variablen erfahren Sie in VBA-Programmierung – Teil
II: Variablen in VBA):
Skill per Doppelklick hinzufügen
Die gleiche Aktion, die wir mit einem Klick auf die
Schaltfläche cmdEinzelnHinzufuegen erreichen, soll
auch durch einen Doppelklick auf einen der Einträge
des rechten Listenfeldes ausgeführt werden.
Also legen Sie eine neue Ereignisprozedur für das
Ereignis Beim Doppeklicken des Listenfeld-Steuerelements an. Prinzipiell können Sie hier genau
die gleichen Anweisungen unterbringen wie in der
Ereignisprozedur cmdEinzelnHinzufuegen_Click.
Das würde allerdings bedeuten, dass wir zweimal
genau die gleiche Abfolge von VBA-Anweisungen in
verschiedenen Routinen haben! Das ist aus verschiedenen Gründen nicht optimal, aber wir wollen diese
Lösung vorerst akzeptieren. Später gehen wir darauf
ein, wie Sie diese Routinen optimieren können.
lngMitarbeiterID = Me!MitarbeiterID
Die neue Ereignisprozedur sieht nun so aus:
Auf ähnliche Weise erhalten wir die SkillID. Diese
entspricht dem aktuell im Listenfeld lstNichtZugeordnet ausgewählten Eintrag:
lngSkillID = Me!lstNichtZugeordnet
Die folgende Anweisung erledigt nun die Hauptarbeit. Sie ruft eine SQL-Anfügeabfrage auf, die der
Tabelle tblMitarbeiterSkills einen neuen Datensatz
hinzufügt. Dabei füllt die Abfrage die beiden Felder
MitarbeiterID und SkillID mit den in den Variablen
lngMitarbeiterID und SkillID zwischengespeicherten
Werten:
CurrentDb.Execute "INSERT INTO µ
tblMitarbeiterSkills(MitarbeiterID, µ
SkillID) VALUES(" & lngMitarbeiterID µ
& ", " & lngSkillID & ")", dbFailOnError
Schließlich sollen nach dem Hinzufügen eines neuen
Skills für den aktuellen Mitarbeiter noch die Datensatzherkünfte der beiden Listenfelder lstZugeordnet und lstNichtZugeordnet aktualisiert werden. Die
dazu nötigen Anweisungen kennen Sie bereits:
Me!lstZugeordnet.Requery
Me!lstNichtZugeordnet.Requery
Die Anweisung zum Durchführen der Anfügeabfrage
wollen wir hier nicht bis ins letzte Detail besprechen,
da wir in folgenden Artikeln noch auf dieses Thema
eingehen – Gleiches gilt für die noch folgenden SQLAbfragen.
Seite 22
Private Sub lstNichtZugeordnet_DblClick(Cancel µ
As Integer)
Dim lngMitarbeiterID As Long
Dim lngSkillID As Long
lngMitarbeiterID = Me!MitarbeiterID
lngSkillID = Me!lstNichtZugeordnet
CurrentDb.Execute "INSERT INTO µ
tblMitarbeiterSkills(MitarbeiterID, µ
SkillID) VALUES(" & lngMitarbeiterID µ
& ", " & lngSkillID & ")", dbFailOnError
Me!lstZugeordnet.Requery
Me!lstNichtZugeordnet.Requery
End Sub
Skills entfernen
Damit Sie die beim Ausprobieren hinzugefügten
Skills auch wieder vom Mitarbeiter entfernen können, kümmern wir uns nun um die Ereignisprozedur
Beim Klicken der Schaltfläche cmdEinzelnEntfernen. Die Prozedur sieht fast genauso wie die vorherigen beiden aus:
Private Sub cmdEinzelnEntfernen_Click()
Dim lngMitarbeiterID As Long
Dim lngSkillID As Long
lngMitarbeiterID = Me!MitarbeiterID
lngSkillID = Me!lstZugeordnet
CurrentDb.Execute "DELETE FROM µ
tblMitarbeiterSkills WHERE MitarbeiterID = µ
" & lngMitarbeiterID & " AND SkillID = " µ
& lngSkillID, dbFailOnError
Access [basics]
8/2010
www.access-basics.de
gen Index für die Kombination dieser beiden Felder angelegt haben.
Me!lstZugeordnet.Requery
Me!lstNichtZugeordnet.Requery
End Sub
Es gibt jedoch zwei wesentliche Unterschiede:
• Der Wert für die Variable lngSkillID wird aus dem
Listenfeld lstZugeordnet gewonnen.
• Es wird keine Anfügeabfrage ausgeführt, sondern
eine Löschabfrage. Diese entfernt genau den
Datensatz aus der Tabelle tblMitarbeiterSkills,
dessen Felder MitarbeiterID und SkillID die in
den Variablen lngMitarbeiterID und lngSkillID
enthaltenen Werte aufweisen.
Entfernen eines Skills per Doppelklick
Auch hier wollen wir das Verschieben eines Eintrags
von Listenfeld zu Listenfeld durch einen Doppelklick
erlauben. Dazu legen wir genau die gleich Zeilen wie
aus der obigen Prozedur in einer weiteren Prozedur
an, die durch das Ereignis Beim Doppelklicken des
Listenfeldes lstZugeordnet ausgelöst wird:
Private Sub cmdEinzelnEntfernen_Click()
Dim lngMitarbeiterID As Long
Dim lngSkillID As Long
lngMitarbeiterID = Me!MitarbeiterID
lngSkillID = Me!lstZugeordnet
CurrentDb.Execute "DELETE FROM µ
tblMitarbeiterSkills WHERE MitarbeiterID µ
= " & lngMitarbeiterID & " AND µ
SkillID = " & lngSkillID, dbFailOnError
Me!lstZugeordnet.Requery
Me!lstNichtZugeordnet.Requery
End Sub
Fehler vermeiden
Damit hätten wir die Grundfunktion fast fertig. Wenn
da nicht noch ein paar kleine Fehler auftreten würden:
• Wenn Sie direkt auf die Schaltfläche mit der Beschriftung < klicken, ohne zuvor einen Eintrag
des rechten Listenfeldes zu markieren, löst dies
einen Fehler 94, Unzulässige Verwendung von
Null aus.
• Wenn man einen Eintrag des rechten Listenfelds
markiert und dann zweimal auf die Schaltfläche
mit der Beschriftung < klickt, folgt ein Fehler mit
der Nummer 3022. Dieser wird durch den Versuch ausgelöst, eine bereits vorhandene Kombination aus MitarbeiterID und SkillID erneut in
der Tabelle tblMitarbeiterSkills zu speichern.
Dies funktioniert nicht, weil wir einen eindeuti-
Seite 23
Der erste Fehler resultiert daraus, dass das Listenfeld erst einen Wert enthält, wenn der Benutzer einen Eintrag markiert hat. Dies ist zu Beginn nicht der
Fall.
Der zweite Fehler ist ein Bug: Es war ein Eintrag im
Listenfeld markiert, der aber aus der Datensatzherkunft entfernt wurde. Durch den Aufruf der RequeryMethode wird zwar der betroffene Listenfeldeintrag
entfernt, der Primärschlüsselwert des zuletzt markierten Eintrags bleibt jedoch als aktueller Wert des
Listenfeldes gespeichert.
Es gibt diverse Möglichkeiten, diese beiden Fehler zu
umgehen. Damit wir diesen Artikel bis zur Fortsetzung beschließen können und Sie dennoch eine funktionierende Lösung haben, wählen wir ausnahmsweise einen unsauberen Weg: Wir fügen einfach zu
Beginn der betroffenen Prozedur die Zeile On Error
Resume Next ein. Das sieht dann so aus:
Private Sub cmdEinzelnHinzufuegen_Click()
Dim lngMitarbeiterID As Long
Dim lngSkillID As Long
On Error Resume Next
lngMitarbeiterID = Me!MitarbeiterID
...
End Sub
Zusammenfassung und Ausblick
Diese Lösung ist für den Kenntnisstand, den Sie
durch den bisherigen Inhalt von Access [basics] erhalten haben, bereits recht anspruchsvoll. Allerdings
lohnt es sich, hier nicht aufzugeben: Wenn Sie das
Verwalten von m:n-Beziehungen mit Listenfeldern
einmal verstanden haben, können Sie es mit nur wenigen Änderungen immer wieder einsetzen.
In der Fortsetzung zu diesem Artikel werden wir uns
um das Hinzufügen und Entfernen aller Skills gleichzeitig kümmern und einige Feinarbeiten am Code
vornehmen.