manuel-r
Goto Top

Per VBScript und SQL auf Access-DB zugreifen

Ein fröhliches guten Morgen an die Scripting-Profis unter uns. Kann mir mal jemand mit ein oder zwei Codeschnippseln auf die Sprünge helfen?
Ich wurde gerne aus einem VBScript heraus eine vorhandene Access-Datenbank (bspw. datenbank.mdb) handlen und per SQL-Statement die üblichen Aktionen (bspw. select, insert, update, delete,...) ausführen. Google hat mir zwar ein paar Treffer geliefert, aber irgendwie steige ich als nicht VBS-Profi da nicht so ganz durch face-sad den SQL-Teil hingegen bekomme ich hin face-smile

Manuel

Content-ID: 116429

Url: https://administrator.de/contentid/116429

Ausgedruckt am: 23.11.2024 um 05:11 Uhr

Logan000
Logan000 20.05.2009 um 08:26:56 Uhr
Goto Top
Moin Moin

So sollte das in etwa funktionieren für Access 97- 2003. Bei Acc 2007 müste wohl der Connctstring etwas anders aussehen.

Const connectString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\mydatabase.mdb;User Id=admin;Password=;"  
Const adOpenStatic = 3
Const adLockOptimistic = 3
Const adUseClient = 3
Set objConnection = CreateObject("ADODB.Connection")  
Set objRecordset = CreateObject("ADODB.Recordset")  
objConnection.Open connectString			 
objRecordset.CursorLocation = adUseClient
objRecordset.Open "SELECT * FROM MyTable" , objConnection, adOpenStatic, adLockOptimistic  
Wert = objRecordSet("Feld1")   
objRecordset.Close

Noch ein hilfreicher Link: http://www.connectionstrings.com/

Gruß L.
manuel-r
manuel-r 20.05.2009 um 08:35:30 Uhr
Goto Top
Hallo Logan,
kannst du das vielleicht noch etwas kommentieren, damit ich es auch verstehe?
76109
76109 21.05.2009 um 15:50:16 Uhr
Goto Top
Hallo manuel-r,

anhand der folgenden Beispiele solltest Du es verstehen.

Der Code funktioniert jedoch nur mit Datenbanken ohne Passwort. Bei Datenbanken mit Passwort müssen noch ein paar Anweisungen eingefügt und in ACCESS eine Sicherheitsdatei *.mdw mit Benutzername und Benutzerpasswort erstellt werden.

Ideal währe es, wenn Du den Code in einem Excel-Modul einfügst und bei den Kommentaren Main Beg/End eine Sub Test/End einfügst, dann könntest Du den Code Debuggen und im ADO-Object einiges anhand der Einträge besser nachvollziehen.

Bei komplexen Abfragen, kann in ACCESS eine Abfrage im Entwurfsmodus erstellt und der SQL-Code in eine Datei kopiert werden, die dann im Code in einen Sql-String komplett eingelesen an die Routine OpenRecordset übergeben werden kann. Hierbei ist allerdings zu beachten, dass nur SQL-Kompatible Funktionen verwendet werden.

Hier noch zwei hilfreiche Links:

http://www.activevb.de/tutorials/tut_adokurs/adokurs.html
http://msdn.microsoft.com/en-us/library/ms677516(VS.85).aspx

Beispiel Test.Mdb - Tabelle1:

Feld1 Feld2 Feld3 Feld4 Feld5 Feld6
1 2a 3a 4a 5a 6a
2 2c 3c 4c 5c 6c
3 2d 3d 4d 5d 6d
(Auto)

Option Explicit

Const dbPath = "F:\Test\Test.mdb"  

Const adModeReadWrite = 3

Const adUseClient = 3
Const adOpenKeyset = 1
Const adLockOptimistic = 3

Dim dbCon, dbRec, Data, i

