Access-FAQ: Rund um Access

Zusammenfassung

Lernen Sie die Lösung zu den häufigsten VBA-Problemen kennen.

Techniken

VBA, DAO, ADO, SQL

Voraussetzungen

Access 97 und höher

Beispieldateien

FAQ12_A97.mdb (Access 97)FAQ12_A00.mdb (Access 2000 und höher)

Karl Donaubauer, Wien

In der Access-FAQ von Karl Donaubauer (www.donkarl.com) finden Sie die meistgestellten Fragen und Anworten zum Thema Microsoft Access. In dieser Beitragsreihe stellt Karl Donaubauer die wichtigsten Einträge im Detail vor und zeigt Ihnen entsprechende Lösungen anhand praxisnaher Beispiele. Im zwölften Teil werden Lösungen für die häufigsten Probleme in VBA vorgestellt.

Jahrelang war eine der häufigsten Fragen zum Thema Access-Programmierung, ob nun DAO oder ADO als Datenzugriffstechnik zu lernen und zu verwenden sei. Heute kommt die Frage etwas seltener, auch, weil das Match inzwischen entschieden ist. Microsoft hat von cirka 1999 bis 2001/2002, das heißt, ab der Veröffentlichung von Access 2000 bis in die Zeit von Access XP hinein, versucht, das althergebrachte DAO loszuwerden und durch ADO und ADOX zu ersetzen. Viele Buchautoren sind dem MS-Marketingwirbel erlegen und haben dieses Anliegen freudig weiterpropagiert. Allein, die überwältigende Mehrheit der Access-Programmierer ist MS hier nicht gefolgt, sondern bei DAO geblieben. ADO konnte sich nur in Nischen durchsetzen, etwa bei ADPs und beim Zugriff auf JET-Dateien im klassischen ASP.

Bei der reinen Entwicklungsarbeit mit Access, JET und MDBs hatte ADO keine Chance, weil DAO und JET als Duo gewachsen, besser integriert und meist performanter sind und waren. Da half es auch nichts, dass der Zugriff auf manche Erweiterungen in JET 4.0 nur für ADO ermöglicht wurde, während DAO von MS bewusst vernachlässigt wurde. Bei der täglichen Brotarbeit war und ist DAO einfach beliebter. Microsoft hat diese Realität spät, aber doch akzeptiert. Wenn man in Access 2000 oder XP eine neue Datenbank anlegt, ist standardmäßig nur der Verweis auf ADO vorhanden. Das führte zu millionenfachen Verweisproblemen und ebenso vielen Fragen in Access-Foren. Bei einer neuen Datenbank in Access 2003 hingegen ist nicht nur der DAO-Verweis wieder vorhanden, sondern er steht in der Reihenfolge über dem ADO-Verweis. In der nächsten Version von Access gibt es sogar zum ersten Mal nach vielen Jahren wieder Anpassungen und Neuerungen in DAO.

