Ralf Albrecht, Natascha Nicol Access 2003 programmieren Professionelle Anwendungsentwicklung mit Access und VBA eBook Die nicht autorisierte Weitergabe dieses eBooks ist eine Verletzung des Urheberrechts! An imprint of Pearson Education München • Boston • San Francisco • Harlow, England Don Mills, Ontario • Sydney • Mexico City Madrid • Amsterdam Datenzugriff mit Recordsets Sub RecordsetOhneFilter() Dim db As DAO.Database Dim rst As DAO.Recordset Set db = CurrentDb() Set rst = db.OpenRecordset("Select * From _ qryAnzahlCocktailZutaten Where Cocktail Like 'C*'") ' Wiederhole bis zum Ende des Recordsets While Not rst.EOF Debug.Print rst!Cocktail; Debug.Print " mit "; rst("Anzahl von ZutatenNr"); Debug.Print " Zutaten" rst.MoveNext Wend rst.Close End Sub Eine interessante Methode im Zusammenhang mit Filtern ist BuildCriteria() zum Zusammenstellen einer Filterbedingung (siehe 14.2.6). 11.4.5 Sortieren von Recordsets Bei der Sortierung von Recordsets müssen wiederum die Recordset-Typen Table, Dynaset und Snapshot unterschieden werden. Sortierte Table-Recordsets Nach dem Öffnen eines Recordsets vom Typ Table sind die Datensätze nach dem Primärschlüssel der zugrunde liegenden Tabelle geordnet. Um die Sortierung zu ändern, muss im Programm die Eigenschaft Index des Recordsets eingestellt werden, so wie dies schon im Abschnitt 11.4.4, »Suchen von Datensätzen«, beschrieben wurde. Diese Eigenschaft kann nur für Table-Recordsets eingestellt werden, anderenfalls kommt es zu einer Fehlermeldung. Durch Setzen der IndexEigenschaft, z. B. in der Form Dim rstTable As DAO.Recordset Set rstTable = CurrentDb().OpenRecordset("tblCocktailLokal") rstTable.Index "Cocktail" liegen die Datensätze nach »Cocktail« sortiert vor. 343 11 Datenzugriff mit DAO Sortieren in Dynasets und Snapshots Es stehen Ihnen für die Sortierung von Dynasets und Snapshots zwei unterschiedliche Verfahren zur Verfügung: § Sortieren durch eine ORDER BY-Klausel in der SQL-Abfrage oder § sortieren mit der Sort-Eigenschaft des Recordsets. Für beide Varianten gelten im Prinzip die gleichen Aussagen, wie wir sie in Abschnitt 11.4.4, »Suchen von Datensätzen«, für die Filter-Eigenschaft getroffen haben. Verwenden Sie nach Möglichkeit immer ORDER BY und verzichten Sie auf den Einsatz der Eigenschaft Sort. 11.4.6 Lesezeichen Oft ist es in Programmen notwendig, sich die Position bestimmter Datensätze zu merken, um später darauf zurückkommen zu können. Access arbeitet mit so genannten Lesezeichen, englisch Bookmarks. Access führt für jeden Datensatz eines Recordsets eine eindeutige Markierung. Diese Markierung kann in einer eigenen Variablen gespeichert werden, um so später als Sprungadresse zu dienen. Lesezeichen sind nicht mit den Datensatznummern von dBase oder anderen Produkten vergleichbar, denn ihre Gültigkeit ist auf die Lebensdauer des Recordsets beschränkt. Ein Bookmark besitzt den Typ String, den Sie allerdings nicht beachten sollten, da er Access-intern festgelegt wird und sich in späteren Versionen ändern kann. Nicht alle Recordsets ermöglichen das Setzen von Lesezeichen. Die Eigenschaft Bookmarkable des Recordsets zeigt die Lesezeichenunterstützung an. Das folgende Programmfragment weist das Lesezeichen des aktuellen Datensatzes einer Variablen zu und setzt am Ende die Position des aktuellen Datensatzes auf den Datensatz, zu dem das gespeicherte Lesezeichen gehört. Dim strLesezeichen As String ... ' Speichern des Lesezeichens strLesezeichen = rst.Bookmark ... rst.MoveFirst ... ' Sprung zurück rst.Bookmark = strLesezeichen 344 Datenzugriff mit Recordsets 11.4.7 Recordset-Daten bearbeiten In Recordsets vom Typ Table und in bearbeitbaren Dynasets können Sie Veränderungen an den Daten vornehmen bzw. neue Datensätze hinzufügen. Ob ein Dynaset bearbeitbar ist, können Sie mit der Eigenschaft Updatable des Recordsets ermitteln. Nicht bearbeitbare Dynasets und Snapshots liefern für Updatable den Wert False zurück. Wir möchten in diesem Abschnitt nicht die Besonderheiten von Multiuser-Zugriffen auf Daten besprechen, da alle Fragen, die sich mit dem Sperren (Locking) von Daten beschäftigen, in Kapitel 18, »Multiuser-Zugriffe«, behandelt werden. Verändern von Daten Um den aktuellen Datensatz zu ändern, kopieren Sie mithilfe der Methode Edit die Daten in einen internen Puffer. Sind die Daten bearbeitet, wird die Änderung mit der Update-Methode geschrieben. Erst nach dem Update sind die Bearbeitungen dauerhaft gespeichert. Bewegen Sie vor dem Update den Positionszeiger zu einem anderen Datensatz, werden die Änderungen verworfen. Das folgende Programm durchläuft die Datensätze und ändert überall den Inhalt des Feldes CocktailGeändert auf das aktuelle Datum. Sub EditMethode() Dim db As DAO.Database Dim rst As DAO.Recordset Set db = CurrentDb() Set rst = db.OpenRecordset("tblCocktail") With rst If .Updatable Then While Not .EOF .Edit !CocktailGeändert = Now() .Update .MoveNext Wend End If End With rst.Close End Sub 345 11 Datenzugriff mit DAO Wenn Sie versuchen, die Methode Edit auf ein Recordset anzuwenden, dessen Eigenschaft Updatable den Wert False hat, erhalten Sie eine Fehlermeldung. Neue Datensätze hinzufügen Mithilfe der AddNew-Methode wird dem Recordset ein neuer Datensatz hinzugefügt. Durch den Aufruf von AddNew wird im internen Puffer ein leerer Datensatz erzeugt. Leer heißt, dass alle Felder den Wert NULL erhalten. Anschließend können den Feldern Werte zugewiesen werden. Nach einem Update werden die Daten in die zugrunde liegenden Tabellen geschrieben. Sub AddNewMethode() Dim db As DAO.Database Dim rst As DAO.Recordset Set db = CurrentDb() Set rst = db.OpenRecordset("tblCocktailLokal") With rst If .Updatable Then .AddNew !Cocktail = "Klare Sache" !Alkoholgehalt = 0# !Zubereitung = "Eiswürfel ins Glas geben, " & _ "Mineralwasser darübergießen, nicht umrühren." .Update End If End With rst.Close End Sub Die Eigenschaft LastModified Nach dem Bearbeiten eines Datensatzes mit Edit oder dem Hinzufügen mit AddNew steht der Positionszeiger nach der Ausführung von Update auf dem zuletzt aktuellen Datensatz. Möchten Sie später im Programm, wenn Sie den Positionszeiger weiterbewegt haben, zu dem zuletzt bearbeiteten Datensatz zurückspringen, können Sie dies mit rst.Bookmark = rst.LastModified durchführen. Alternativ können Sie auch folgenden Befehl verwenden: rst.Move 0, rst.LastModified 346 Datenzugriff mit Recordsets Status der Bearbeitung Es kann sinnvoll sein, den Status der Bearbeitung abzufragen. Mithilfe der Eigenschaft EditMode können Sie den aktuellen Stand erfahren. Die folgende Tabelle führt die Werte auf, die die Eigenschaft annehmen kann. Tabelle 11.6: Konstanten für den Bearbeitungsstatus Option Beschreibung dbEditNone gibt an, dass keine Bearbeitung eines Datensatzes durchgeführt wird. dbEditInProgress gibt an, dass der aktuelle Datensatz mit Edit bearbeitet wird, aber noch nicht gespeichert ist. dbEditAdd gibt an, dass ein neuer Datensatz hinzugefügt wurde, aber noch nicht gespeichert ist. Datensätze löschen Sie können den aktuellen Datensatz mithilfe der Methode Delete löschen. Der Positionszeiger verbleibt nach dem Löschvorgang auf dem gleichen, jetzt gelöschten Datensatz. Löschen ist in Access endgültig, ein per Programm gelöschter Datensatz kann nicht wiederhergestellt werden. Es besteht allerdings eine Ausnahme, wenn Sie mit Transaktionen arbeiten, denn solange eine Transaktion nicht abgeschlossen ist, kann eine Löschung, die innerhalb der Transaktion stattfand, rückgängig gemacht werden. Mehr zu Transaktionen erfahren Sie in Kapitel 18, »MultiuserZugriffe«. Oder doch besser SQL? Wir möchten Ihnen zu bedenken geben, dass sich alle Änderungen an Datensätzen auch mit SQL vornehmen lassen. Der SQL-Befehl UPDATE ermöglicht die schnelle Änderung von Datensatzgruppen, mit INSERT INTO können Sie neue Datensätze aufnehmen. In Abschnitt 11.5.4, »Parameterabfragen«, finden Sie die Funktion Alkoholgehalt(), die einmal mit Move-Befehlen und einmal mit SQL gelöst wurde. Insbesondere wenn Sie vorher mit dBase, FoxPro oder ähnlichen Datenbanken gearbeitet haben, sollten Sie sich mit den Möglichkeiten von SQL vertraut machen. 347 11 Datenzugriff mit DAO 11.4.8 Weitere Recordset-Methoden In diesem Abschnitt möchten wir Ihnen weitere Recordset-Methoden vorstellen. Die Methode GetRows( ) Mithilfe der Recordset-Methode GetRows() kann die Ergebnismenge eines Recordsets ganz oder teilweise in ein zweidimensionales Feld übertragen werden. Dabei wird GetRows() als Parameter die Anzahl der in das Array aufzunehmenden Zeilen übergeben. Ist die Zahl höher als die Anzahl der Datensätze im Recordset, wird das Array entsprechend dimensioniert. Durch UBound(var,2) + 1 kann die tatsächlich übertragene Anzahl bestimmt werden. Damit die Funktion UBound() die korrekte Anzahl von Zeilen des zweidimensionalen Arrays zurückgibt, muss als zweiter Parameter die Anzahl der Dimensionen des Arrays übergeben werden, so wie es unten im Beispiel durch die Konstante conDimension durchgeführt wird. Sub FillArray() Const conDimension = 2 Dim db As DAO.Database Dim rec As DAO.Recordset Dim varArr As Variant Dim intCount As Integer Set db = CurrentDb() Set rec = db.OpenRecordset("qryAnzahlCocktailZutaten", dbOpenSnapshot) ' Einlesen des kompletten Recordsets, Aktualisieren von RecordCount rec.MoveLast ' Zurück zum ersten Datensatz rec.MoveFirst ' Anfordern der Ergebnismenge des Recordsets varArr = rec.GetRows(rec.RecordCount) MsgBox Str(UBound(varArr, conDimension) + 1) " Zeilen eingelesen." rec.Close End Sub Beachten Sie beim Übertragen von Daten, dass insbesondere Memo- und OLEObjekt-Felder große Datenmengen beinhalten können, die dann mit GetRows() in den Hauptspeicher aufgenommen werden. Versucht die GetRows()-Methode auf einen Datensatz zuzugreifen, der zwischenzeitlich gelöscht wurde, bricht GetRows() ab, d. h., nicht alle angeforderten Datensätze werden übertragen. Überprüfen Sie daher mit 348 Datenzugriff mit Recordsets If UBound(varArr, conDimension) + 1 <> rec.RecordCount Then ' Nicht alle Datensätze eingelesen End If ob tatsächlich alle Datensätze im Array angekommen sind. Die Methode Clone( ) Die Clone()-Methode erstellt eine identische Kopie eines Recordsets. Dies ist beispielsweise hilfreich, wenn Sie Daten zweier Datensätze des Recordsets gleichzeitig verarbeiten müssen. Im folgenden Beispiel wird ein Recordset rec Datensatz für Datensatz durchlaufen. Für jeden Datensatz wird in einer Kopie des Recordsets, also in der gleichen Ergebnismenge, nach Datensätzen gesucht, die die gleiche Kategorie wie der Datensatz des Original-Recordsets haben. Sub TestRecordsetClone() Dim db As DAO.Database Dim rec As DAO.Recordset Dim recClone As DAO.Recordset Set db = CurrentDb() ' recordset enthält zwei Spalten: "CocktailNr" u. "KategorieNr" Set rec = db.OpenRecordset("tblCocktailKategorie", dbOpenSnapshot) ' Recordset klonen Set recClone = rec.Clone() While Not rec.EOF With recClone .FindFirst "KategorieNr = " & rec!KategorieNr While Not .NoMatch Debug.Print rec!CocktailNr _ & " hat die gleiche Kategorie wie " _ & !CocktailNr .FindNext "KategorieNr = " & rec!KategorieNr Wend .MoveFirst End With rec.MoveNext Wend rec.Close End Sub Die Methode Clone() bietet einen weiteren Zugriff auf die gleichen Daten, Sie erhalten aber eine weitere aktuelle Zeile und ein weiteres Lesezeichen (Bookmark). 349 11 Datenzugriff mit DAO Die Lesezeichen von Original und Klon sind austauschbar, d. h., eine Zuweisung wie recClone.Bookmark = rec.Bookmark ist zulässig. Die Methode Clone() ist eng verwandt mit der Methode RecordsetClone() für Formulare. In Kapitel 14, »Formulare«, beschreiben wir den Einsatz von RecordsetClone(). 11.5 Arbeiten mit QueryDefs Mit der OpenRecordset-Methode lassen sich, wie beschrieben, gespeicherte Auswahlabfragen öffnen oder SQL-Zeichenfolgen direkt eingeben. Für die Bearbeitung von Aktions-, Kreuztabellen-, Datendefinitions- und Parameterabfragen benötigen Sie QueryDef-Objekte. 11.5.1 Arbeiten mit QueryDef-Objekten Wir möchten Ihnen an einem kurzen Beispiel den Einsatz einer Aktualisierungsabfrage in einem Programm erläutern. Auf die entsprechende gespeicherte Abfrage wird über ihren Namen zugegriffen. Jede gespeicherte Abfrage ist Bestandteil der QueryDefs-Auflistung. Liefern Abfragen keine Datensätze zurück, sondern führen sie eine Aktion durch, werden sie mit der Methode Execute ausgeführt. Sub Aktionsabfragen() Dim db As DAO.Database Dim qry As DAO.QueryDef Dim rst As DAO.Recordset Set db = CurrentDb() ' Die Aktualisierungsabfrage "qupdAlkoholgehalt" bringt den ' Alkoholgehalt der Cocktails auf den neusten Stand Set qry = db.QueryDefs("qupdAlkoholgehalt") ' Ausführen der Abfrage qry.Execute Debug.Print "Betroffene Datensätze: "; qry.RecordsAffected End Sub 350 Arbeiten mit QueryDefs Versuchen Sie Auswahl-, Kreuztabellen- oder Union-Abfragen mit der Methode Execute auszuführen, erhalten Sie eine abfangbare Fehlermeldung. Das folgende Programm zeigt, wie aufgrund des Typs der Abfrage verzweigt werden kann. Sub Abfragen() Dim db As DAO.Database Dim qry As DAO.QueryDef Dim rst As DAO.Recordset Dim fld As DAO.Field Dim strQry As String Set db = CurrentDb() strQry = InputBox("Name der Abfrage") Set qry = db.QueryDefs(strQry) If qry.Type = dbQSelect Or qry.Type = dbQSetOperation _ Or qry.Type = dbQCrosstab Then Set rst = qry.OpenRecordset() While Not rst.EOF For Each fld In rst.Fields Debug.Print fld; Next Debug.Print rst.MoveNext Wend rst.Close Else qry.Execute Debug.Print "Betroffene Datensätze: "; qry.RecordsAffected End If End Sub Der Methode Execute kann ein Parameter mitgegeben werden, der die Aktionsabfrage steuert. Die folgende Tabelle zeigt die entsprechenden Konstanten. 351 11 Datenzugriff mit DAO Tabelle 11.7: Konstanten für Aktionsabfragen Eigenschaft Beschreibung dbDenyWrite verhindert, dass andere Benutzer während der Abfrage schreibend auf die der Abfrage zugrunde liegenden Tabellen zugreifen können. dbInconsistent führt auch inkonsistente Aktualisierungen durch. Dieses ist die Standardeinstellung. dbConsistent erzwingt konsistente Aktualisierungen. dbSQLPassThrough sorgt dafür, dass die SQL-Anweisung zur Verarbeitung an eine ODBC-Datenbank weitergereicht wird. dbFailOnError setzt Aktualisierungen zurück, wenn ein Fehler auftritt. dbSeeChanges löst einen Laufzeitfehler aus, wenn ein anderer Benutzer Daten ändert, die von der Abfrage bearbeitet werden. Wichtig ist insbesondere die Konstante dbFailOnError. Durch sie werden beim Auftreten eines Fehlers alle Änderungen, die die Aktionsabfrage bis zum Zeitpunkt des Fehlers durchgeführt hat, wieder zurückgesetzt. Direkter Einsatz Eine Aktionsabfrage lässt sich direkt ausführen, d. h., Sie geben dazu der Methode Execute() die in SQL formulierte Abfrage als Parameter mit. Es handelt sich hierbei allerdings um eine Methode der Datenbank, nicht um die eines QueryDef-Objektes. Im folgenden Beispiel werden alle Datensätze gelöscht, für die die angegebene Bedingung zutrifft. Sub DirekteAktionsabfrage() Dim db As DAO.Database Set db = CurrentDb() db.Execute( "DELETE * FROM tblCocktail WHERE CocktailNr > 1000;") End Sub Erweiterte Löschabfrage Das nächste Beispiel führt eine Löschabfrage aus. Die Besonderheit der Subroutine liegt in der Verwendung einer benutzerdefinierten Eigenschaft. In dieser soll abgelegt werden, wann die Löschabfrage zuletzt durchgeführt wurde. An die 352 Copyright Daten, Texte, Design und Grafiken dieses eBooks, sowie die eventuell angebotenen eBook-Zusatzdaten sind urheberrechtlich geschützt. Dieses eBook stellen wir lediglich als Einzelplatz-Lizenz zur Verfügung! Jede andere Verwendung dieses eBooks oder zugehöriger Materialien und Informationen, einschliesslich der Reproduktion, der Weitergabe, des Weitervertriebs, der Platzierung im Internet, in Intranets, in Extranets anderen Websites, der Veränderung, des Weiterverkaufs und der Veröffentlichung bedarf der schriftlichen Genehmigung des Verlags. Bei Fragen zu diesem Thema wenden Sie sich bitte an: mailto:[email protected] Zusatzdaten Möglicherweise liegt dem gedruckten Buch eine CD-ROM mit Zusatzdaten bei. Die Zurverfügungstellung dieser Daten auf der Website ist eine freiwillige Leistung des Verlags. Der Rechtsweg ist ausgeschlossen. Hinweis Dieses und andere eBooks können Sie rund um die Uhr und legal auf unserer Website (http://www.informit.de) herunterladen