'Main Begin  

   'Datenbank öffnen  
    Call OpenRecordset("SELECT * FROM [Tabelle1]")  
    
   'Datensatz  
    Data = Array("Dummy AutoWert", "feld 2b", "feld 3b", "feld 4b", "feld 5b", "feld 6b")  

    With dbRec 'Datensatz Data in Feld2 bis Feld6 hinzufügen (Feld1 = AutoWert)  
       .AddNew
        For i = 1 To .Fields.Count - 1:  .Fields(i) = Data(i):  Next
       .Update
    End With

    With dbRec 'Alle Datensätze nacheinander auslesen  
      .Sort = "Feld2"  
      .MoveFirst
        Do Until .EOF
            For i = 0 To .Fields.Count - 1:  Data(i) = .Fields(i):  Next
            MsgBox Join(Data, ";")  
           .MoveNext
        Loop
    End With

    With dbRec 'Den Eintrag 'feld 3c' in Feld3 suchen  
        .MoveFirst
        .Find = "feld3 = 'feld 3c'"  
         If .EOF Then
            MsgBox "Nicht gefunden."  
         Else
            MsgBox "Gefunden Zeile: " & .AbsolutePosition  
         End If
    End With
         
   'Alternativ direkte SQL-Anweisungen ausführen  
    dbCon.Execute "INSERT INTO Tabelle1 (Feld2) VALUES ('Hallo')"  
    dbCon.Execute "DELETE FROM Tabelle1 WHERE Feld2 = 'Hallo'"  
    dbCon.Execute "SELECT Tabelle1.* FROM Tabelle1 ORDER BY Tabelle1.feld2;"  

   'Datenbank und Recordset schließen  
    dbRec.Close:   dbCon.Close

   'WScript.Quit  
    
'Main End  


Private Sub OpenRecordset(ByRef dbSql)
    
    Set dbCon = CreateObject("ADODB.Connection")  
    Set dbRec = CreateObject("ADODB.Recordset")  
    
    With dbCon 'Verbindung zur Datenbank herstellen  
        .Mode = adModeReadWrite
        .CursorLocation = adUseClient
        .Provider = "Microsoft.Jet.OLEDB.4.0"  '*.mdb  
       '.Provider = "Microsoft.ACE.OLEDB.12.0" '*.accdb ACCESS 2007  
        .Properties("Data Source") = dbPath  
        .Properties("Persist Security Info") = False  
        .Open
    End With
    
    With dbRec 'Einen Recordset für die Datensätze erstellen  
        .Source = dbSql
        .ActiveConnection = dbCon
        .CursorLocation = adUseClient
        .CursorType = adOpenKeyset
        .LockType = adLockOptimistic
        .Open
    End With
End Sub

Gruß Dieter
manuel-r
manuel-r 25.05.2009 um 08:35:54 Uhr
Goto Top
Danke für das Beispielscript Dieter.
Ich hab's jetzt mal getestet, einige Dinge auf meine Bedürfnisse angepasst usw - und ich hab's wohl auch verstanden.
Eine Frage stellt sich mir aber noch:
Wenn ich ein SELECT (in SQL) ausführe müssen die Ergebnisse doch in irgendeinem Array stehen. In welchem? Gibt es auch einen Befehl der etwa das gleiche macht wie unter PHP mysql_affected_rows?
Ich muss beim Schreiben von Datensätzen die UNIQUE-Felder haben ja vorher prüfen ob es den Datensatz schon gibt. Je nachdem muss ich ja entweder ein INSERT oder UPDATE machen.

Manuel

EDIT:
Hab's schon selbt raus gefunden
If dbRec.Recordcount > 0 Then
  strSQL = "UPDATE " & dbTab1 & " SET Nutzer = 'geändert' WHERE Nummer = '" & strNummer & "'"  
  dbCon.Execute strSQL
Else
  strSQL = "INSERT INTO " & dbTab1 & " (Nummer, Nutzer) VALUES ('1111111111', 'ein Test')"  
  dbCon.Execute strSQL
End If
76109
76109 25.05.2009 um 10:22:05 Uhr
Goto Top
Hallo manuel-r,

Meine SQL-Kenntnisse sind sehr bescheiden und hier auch nur in geringem Umfang erforderlich, da der ganze Ablauf über Recordset-Funktionen ausgeführt werden kann (siehe Links).

Beim Lesen und Schreiben über Recordset, können Felder auch über den Feldnamen angesprochen werden z.B:
With dbRec 'Datensatz hinzufügen   
     .AddNew
     .Fields("Feld1") = "ab"  
     .Fields("Feld2") = "xy"  
     ..........
    .Update
End With