Das ist nicht nur die Konsequenz der Beharrlichkeit der Access-Gemeinde. Das MS-Marketing konzentriert sich seit Jahren ausschließlich auf .NET und damit ADO.NET. Der Name ist mehr oder weniger eine Finte, denn diese Zugriffstechnologie hat nicht sehr viel mit dem klassischen ADO zu tun. ADO ist also auch aus Marketingsicht bereits wieder veraltet. Fazit der jahrelangen Schlacht:

  • DAO ist ein Evergreen und Königin für Access/JET/MDBs.
  • ADO regiert bei ADPs, also Access-Projekten mit dem MS SQL Server als Backend.
  • ADOX , die ADO-Erweiterung für JET, war nur eine Episode.
  • ADO.NET könnte die Zukunft in allen MS-Anwendungen sein. MS hat es aber noch nicht geschafft, .NET ernsthaft in die Office-Welt und -Programmierung zu integrieren. Sie sollten auch als vielleicht reiner Access-Entwickler diese interessante Technologie im Auge behalten. Sie ist aber noch nicht mit Access oder VBA nutzbar.
  • Eines der ersten Probleme jedes Access-VBA-Programmierers ist ebenso ein beliebtes Streitthema unter erfahrenen Programmierern: Wann ist bei Bezügen der Punkt, wann das Ausrufezeichen als Trennzeichen voranzusetzen oder ist die Verwendung der String-Schreibweise generell vorzuziehen

    Eine einfache Grundregel ist: vor Objekten ein Ausrufezeichen, vor Auflistungen und Eigenschaften ein Punkt. Eine andere bekannte Merkregel lautet: Wenn nach dem Trennzeichen ein Element folgt, das fix in Access eingebaut ist, dann gehört der Punkt dorthin. Wenn das Element benutzerdefiniert ist, dann verwendet man das Ausrufezeichen. Ein Beispiel (in einer Zeile):

    Application.Forms!frmKunden.Controls!Nachname.Visible

    Die Forms-Auflistung ist von Access vorgegeben, deshalb wird hier der Punkt vorangestellt. Das Formular frmKunden wurde vom Entwickler erstellt, deshalb kommt hier das Ausrufezeichen zum Zuge. Die Controls-Auflistung ist wieder ein eingebautes Element von Access. Nachname ist ein benutzerdefinierter Steuerelementname. Die Eigenschaft Visible stammt wiederum von Access.

    Diese Regel gilt auch für die meistangewandte Kurzform:

    Forms!frmKunden!Nachname.Visible

    So einfach diese Grundregeln sind, so diffizil wird es im Detail, weil VBA sehr variabel ist und oft mehrere Varianten zulässt. Eine Quelle der Unsicherheit und der häufigste Streitpunkt ist dabei Punkt oder Ausrufezeichen nach dem Schlüsselwort Me. Mit Me bezieht man sich auf das Objekt, das heißt die Instanz der Klasse, in der der aktuelle Code ausgeführt wird. In Access ist das meist ein Formular oder ein Bericht. Nach den oben angeführten Regeln müsste man sich auf Steuerelemente mit Ausrufezeichen beziehen, also: Me!MeinSteuerelement.

    Steuerelemente sind in VB und VBA aber nicht nur Objekte, sondern auch Eigenschaften von Formularen. Deshalb funktioniert ebenso: Me.MeinSteuerelement.

    Manche Programmierer bevorzugen diese Schreibweise, weil sie damit im VBA-Editor Intellisense nutzen können, ihnen also automatisch die Liste der im jeweiligen Kontext verfügbaren Objekte und Eigenschaften angezeigt wird (siehe Bild 1).

    Bild 1: Punkt bringt Intellisense im Kontext.

    Bei Verwendung des Ausrufezeichens tritt Intellisense nicht in Aktion. Sie können zwar mit der Tastenkombination STRG + Leertaste die Auswahlliste erzwingen, diese zeigt dann aber nicht die in diesem Kontext verfügbaren Einträge, sondern alle für den VBA-Code in der aktuellen Anwendung verfügbaren Schlüsselworte und Objekte an (siehe Bild 2).

    Bild 2: Auswahlliste ohne Kontext

    Die Punkt-Schreibweise hat also einen unbestreitbaren Vorteil. Der Nachteil ist jedoch, dass manchmal unvorhersehbare und von Microsoft nicht dokumentierte Probleme damit auftauchen. So kommt es vor, dass nach einer Konvertierung in eine höhere Access-Version oder auch einfach nach einer Neukompilierung die Bezüge nicht mehr funktionieren. Oft passiert diese Art Korruption, wenn für die Steuerelemente dieselben Namen wie für die Felder der Datenquelle verwendet werden. Das scheint aber nur eine der möglichen Mitverursacher zu sein. Jedenfalls treten derartige Probleme mit Ausrufezeichen nicht auf. Deshalb ist es sicherer, auch hier das Ausrufezeichen zu verwenden, oder die ebenfalls zuverlässige String-Schreibweise mit Klammern:

    Me("MeinSteuerelement")

    oder

    Me.Controls("MeinSteuerelement")

    Für viele Aufgaben in der VBA-Programmieung ist es von Vorteil oder unbedingt notwendig, statt fixer Objektnamen Variablen verwenden zu können. Das betrifft sowohl Steuerelemente in Formularen und Berichten als auch Felder in Recordsets von DAO oder ADO. Die Lösung für diese Anforderung ist die Schreibweise mit runden Klammern.

    Ein Steuerelement können Sie zum Beispiel so ansprechen:

    Forms("Formularname")(StringVariable)

    Ebenso funktioniert es mit einem Feld in einem Recordset:

    rs(StringVariable)

    Die häufigste Verwendung findet die eben behandelte Klammer-Schreibweise in Schleifen zum Durchlaufen von Controls- oder Fields-Auflistungen. Meistens geht es darum, per Code mehrere oder alle Steuerelemente eines Formulares oder Berichtes zu durchlaufen, um eine bestimmte Eigenschaft für diese Elemente in einem Rutsch zu prüfen oder zu ändern.

    Eine beliebte Lösungsvariante dafür ist, gleichartige Steuerelemente mit denselben Namen und einer fortlaufenden Nummer zu benennen: Liste1, Liste2, Liste3… oder Combo1, Combo2…

    Mit dieser Voraussetzung ist es dann einfach, zum Beispiel die Eigenschaft Sichtbar der Steuerelemente zu ändern:

    Dim i As Integer
    For i = 1 To 5
      Me("Liste" & i).Visible = False
    Next

    Eine andere Variante, um bestimmte Steuerelemente zu kennzeichnen, ist die Verwendung ihrer Eigenschaft Marke (Tag).

    Die Eigenschaft ist genau für diesen Zweck vorhanden, also eine kennzeichnende Information oder irgendeinen Memo-Text für Objekte zu hinterlegen, der ansonsten keine Auswirkungen auf die Funktionalität oder die Eigenschaften des Objektes hat.

    Um sie für Steuerelemente zu nützen, können Sie sie per Code durch die Controls-Auflistung von Formularen und Berichten schleifen und Tag prüfen:

    Dim ctl As Control
    For Each ctl In Me.Controls
      If ctl.Tag = "Suchtext" Then ctl.Visible = False
    Next ctl

    Wenn Sie ein Meldungsfenster öffnen, so wird der Code angehalten, bis die Box wieder geschlossen wird. Damit können Sie im Code nach dem Aufruf des Meldungsfensters sofort auf die im Meldungsfenster gewählte Schaltfläche reagieren. Bild 3 zeigt eine solche Anordnung.

    Bild 3: Meldungsfenster als Dialogformular

    Im Formular frmDialogAufruf wird per Schaltfläche ein Meldungsfenster aufgerufen. Im Meldungsfenster klickt der Benutzer auf Ja oder Nein. Danach erst läuft der Code im aufrufenden Formular weiter und zeigt dabei das Ergebnis der MsgBox-Funktion an. Der Code hinter der Schaltfläche zum Aufruf des Meldungsfensters sieht dabei so aus:

    Dim intAntwort As Integer
    intAntwort = MsgBox("Bitte klicken " _    "Sie auf Ja oder Nein.", vbYesNo Or _    vbQuestion, "Msgbox als Dialog")
    Select Case intAntwort
        Case vbYes
            Me!txtErgebnis = "Ja"
        Case vbNo
            Me!txtErgebnis = "Nein"
    End Select

    Der Grund für das Anhalten des Codes ist, dass das Meldungsfenster modal ist. Es muss zuerst geschlossen werden, bevor Access die aufrufende Prozedur fortführt und wieder Anwenderaktionen in anderen Objekten zulässt.

    Die Möglichkeiten eines Meldungsfensters sind auf wenige, fix vorgegebene Schaltflächen begrenzt. Sie können die Dialog-Funktionalität aber auch mit einem selbst definierten modalen Formular programmieren (siehe Bild 4)

    Bild 4: Modales Formular als Dialog

    Das Dialogformular ist dabei im Vergleich zum Meldungsfenster um weitere Schaltflächen ergänzt. Es könnte aber auch Eingabefelder und so weiter enthalten. Der Code hinter den Schaltflächen im Dialogformular besteht nur aus einer schlanken Anweisung:

    Me.Visible = False

    Das Dialogformular wird also unsichtbar gemacht. Damit hat das aufrufende Formular wieder den Fokus, sein Code läuft weiter und kann auf die Benutzereingaben im Dialogformular zugreifen. Der entsprechende aufrufende und reagierende Code lautet:

    DoCmd.OpenForm "frmDialog", , , , , _    acDialog
    txtErgebnis = _    Forms!frmDialog.ActiveControl.Caption
    DoCmd.Close acForm, "frmDialog"

    Das Dialogformular wird mit dem Wert acDialog im Parameter Fenstermodus geöffnet. Damit hält der Code an, bis das Dialogformular entweder geschlossen oder unsichtbar gemacht wird. Danach läuft der Code weiter und es wird ein Textfeld im aufrufenden Formular mit der Beschriftung der im Dialogformular gewählten Schaltfläche versorgt. Am Ende wird das Dialogformular geschlossen, damit es nicht dauerhaft unsichtbar geöffnet bleibt.

    Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

    den kompletten Artikel im PDF-Format mit Beispieldatenbank

    diesen und alle anderen Artikel mit dem Jahresabo

    Schreibe einen Kommentar

    Access-FAQ: Rund um Access

    Roland Grothe, Hanau; André Minhorst, Duisburg

    Zusammenfassung

    Erstellen Sie ein Add-In zum Messen und Vergleichen der Performance von Funktionen.

    Techniken

    Domänenfunktionen

    Voraussetzungen

    Access 97 und höher

    Beispieldateien

    Domaenenfunktionen97.mdb (Access 97)Domaenenfunktionen00.mdb (Access 2000 und höher)

    Dieser Beitrag stellt Ihnen eine Gruppe von Funktionen vor, die einen recht einfachen Zugriff auf Daten in beliebigen Tabellen oder Abfragen einer Access-Datenbank ermöglichen. Mit diesen so genannten Domänenfunktionen ist es möglich, Tabellendaten in Form von Funktionsergebnissen zum Beispiel als Feldinhalte oder als Kriterien in Abfragen zur Verfügung zu stellen. Anhand einiger Praxisbeispiele erfahren Sie, in welchen Fällen der Einsatz von Domänenfunktionen sinnvoll ist und wann es besser ist, auf andere Alternativen zur Datenermittlung zurückzugreifen.

    Domänenfunktionen lassen sich am einfachsten als „in eine Funktion gepackte SQL-Abfragen“ definieren. Mit Domänenfunktionen lassen sich fast alle Abfragen ersetzen, die allerdings eine Bedingung zwingend erfüllen müssen: Sie dürfen lediglich einen einzigen Wert zurückliefern. Die Bezeichnung dieses Funktionstyps erklärt sich aus dem Begriff Domäne (engl.: Domain), eine in Datenbank-Kreisen übliche Bezeichnung für eine Datensatzgruppe. Die insgesamt zwölf von Access zur Verfügung gestellten Domänenfunktionen ermöglichen den schnellen und unkomplizierten Zugriff auf Informationen aus einer Tabelle oder einer gespeicherten Abfrage.

    Sie lassen sich sehr flexibel einsetzen und stellen oft die einzige Möglichkeit dar, das Ergebnis einer Funktionsabfrage in einem Formular- oder Berichtsfeld darzustellen, ohne aufwändigen VBA-Code schreiben zu müssen. Sie sind auch immer dann hilfreich, wenn ein solches Ergebnis zu weiteren Berechnungen benötigt wird, da Sie direkt in dem jeweiligen Ausdruck anstelle eines konkreten Wertes verwendet werden.

    Tab. 1 zeigt alle Domänenfunktionen in Deutsch und Englisch inklusive Beschreibung. Sie können in der deutschen Version von Access fast überall sowohl die deutschen als auch die englischen Funktionsbezeichnungen verwenden. Access wandelt diese automatisch in die deutsche Bezeichnung um. Dies gilt allerdings nicht für VBA-Code. Dort verwendete Funktionen müssen mit der englischen Bezeichnung eingegeben werden. In VBA werden die Funktionsparameter statt mit dem Semikolon mit einem Komma voneinander getrennt.

    Funktion (engl. Bez.)

    Beschreibung

    DomAnzahl (DCount)

    Anzahl der Datensätze aus der Tabellen- bzw. Abfrage-Domäne, bei denen der Inhalt des in Ausdruck definierten Feldes bzw. das Ergebnis dieses Ausdrucks nicht Null ist. Berücksichtigt werden nur Datensätze, die dem in Kriterium festgelegten Kriterium entsprechen (die Syntaxbeschreibung gilt für alle Domänenfunktionen).

    DomSumme (DSum)

    Summe der Feldinhalte

    DomErsterWert (DFirst)

    Feldinhalt des ersten Datensatzes

    DomLetzterWert (DLast)

    Feldinhalt des letzten Datensatzes

    DomMittelwert (DAvg)

    Durchschnittswert des Feldinhaltes. Nullwerte werden ignoriert

    DomVarianz (DVar)

    Varianz eines Feldes, bezogen auf eine Stichprobe

    DomVarianzG (DVarP)

    Varianz eines Feldes, bezogen auf die Gesamtmenge

    DomStdAbw (DStDev)

    Standardabweichung eines Feldes, bezogen auf eine Stichprobe

    DomStdAbwG (DStDevP)

    Standardabweichung eines Feldes, bezogen auf die Gesamtmenge

    DomMin (DMin)

    minimaler Wert eines Feldes

    DomMax (DMax)

    maximaler Wert eines Feldes

    DomWert (DLookup)

    Feldinhalt des ersten Datensatzes

    Tab. 1: Domänenfunktionen von Access

    Der Aufruf einer Domänenfunktion erfolgt immer in dieser Form:

    Funktion(Ausdruck;Domäne[;Kriterium])

    Alle drei Parameter werden in Form einer Zeichenkette übergeben, wobei die ersten beiden zwingend notwendig sind. Der Parameter Kriterium ist optional und kann weggelassen werden, wenn er nicht benötigt wird. Im Prinzip finden Sie in den Parametern die Hauptkomponenten einer SQL-Abfrage wieder, wobei lediglich die entsprechenden Schlüsselwörter weggelassen werden. Fügen Sie diese (in Gedanken) wieder hinzu, erhalten Sie den SQL-Befehl:

    SELECT Ausdruck FROM Domäne WHERE Kriterium

    Tatsächlich baut Access aus den Parametern einen der jeweiligen Domänenfunktion angepassten SQL-Befehl zusammen. Daher müssen Sie bei der Verwendung von Domänenfunktionen alle Bedingungen und Einschränkungen beachten, die auch für „normale“ SQL-Befehle gelten.

    Dies gilt vor allem für die vom SQL-Interpreter vorgeschriebenen amerikanischen Formatierungen, auf die der Beitrag später noch eingehen wird. Für die folgenden Beschreibungen der einzelnen Parameter verwenden Sie als Beispiel die Domänenfunktion DomWert(), die einen einzelnen Wert aus einer Tabelle oder Abfrage ermittelt und die Funktion DomAnzahl(), welche die Anzahl der Datensätze zurückgibt, die einen Eintrag in einem bestimmten Feld enthalten.

    Der Parameter „Ausdruck“

    Bei diesem Parameter handelt es sich normalerweise um den Namen des Feldes, das die benötigte Information enthält. Der Feldname wird als Zeichenkette übergeben, daher müssen Sie ihn in Anführungszeichen setzen. Um etwa das Bestelldatum des ersten Datensatzes der Tabelle Bestellungen zu ermitteln, verwenden Sie folgenden Ausdruck:

    DomWert("[Bestelldatum]";"[Bestellungen]")

    Unter VBA würde dieser Ausdruck so aussehen (in einer Zeile):

    Dlookup("[Bestelldatum]","[Bestellungen]")

    Sie können das Ergebnis dieses Ausdrucks im Direktfenster durch Voranstellen der Anweisung Debug.Print oder dessen Abkürzung, dem Fragezeichen (), ausgeben lassen (siehe Bild 1).

    Bild 1: Testen einer Domänenfunktion im Direktfenster

    Statt eines einzelnen Feldnamens kann aber auch ein komplexerer Ausdruck übergeben werden, der Informationen aus mehreren Feldern zusammenfasst oder Berechnungen durchführt. In diesem Fall setzen Sie den gesamten Ausdruck in doppelte Anführungszeichen. Der folgende Ausdruck ermittelt beispielsweise die Zeit zwischen der Bestellung und der Lieferung des ersten Datensatzes der Tabelle Bestellungen:

    DomWert("[Lieferdatum] - [Bestelldatum]"; "[Bestellungen]")

    Die VBA-Variante lautet:

    Dlookup("[Lieferdatum] - [Bestelldatum]", "[Bestellungen]")

    Befinden sich innerhalb des Ausdrucks doppelte Anführungszeichen, ersetzen Sie diese durch einfache Anführungszeichen, die vom SQL-Interpreter als Begrenzungszeichen anerkannt werden.

    Der folgende Ausdruck ermittelt die Firmenbezeichnung aus dem ersten Datensatz der Tabelle Kunden und stellt den Ansprechpartner anschließend in Klammern dar:

    DomWert("[Firma] & '' ('' & [Kontaktperson] & '')''";"[Kunden]")

    beziehungsweise

    Dlookup("[Firma] & '' ('' & [Kontaktperson] & '')''","[Kunden]")

    Anstelle eines einfachen Anführungszeichens können Sie auch zwei doppelte Anführungszeichen verwenden, allerdings wird ein solcher Ausdruck sehr schnell unübersichtlich:

    DomWert("[Firma] & "" ("" & [Kontaktperson] & "")""";"[Kunden]")

    Die Zeichenkette kann der Domänenfunktion auch als Bezeichner, als Ergebnis einer Funktion oder (in VBA) als Variable übergeben werden.

    In diesem Fall lassen Sie die Anführungszeichen weg. Es muss jedoch sichergestellt sein, dass die übergebene Zeichenkette die bereits angesprochenen formalen Bedingungen erfüllt, ansonsten erhalten Sie den Ausdruck #Fehler als Ergebnis.

    Der Parameter „Domäne“

    Wie auch der Parameter Ausdruck ist der Parameter Domäne nicht optional und daher unbedingt einzugeben. Als gültige Werte wird der Name jeder Tabelle oder gespeicherten Abfrage der aktuellen Datenbank in Form einer Zeichenkette akzeptiert. Auch für diesen Parameter gelten die gleichen Regeln bezüglich der Anführungszeichen und eckigen Klammern wie beim Parameter Ausdruck. Wird als Domäne der Name einer Abfrage verwendet, kann es sich hierbei nur um eine gespeicherte Abfrage handeln. Es ist nicht möglich, diesen Parameter wie im Ausdruck

    DomWert("[Bestelldatum]";"SELECT * FROM [Bestellungen]")

    direkt in Form eines SQL-Befehls zu übergeben.

    Aus Gründen der Ausführungsgeschwindigkeit sollten Sie versuchen, die benötigte Information möglichst direkt aus der Tabelle zu beziehen. Im optimalen Fall verfügt die Tabelle über einen Index auf das gesuchte Feld.

    Der Parameter „Kriterium“

    Alle bisherigen Beispiele lieferten die gesuchte Information entweder aus einem Feld des ersten Datensatzes (DomWert()) oder berücksichtigten bei der Berechnung alle Datensätze (DomAnzahl()) der im Parameter Domäne genannten Tabelle oder Abfrage.

    Dies liegt daran, dass Sie den Parameter Kriterium bei diesen Beispielen einfach weggelassen haben. Mit diesem Parameter ist es möglich, auf einen anderen als den ersten Datensatz zuzugreifen oder lediglich eine begrenzte Auswahl von Datensätzen zu berücksichtigen.

    Die Syntax des Parameters Kriterium entspricht exakt der WHERE-Klausel einer SQL-Abfrage, bei der das Schlüsselwort WHERE fehlt. Wie die anderen Parameter wird auch dieser als Zeichenkette übergeben und ist in doppelte Anführungszeichen zu setzen. Um beispielsweise das Bestelldatum der Bestellung Nr. 10268 zu ermitteln, verwenden Sie den Ausdruck

    Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

    den kompletten Artikel im PDF-Format mit Beispieldatenbank

    diesen und alle anderen Artikel mit dem Jahresabo

    Schreibe einen Kommentar

    Access-FAQ: Rund um Access

    Zusammenfassung

    Erfahren Sie, wie Sie mit Schlüsseln, Indizes, Beziehungen und Validierungen für konsistente Daten sorgen.

    Techniken

    Tabellen, Indizes, Schlüssel, Beziehungen, Gültigkeitsregeln, Validierung in Formularen

    Voraussetzungen

    Access 97 oder höher

    Beispieldateien

    FAQ10_97.mdb, FAQ10_00.mdb

    Karl Donaubauer, Wien

    In der Access-FAQ von Karl Donaubauer (www.donkarl.com) finden Sie die meistgestellten Fragen und Anworten zum Thema Microsoft Access. In dieser Beitragsreihe stellt Karl Donaubauer die wichtigsten Einträge im Detail vor und zeigt Ihnen entsprechende Lösungen anhand praxisnaher Beispiele. Im zehnten Teil werden Lösungen für die häufigsten Probleme mit dem Tastatur-, Cursor- und Mausverhalten in Formularen vorgestellt sowie Probleme, die beim Aufruf von Berichten aus Formularen auftreten.

    Das Register-Steuerelement ist ein besonderes Wesen. Es hat keinen Steuerelementinhalt und kann keine Tabellendaten aufnehmen, besitzt aber eine Value-Eigenschaft. Es ist ein Container für die anderen Steuerelemente, spielt aber bei einem Bezug auf diese Steuerelemente keine Rolle. Es bietet mit den Seiten (Pages) seine eigenen Steuerelemente, die aber ganz anders funktionieren, und vieles mehr. Diese Besonderheiten bereiten mancherlei Probleme auch in Hinblick auf die Navigation.

    Eine häufige Frage ist etwa, wie man per VBA einen Seitenwechsel auslösen kann. Eine Möglichkeit ist, mit SetFocus den Fokus auf ein Steuerelement auf der gewünschten Seite zu setzen. Das bewirkt gleichzeitig einen Seitenwechsel. Ein gezielter Seitenwechsel lässt sich jedoch auch ohne diesen Workaround mit der bereits erwähnten Eigenschaft Value des Register-Steuerelements regeln:

    Me!MeinRegister.Value = 1

    Dieser Code wechselt zur zweiten Seite des Registers. Die Value-Eigenschaft entspricht der Eigenschaft Seitenindex (PageIndex) der einzelnen Registerseiten. Die erste Seite hat immer den Index 0, die zweite Seite 1 und so weiter. Wie bei den meisten anderen Steuerelementen heißt auch beim Register die Standardeigenschaft Value und kann deshalb weggelassen werden. Für den Wechsel zur zweiten Seite reicht also:

    Me!MeinRegister = 1

    Ein anderes häufiges Problem ist, wie man bei einem Register-Steuerelement mitbekommt, dass die Seite gewechselt wird, weil man mit Aktionen oder Einstellungen auf den Wechsel zu einer bestimmten Seite reagieren möchte. Für diesen Zweck besitzt das Register das Ereignis Bei änderung (OnChange). Um die Eigenschaften des Register-Steuerelementes zu sehen, darf nicht eine einzelne Seite, sondern muss das Register komplett markiert sein. Das erreichen Sie in der Entwurfsansicht am besten durch einen Ziehrahmen, der außerhalb des Registers beginnt, oder durch einen Klick auf einen freien Platz neben den Registerzungen. Im Code der Ereignis-Eigenschaft Bei änderung können Sie dann zum Beispiel ein Select-Case-Konstrukt verwenden, um auf die Seitenwechsel individuell reagieren zu können (s. Quellcode 1).

    Quellcode 1: Registerseite wechseln

    Private Sub MeinRegister_Change()
        Select Case Me!MeinRegister.Value
            Case 0
                ''es wurde zur 1. Seite gewechselt
            Case 1
                ''es wurde zur 2. Seite gewechselt
        End Select
    End Sub

    Oft wird eine längere, zusammengehörende Sequenz von Steuerelementen auf verschiedene Registerseiten verteilt, zum Beispiel um die vielen Textfelder von Personal- oder Fragebögen besser zu gliedern. In diesem Fall ist es für Tastatureingaben bequemer, wenn beim Drücken der Eingabetaste im untersten Steuerelement der Registerseite der Wechsel zum ersten Steuerelement der nächsten Seite ausgelöst wird. Diese Funktionalität können Sie mithilfe des Ereignisses Bei Taste Ab des Textfeldes programmieren.

    Bild 1: Navigation im Register-Steuerelement

    Bild 1 zeigt das Beispiel-Formular frmRegister, in das alle genannten Funktionalitäten eingebaut sind.

    Der Ereigniscode Bei Taste Ab des letzten Textfelds auf Seite 2 lautet:

    Select Case KeyCode
      Case vbKeyReturn, vbKeyDown, vbKeyTab And (Shift And acShiftMask) = 0
        KeyCode = 0
        Me!Telefon.SetFocus
    End Select

    Es wird damit geprüft, ob die Eingabetaste, die Cursortaste Nach unten oder die Tabulatortaste ohne heruntergedrückte Umschalttaste betätigt wurde. Falls ja, wird der Tastaturanschlag aufgehoben und der Fokus auf das erste Textfeld, Telefon, der dritten Registerseite gesetzt. Wie schon erwähnt, wird dadurch automatisch ein Seitenwechsel bewirkt.

    Komplett ist diese Tastatursteuerung erst mit dem Gegenstück, das heißt, im ersten Steuerelement einer Registerseite sollten die Cursortaste Nach oben oder die Tabulatortaste bei gedrückter Umschalttaste den Wechsel zum letzten Steuerelement der vorherigen Seite bewirken. Im Ereigniscode Bei Taste Ab des Textfeldes Telefon steht daher:

    Select Case KeyCode
        Case vbKeyUp, vbKeyTab And _        (Shift And acShiftMask) = 1
        KeyCode = 0
        Me!Land.SetFocus
    End Select

    Von der Datenblattansicht von Tabellen, Abfragen und Formularen oder auch von Excel her sind viele Anwender gewohnt, die Zeile mit den Cursortasten Nach unten und Nach oben wechseln zu können. In einem Endlosformular hingegen muss der Cursor standardmäßig erst alle Steuerelemente des Datensatzes durchlaufen und wechselt erst nach dem letzten Steuerelement zum nächsten Datensatz beziehungsweise zur nächsten Zeile. Der Weg, um das zu ändern, führt über die Programmierung des Tastaturverhaltens auf Formularebene. Zuerst müssen Sie die Eigenschaft Tastenvorschau des Formulars auf Ja setzen, damit die Tastaturereignisse des Formulars Vorrang vor denen der Steuerelemente haben. Im Ereignis Bei Taste Ab des Formulars können Sie dann folgenden Code verwenden:

    On Error Resume Next
    Select Case KeyCode
        Case vbKeyDown
            KeyCode = 0
            DoCmd.GoToRecord , , acNext
        Case vbKeyUp
            KeyCode = 0
            DoCmd.GoToRecord , , acPrevious
    End Select

    Beim ersten oder letzten Datensatz würde eine Fehlermeldung erscheinen, weil kein weiterer Datensatzwechsel in die gleiche Richtung mehr möglich ist. Diese erwarteten Fehlermeldungen werden zu Beginn des Codes mit Resume Next übergangen. Danach wird geprüft, ob eine der Cursortasten Nach unten oder Nach oben gedrückt wurde. In beiden Fällen werden die Tastaturwerte ausgelesen und es wird zum nächsten beziehungsweise vorherigen Datensatz gewechselt. Bei jedem Drücken dieser beiden Tasten in allen Steuerelementen wird nun ein Datensatzwechsel ausgelöst und das Endlosformular verhält sich wie ein Datenblatt. Allerdings nur fast.

    Falls sich ein Kombinationsfeld im Formular befindet, dessen Auswahlliste gerade aufgeklappt ist, dann findet mit den Cursortasten ebenfalls ein Datensatzwechsel statt. Der Anwender kann also nicht mehr wie gewohnt mit diesen Tasten in der Auswahlliste navigieren. Bild 2 zeigt dieses Dilemma, beinhaltet aber auch die Lösung. Mit Access-Mitteln gibt es leider keine Möglichkeit zu prüfen, ob die Auswahlliste eines Kombinationsfeldes geöffnet ist oder nicht. Dafür sind relativ umfangreiche API-Codes nötig, die es im Internet zum Beispiel vom bekannten API-Künstler Dev Ashish gibt. Seinen Code habe ich in der Beispiel-Datenbank in das Modul basIsComboOpen eingefügt. Im Formular frmDSWechselCursor ist dann im zuvor beschriebenen Code nur eine zusätzliche Zeile mit dem Aufruf der Funktion nötig, die prüft, ob aktuell ein Kombinationsfeld geöffnet ist:

    If fIsComboOpen Then Exit Sub

    In diesem Fall wird also schlicht die Prozedur verlassen und die Tastatureingabe nicht geändert, damit der Anwender ganz normal in der geöffneten Liste navigieren kann.

    Bild 2: Kein Datensatzwechsel bei geöffnetem Kombinationsfeld

    In den bisherigen Fällen ging es darum, die Navigation, vor allem per Tastatur, zu erweitern. Der Gegensatz sind Situationen, in denen die eingebauten Navigationsmöglichkeiten von Access unerwünscht sind und eingeschränkt werden müssen.

    Der einfachste Fall ist, den Datensatzwechsel zum vorigen/nächsten Datensatz zu verhindern, wenn im ersten/letzten Steuerelement die Return-, Tabulator- oder eine Pfeiltaste gedrückt wird. Dafür bietet Access die eingebaute Eigenschaft Zyklus, die Sie auf Aktueller Datensatz stellen können.

    Nur wenig aufwändiger ist das Unterbinden des Datensatzwechsels mit den Tasten Bild Auf und Bild Ab, die standardmäßig einen Datensatzsprung um eine komplette Formularinnenhöhe bewirken. Um das zu verhindern, müssen Sie wiederum die Eigenschaft Tastenvorschau des Formulars auf Ja setzen. Im Ereignis Bei Taste Ab des Formulars reicht dann eine einzige Codezeile, um die beiden Tasten zu deaktivieren:

    If KeyCode = vbKeyPageUp Or KeyCode = vbKeyPageDown Then KeyCode = 0

    Schade ist, dass es nach wie vor keine Option gibt, die dieses Verhalten Access- oder anwendungsweit einstellt, wie es für andere Tastaturfunktionalitäten im Menü Extras/Optionen/Tastatur oder zumindest über ein Tastaturbelegungs-Makro möglich ist. Statt dessen müssen Sie es für die Bild-Auf- und Bild_ Ab-Taste in jedem einzelnen Formular selbst und per Code regeln.

    Wesentlich komplizierter ist das Verhindern des Datensatzwechsels per Scrollmaus. Dafür sind umfangreiche API-Programmierungen nötig, wie sie zum Beispiel im Knowledgebase-Artikel 278379 erläutert werden. Es gibt im Web einige Komplettlösungen mit unterschiedlichen Stärken und Schwächen. Eine bewährte Lösung ist zum Beispiel jene von Stephen Lebans auf seiner Webseite http://www.lebans.com/mousewheelonoff.htm.

    Eine häufige Frage in diesem Zusammenhang ist, ob hier nicht das mit Access 2002 eingeführte Ereignis Bei Mausrad helfen könne. Antwort: Nein. Dieses Ereignis verhindert gar nichts und die ganze Access-Gemeinde sucht seit Jahren nach seinem praktischen Nutzen.

    Das Cursorverhalten bei Eintritt in ein Textfeld lässt sich für die ganze Datenbank geltend im Menü Extras/Optionen/Tastatur einstellen. Wenn Sie hingegen das Verhalten für einzelne Formulare oder Steuerelemente ändern möchten, müssen Sie das per Programmierung erledigen. Je nach Situation und gewünschtem Effekt können Sie das Ereignis Beim Hingehen oder Beim Klicken des Steuerelementes verwenden oder den Cursor mit der SetFocus-Methode von außen auf das Steuerelement setzen.

    Jedenfalls muss sich der Cursor im Steuerelement befinden, damit Sie die Markierung beeinflussen können. Nur dann stehen die dafür nötigen Eigenschaften SelStart und SelLength zur Verfügung. Die folgenden Varianten sind für die Praxis relevant.

    ''Cursor an den Anfang des Textes setzen:
    Me!MeinTextfeld.SelStart = 0
    ''Cursor an das Ende des Textes setzen
    Me!MeinTextfeld.SelStart = _    Len(Nz(Me!MeinTextfeld))
    ''Den kompletten Text markieren:
    Me!MeinTextfeld.SelStart = 0
    Me!MeinTextfeld.SelLength = _    Len(Nz(Me!MeinTextfeld))

    Die Nz-Funktion in den beiden letzten Varianten verhindert die Fehlermeldung, die bei einem leeren Textfeld in der Len-Funktion auftreten würde.

    Bild 3 zeigt das Beispiel-Formular frmMarkierung in der Datenbank zum Artikel.

    Bild 3: Cursorsetzung und Textmarkierung

    Einige Assistenten in Access wurden bereits für die Version 2.0 programmiert und sind seither unverändert, weil Microsoft es nicht der Mühe wert fand, sie zu modernisieren.

    Eine alte Schwäche, die hier mitgeschleppt wird, ist eine Beschränkung bei den Berichtsoperationen des Schaltflächenassistenten: Man kann zwar den Druck eines Berichtes mit den Formulardaten einstellen, nicht aber die Einschränkung auf den aktuellen Datensatz im Formular. Es gibt zwei übliche Lösungswege dafür.

    Beim ersten lässt man den Bericht auf einer eigenen Abfrage basieren und verwendet in der Abfrage bei einem eindeutigen Feld, das den Datensatz identifiziert, als Kriterium einen Bezug auf das Formular, also zum Beispiel:

    Quellcode 1: Prüfen der Datenherkunft und gegebenenfalls Abbruch der Berichtsausgabe

    If DCount("*", "Datenherkunft des Berichtes") > 0 Then
        DoCmd.OpenReport "Berichtsname"
    Else
        MsgBox "Der Bericht enthält keine Daten.", _
        vbInformation + vbOKOnly, "Keine Daten"
    End If

    Forms!frmKunden!KundenId

    Der Vorteil dieser Lösung ist, dass keine Programmierkenntnisse notwendig sind. Auch jemand mit relativ wenig Erfahrung kann sich eine Drucken-Schaltfläche vom Assistenten erstellen lassen, eine Abfrage anpassen und sie als Datenherkunft eines Berichtes eintragen.

    Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

    den kompletten Artikel im PDF-Format mit Beispieldatenbank

    diesen und alle anderen Artikel mit dem Jahresabo

    Schreibe einen Kommentar

    Access-FAQ: Rund um Access

    Karl Donaubauer, Wien

    In der Access-FAQ von Karl Donaubauer (www.donkarl.com) finden Sie die meistgestellten Fragen und Anworten zum Thema Microsoft Access. In dieser Beitragsreihe stellt Karl Donaubauer die wichtigsten Einträge im Detail vor und zeigt Ihnen entsprechende Lösungen anhand praxisnaher Beispiele. Im fünften Teil lernen Sie die Lösungen zu den meistgenannten Problemen der Teilnehmer der deutschsprachigen Access-Newsgroups im Zusammenhang mit Tabellen kennen.

    Eine professionell aufgebaute Access-Anwendung besteht fast immer aus zwei oder mehr MDBs in der klassischen Frontend/Backend-Struktur. In der Backend-MDB befinden sich nur die Daten, das heißt Tabellen, in der Frontend-MDB sämtliche anderen Datenbankobjekte sowie die eingebundenen Tabellen aus dem Backend. Die wichtigsten Vorteile dieser Struktur sind geringere Korruptionsanfälligkeit und leichtere Wartung.

    Manche Anwendungen besitzen auch mehrere Backends, aus denen Tabellen im Frontend eingebunden sind. Das macht zum Beispiel Sinn, wenn ein einzelnes Backend aufgrund der Datenmenge an die Grenzen von Access stoßen würde (ein Gigabyte bei Access 97, zwei Gigabyte ab Access 2000) oder wenn man „Wegwerf-Backends“ verwendet, in die große Datenmengen aus anderen Formaten importiert werden und die dafür immer wieder neu aufgebaut werden.

    Bild 1: Tabelleneigenschaft Beschreibung

    Access erlaubt bei eingebundenen Tabellen leider nur die Angabe von absoluten und fixen Herkunftspfaden. Diese sind in der Entwurfsansicht der eingebundenen Tabelle in der Eigenschaft Beschreibung sichtbar. Bild 1 zeigt ein Beispiel, in dem der Wert dieser Eigenschaft folgendermaßen lautet (ohne Zeilenumbruch):

    DATABASE=D:\Lager\ArtikelBE.mdb;TABLE=tblArtikel

    Das bedeutet, dass die Originaltabelle tblArtikel heißt und dass sich das Backend ArtikelBE.mdb im Ordner D:\Lager befindet.

    Hinweis

    Auf der Begleit-CD finden Sie je zwei Beispiel-Datenbanken im Format von Access 97 und im Format von Access 2000 mit den Quellcodes und Beispielen aus diesem Artikel.

    Function fctReConnect1(strNameBE As String)
        On Error GoTo myError
        Dim db As DAO.Database
        Dim tdf As DAO.Tabledef
        Dim strPathBE As String
        Set db = CurrentDb
        strPathBE = Left(db.Name, Len(db.Name) - _        Len(Dir(db.Name))) & strNameBE
        For Each tdf In db.TableDefs
           If tdf.Connect <> "" Then
                If Mid(tdf.Connect, 11) <> strPathBE Then
                    tdf.Connect = ";database=" & strPathBE
                    tdf.RefreshLink
                End If
           End If
        Next tdf
    myExit:
        Exit Function
    myError:
        Select Case Err.Number
            Case Else
                MsgBox "Ausnahme Nr. " & Err.Number _                & " " & Err.Description
        End Select
        Resume myExit
    End Function

    Quellcode 1

    ändert sich nun der Ordner des Backends, so ist die Verbindung zur Ursprungstabelle verloren, und beim Versuch, die eingebundene Tabelle zu öffnen, erscheint eine Fehlermeldung, die besagt, dass die Backend-MDB nicht gefunden werden kann. Manuell müsste man nun die eingebundene Tabelle löschen und wieder neu mit dem richtigen Pfad verknüpfen.

    Eine andere Möglichkeit ist die Verwaltung der eingebundenen Tabellen über den Tabellenverknüpfungs-Manager im Menüpunkt Extras/Datenbank-Dienstprogramme. Der Tabellenverknüpfungs-Manager hat jedoch einige Schwächen, wie Installationsprobleme und begrenzte Breite für sehr lange Pfade.

    In Access 2003 gibt es zudem den häufigen Bug, dass eingebundene Tabellen nicht im Manager angezeigt werden. Man muss für sein korrektes Funktionieren erst die zuständige accwizz.dll neu registrieren. Bug und Lösung sind im Knowledgebase-Artikel 835519 beschrieben.

    Möchten Sie das Wiedereinbinden selbst kontrollieren und automatisieren, so können Sie per Code beim Starten der Datenbank prüfen, ob die Einbindung noch in Ordnung ist, und falls nicht, die Tabellen neu verknüpfen. Um das komplett ohne Anwender-Eingriff durchzuführen, können Sie als Vorgabe für den Anwender festlegen, dass Backend- und Frontend-MDB immer zusammen in einem gemeinsamen Verzeichnis zu installieren sind. Damit kann der Code automatisch den aktuellen Pfad für die Wiedereinbindung verwenden. Die Funktion aus Quellcode 1 erledigt genau das.

    Sie können die Funktion beim öffnen des Startformulars oder im Autoexec-Makro aufrufen:

    fctReConnect1 "NameDesBackends"

    Im Code wird zuerst die Variable strPathBE auf den aktuellen Ordner des Frontends gesetzt und um den übergebenen Backend-Namen ergänzt. Danach werden alle Tabellen des Frontends durchlaufen und es wird geprüft, ob die Eigenschaft Connect mehr als einen Leerstring erhält. Nur bei eingebundenen Tabellen enthält die Eigenschaft den gleichen Text wie die oben angeführte Tabelleneigenschaft Beschreibung. Es wird geprüft, ob Backendpfad und -name identisch sind mit strPathBE. Falls nicht, wird die Connect-Eigenschaft auf den neuen Pfad geändert und die Verbindung mit der Methode RefreshLink aktualisiert. Das Installieren von Frontend und Backend im selben Ordner ist natürlich nicht immer möglich. In solchen Fällen ist das Wiedereinbinden in der Praxis nur halbautomatisch möglich.

    Function fctReConnect2()
        On Error GoTo myError
        Dim tdf As DAO.Tabledef
        Dim strPathBE As String
        If DLookup("ArtikelId", "tblArtikel") <> "" Then Exit Function
    myExit:
        Exit Function
    myError:
        Select Case Err.Number
            Case 3024, 63725, 3043, 3044
                MsgBox "Der Pfad zu den Daten hat sich geändert. " & _
                       "Bitte wählen Sie im folgenden Dialog die aktuelle Daten-mdb aus."
                strPathBE = fct_Datei_suchen
                If strPathBE <> "" Then
                    Dim db As DAO.Database
                    Set db = CurrentDb
                    For Each tdf In db.TableDefs
                       If tdf.Connect <> "" Then
                            If Mid(tdf.Connect, 11) <> strPathBE Then
                                tdf.Connect = ";database=" & strPathBE
                                tdf.RefreshLink
                            End If
                       End If
                    Next tdf
                End If
                Resume Next
            Case Else
                MsgBox "Bei der Installation ist ein Problem aufgetreten. " & _
                       "Bitte überprüfen Sie den Pfad und versuchen Sie noch " & _
                       "einmal die Daten einzubinden.", _
                       vbCritical, "Problem bei der Installation !"
                Resume myExit
        End Select
    End Function
    Public Function fctDateiSuchen()
        Dim fd As New FileDialog
        With fd
            .DialogTitle = "Datei suchen"
            .InitDir = Left(CurrentDb.Name, Len(CurrentDb.Name) - _            Len(Dir(CurrentDb.Name)))
            .ShowOpen
        End With
        If Len(fd.FileName) > 0 Then fctDateiSuchen = fd.FileName
    End Function

    Quellcode 2

    Der Anwender bekommt dabei am besten einen Dateidialog zur Auswahl des Backends präsentiert. Es gibt verschiedene Varianten von Dateidialogen, die man dafür verwenden kann. Ab Office XP existiert der Office-eigene Dateidialog. Für alle Office-Versionen gibt es das FileDialog-ActiveX von Microsoft. Stabiler im Hinblick auf die Verweisproblematik ist jedoch der Aufruf des Windows-eigenen Dateidialogs mithilfe von API-Aufrufen.

    Quellcode 2 zeigt ein Beispiel für einen relativ einfachen Wiedereinbindungscode.

    Bild 2: WindowsXP-Dateidialog zur Auswahl des Backends

    Zum Anzeigen des Windows-Dateidialogs (siehe Bild 2) wird das in der Access-Gemeinde sehr bekannte und frei erhältliche Klassenmodul FileDialog von Karsten Pries verwendet.

    Für die anderen genannten Dateidialoge ist die Verwendung im Wiedereinbindungscode nur unwesentlich anders zu gestalten. Alle geben einen String mit dem ausgewählten Pfad und Dateinamen zurück. In der fctReConnect2 in Quellcode 2 wird zuerst ein DLookup auf irgendein Tabellenfeld, das sicher vorhanden ist, ausgeführt. Wenn die Datenverbindung zum Backend nicht mehr stimmt, ergibt dieser versuchte Datenzugriff einen Laufzeitfehler. In der Fehlerbehandlung werden die Fehlernummern abgeprüft, die üblicherweise bei nicht korrekter Backendverbindung auftreten (Daten-MDB nicht gefunden, Netzwerkfehler wegen Laufwerksproblem, kein zulässiger Pfad). Dann wird die Funktion fctDateiSuchen verwendet, die den Dateidialog aufruft und die wichtigsten Einstellungen (Titel und Startordner) für den Dialog vornimmt. Mit dem ausgewählten und zurückgelieferten Pfad und Dateinamen wird dann die Neueinbindung auf die gleiche Weise wie bei Quellcode 1 beschrieben durchgeführt.

    Theoretisch sollte es ja kaum vorkommen, in der Praxis passiert es aber sehr wohl, dass der Typ eines Tabellenfeldes nachträglich geändert werden muss oder die Feldgröße eines Textfeldes nicht ausreicht. Manuell im Tabellenentwurf ist das schnell erledigt. Wenn es aber programmatorisch bei einem Kunden oder auf vielen anderen Arbeitsplätzen durchgeführt werden soll, ist es etwas schwieriger. Alle anderen Eigenschaften eines Tabellenfeldes sind per DAO oder ADO änderbar, nicht so der Felddatentyp und die Feldgröße. Es gibt zwar die entsprechenden DAO-Eigenschaften Type und Size, aber nur Size kann schreibend verwendet werden und das nur für neue Felder, nicht für bereits bestehende.

    Die Lösung dieser Aufgabe hängt von der Access-Version ab. Bis Access 97 gibt es nur die Möglichkeit, ein neues Tabellenfeld mit den passenden Eigenschaften zu erstellen, die Daten aus dem alten Feld zu übernehmen und das alte Feld danach zu löschen. Mit Access 2000, genauer gesagt mit JET 4, hat Microsoft JET-SQL um den Befehl ALTER COLUMN erweitert, der nachträgliche änderungen an Typ und Größe eines Feldes ermöglicht. Das Vorgehen ist am besten an einem Beispiel erklärt.

    Im folgenden Beispiel soll per Code die Feldgröße des Textfeldes Artikelbezeichnung in der eingebundenen Tabelle tblArtikel von 50 auf 100 geändert werden. Da die Tabelle nur verlinkt und physisch in der Backend-MDB ArtikelBE steht, muss die änderung dort vorgenommen werden. Quellcode 3 zeigt das in den Versionen bis Access 97 notwendige, relativ umständliche Vorgehen.

    On Error GoTo myError
    Dim db As DAO.Database
    Set db = DBEngine.Workspaces(0).OpenDatabase("d:\Lager\ArtikelBE.mdb")
    db.TableDefs("tblArtikel").Fields("Artikelbezeichnung").Name = "AltesFeld"
    db.Execute "ALTER TABLE tblArtikel ADD COLUMN Artikelbezeichnung VARCHAR(100)"
    db.Execute "UPDATE tblArtikel SET Artikelbezeichnung = AltesFeld"
    db.Execute "ALTER TABLE tblArtikel DROP COLUMN AltesFeld"
    db.Close: Set db = Nothing
    myExit:
        Exit Sub
    myError:
        Select Case Err.Number
            Case Else
                MsgBox "Ausnahme Nr. " & Err.Number & " " & Err.Description
        End Select
        Resume myExit

    Quellcode 3

    Zuerst wird die Backend-Datenbank mit der DAO-Methode OpenDatabase geöffnet. Dann wird das Feld Artikelbezeichnung mithilfe der DAO-Eigenschaft Name in AltesFeld umbenannt. Für die weiteren Operationen werden SQL-Befehle verwendet, die mit der DAO-Methode Execute ausgeführt werden. Zuerst wird ein neues Feld mit den gewünschten Einstellungen erzeugt. Detaillierte Erläuterungen dazu:

    ALTER TABLE tblArtikel ADD COLUMN Artikelbezeichnung VARCHAR(100)

    VARCHAR ist die Typbezeichnung für ein Textfeld mit variabler Länge. Die Feldgröße wird auf 100 gesetzt. Im nächsten Schritt werden die Werte aus dem bisherigen Feld übernommen:

    UPDATE tblArtikel SET Artikelbezeichnung = AltesFeld

    Zum Schluss wird das bisherige Feld gelöscht:

    ALTER TABLE tblArtikel DROP COLUMN AltesFeld

    Ab Access 2000 ist dieses komplizierte Vorgehen nicht mehr notwendig, denn der SQL-Befehl ALTER TABLE wurde um das leistungsfähige ALTER COLUMN erweitert. Der komplette Quellcode 3 kann daher durch eine einzige Codezeile ersetzt werden:

    CurrentDb.Execute "ALTER TABLE d:\Lager\ArtikelBE.mdb.tblArtikel ALTER COLUMN Artikelbezeichnung VARCHAR(100)"

    Natürlich kann man wie in Quellcode 4 auch hier zuerst die externe Datenbank mit OpenDatabase öffnen, sie einer Objektvariablen zuordnen und Execute statt CurrentDb verwenden.

    Wie Sie sehen, ist es in JET-SQL aber auch möglich, Pfad und Name der Datenbank direkt in den SQL-String zu schreiben und den Tabellennamen mit Punkt getrennt anzuhängen. Auch so kann man den SQL-Befehl im Execute gegen eine andere MDB ausführen. In der Beispiel-Datenbank auf der Heft-CD finden Sie diese Codebeispiele im Formular frmFeldAenderungen.

    Für viele Operationen ist es wichtig zu wissen, ob eine bestimmte Tabelle in der Datenbank vorhanden ist oder nicht. Es gibt verschiedene Methoden, das zu prüfen. Eine der üblichen zeigt Quellcode 4.

    Function fctTabVorhanden(strTableName As String) _    As Boolean
        Dim db As DAO.Database
        Dim tdf As DAO.TableDef
        Set db = CurrentDb
        For Each tdf In db.TableDefs
            If tdf.Name = strTableName Then
                fctTabVorhanden = True
                Exit For
            End If
        Next
    End Function

    Quellcode 4

    Function fctTabVorhanden2(strTableName As String) _    As Boolean
        On Error GoTo myError
        Dim db As DAO.Database
        Dim tdf As DAO.TableDef
        Set db = CurrentDb
        Set tdf = db.TableDefs(strTableName)
        fctTabVorhanden2 = True
    myExit:
        Set tdf = Nothing
        Exit Function
    myError:
        Select Case Err.Number
            Case 3265
            Case Else
                MsgBox "Ausnahme Nr. " & Err.Number _                & " " & Err.Description
        End Select
        Resume myExit
    End Function

    Quellcode 5

    Die Funktion fctTabVorhanden erwartet beim Aufruf die übergabe eines Tabellennamens nach folgendem Muster:

    fctTabVorhanden("GesuchteTabelle")

    Im Code wird die TableDefs-Auflistung der aktuellen Datenbank durchlaufen und je nachdem, ob der übergebene Name darin gefunden wird oder nicht, liefert die Funktion True oder False zurück. Eine andere Variante zeigt Quellcode 5.

    Der gesuchte Tabellenname wird wieder an die Funktion übergeben. Im Weiteren wird er für die Zuweisung an eine TableDef-Variable verwendet. Ist die Tabelle vorhanden, so wird der Funktionswert auf True gesetzt. Ist sie nicht vorhanden, gibt es einen Laufzeitfehler (3265, Element in dieser Auflistung nicht gefunden), der in der Fehlerbehandlung abgefangen wird. Der Rückgabewert der Funktion bleibt dabei auf False.

    Welches der beiden unterschiedlichen Verfahren man verwendet, ist eher Geschmackssache. Die zweite Variante sollte einen Tick schneller sein, weil sie nicht durch die Tabledefs-Auflistung läuft. In der Praxis ist dieser Unterschied aber irrelevant.

    Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

    den kompletten Artikel im PDF-Format mit Beispieldatenbank

    diesen und alle anderen Artikel mit dem Jahresabo

    Schreibe einen Kommentar