Mit den folgenden Anwesungen können die aktuelle Zeilen-Position und die Anzahl der Datensätze abgefragt werden:
Pos = dbRec.AbsolutePosition 'Zeilen-Position lesen/setzen  
Cnt = dbRec.RecordCount 'Anzahl Datensätze  

Mit der Funktion <dbRec.Find .....> kann geprüft werden, ob ein Datensatz schon vorhanden ist.

Gruß Dieter
manuel-r
manuel-r 25.05.2009 um 10:27:38 Uhr
Goto Top
Danke, ich hab's ja schon (s. oben). dbRec.Recordcount liefert mir die Anzahl der mit der vorangegangenen Abfrage gelieferten Datensätze. Somit weiß ich also nach einem SELECT ob es den Datensatz schon gibt (recordcount = 1) und kann dann per IF entweder ein UPDATE oder INSERT ausführen.

Manuel
76109
76109 25.05.2009 um 10:31:49 Uhr
Goto Top
Hallo manuel_r,

Zitat von @manuel-r:
Danke, ich hab's ja schon (s. oben). dbRec.Recordcount
liefert mir die Anzahl der mit der vorangegangenen Abfrage gelieferten Datensätze.

Yepface-smile

Gruß Dieter
76109
76109 25.05.2009 um 10:58:10 Uhr
Goto Top
Hallo nochmal,

also, ich habe das nochmal getestet und festgestellt, dass das so nicht funktioniert, weil die SQL-Anweisungen über <dbCon.Execute> nicht vom Recordset erfasst werden. D.h. die Recordset-Funktionen AbsolutePosition und RecordCount werden nur aktualisiert, wenn die Datenbank über den Recordset gelesen oder beschrieben wird.

Das bedeutet, wenn Du Execute SQL verwendest, musst Du alles über SQL selbst steuern. Inwieweit das funktioniert, habe ich leider keine Ahnung.

Gruß Dieter
manuel-r
manuel-r 25.05.2009 um 14:59:36 Uhr
Goto Top
Miffft. Klappt doch nicht so einfach face-sad
Hast du vielleicht mal eben noch den passenden Code für das UPDATE eines Datensatzes analog zu
With dbRec 'Datensatz hinzufügen   
     .AddNew
     .Fields("Feld1") = "ab"  
     .Fields("Feld2") = "xy"  
     ..........
    .Update
End With
Manuel
Logan000
Logan000 25.05.2009 um 15:13:06 Uhr
Goto Top
Moin Moin

Wenn dein SQL Statement nur einen Datensatz holt, reicht es einfach das
    .AddNew
wegzulassen.

Gruß L.
manuel-r
manuel-r 25.05.2009 um 15:18:53 Uhr
Goto Top
*kopfkratz*
Irgendwie muss ich aber doch ein WHERE mitgeben - oder eine Zeilennummer irgendwas halt.
Wenn ich bspw. eine Tabelle mit
    • feld1, feld2, feld3
    hab und darin dann die Werte
    • abc1, cde, fgh1
    • abc2, cde, fgh2
    • abc3, cde, fgh3
    Wenn ich jetzt in der Zeile mit dem abc2 den Wert cde ändern will, dann muss ich doch ein WHERE feld1 = 'abc2' (oder ähnlich) übergeben.

    Manuel
76109
76109 25.05.2009 um 16:37:10 Uhr
Goto Top
Hallo manuel-r,

also, beim ändern von Daten - wie von Logan geschrieben - einfach das AddNew weglassen.

wenn Du nur einen bestimmten Datensatz ansprechen möchtest, dann übergebe den SQL-String "Select + Where" in der Anweisung:
OpenRecordset("Select ...Where").  

Ansonsten hast Du, wie bei meinem SQL-OpenRecordset alle Datensätze, die Du über MoveFirst bzw MoveNext
nacheinander ausliest und z.B. einen IF-Test machen kannst:
...
 If LCase(.Fields("Feld1")) = LCase("abc2") Then .Fields("Feld2") = "was anderes"  
.MoveNext
...
oder Du verwendest besser das Find-Beispiel:
.Find = "feld1 = 'abc2'"  


Wenn gefunden, dann befindet sich die AbsolutePosition auf dieser Datensatz-Zeile (EOF = False)
Wenn nicht gefunden, dann ist EOF = True

Kommst Du damit klar?

Gruß Dieter