Excel und RecordSet(SELECT ....) nur ReadOnly
#11
Moinsen,

für mich ergibt sich aus deinen vielen Beiträgen noch kein guter Zusammenhang. Und ein einheitliches Fehlerbild kann ich auch nicht erkennen. Einen Objektverweis auf Nothing zu setzen ist dem Objekt im Zweifel egal. Im konkreten Beispiel hilft vielleicht die Onlinehilfe weiter. Die .OpenRecordset-Methode von DAO hat hat mehrere Parameter, darunter den Type, der den Zugriff auf die einzelnen Records des Recordsets festlegt und den LockEdit-Parameter, der bestimmt, wie mit parallelen Zugriffen umgegangen werden soll. insbsesondere den LockType, der festlegt, wie mit parallelen Zugriffen umgegangen werden soll. Dabei geht es aber eher um (auch) schreibende Zugriffe. Wenn ich das richtig sehe, willst du aber ein ReadOnly Recordset verwenden. Hierzu gibt es den Parameter Options, der du unter anderem den dbReadOnly Wert zuweisen kannst.
Doku bei Microsoft

Deinen anderen Beiträgen entnehme ich, dass du gelegentlich noch einen Access-Prozess beenden musst. Mit welchem Treiber greifst du auf die Datenbank zu?

Viele Grüße
derHöpp
Antworten Top
#12
@derHöpp:

Das ist alles schon gesagt, beantwortet und erklärt worden. Wo fehlt dir da der Zusammenhang? Das es sich um DAO handelt, ist bereits in in der Fragestellung erwähnt worden.

Bei einer MDB-Datenbankdatei ist es eigentlich egal, ob die DAO 3.6 Engine oder die neuere Access Database Engine verwendet wird, allerdings wird das neuere Datenbankformat ACCDB nur von letzterem unterstützt.

Gruß
Ulrich
Antworten Top
#13
... vielleicht kann man noch darauf hinweisen - auch wenn das schon geschrieben wurde - dass es da um Parameter für das Recordset geht.
Es geht nicht um SQL-Befehle. Ich vermute, dass es für den TE bei den "abgekürzten" SQL-Befehlen um weggelassene Recordset - Parameter gehen könnte. Das für bestimmte Aktionen bestimmte Parameter Voraussetzung sein können, sei mal dahingestellt.

Wenn es um Geschwindigkeit geht, ist oftmals auch Excel die Bremse - z.B., weil die Daten einzeln abgegriffen und irgendwo in Zellen gepackt werden.
Man kann ein Recordset aber auch komplett in ein Array holen, z.B. mit arrDyna() = objDynaset.GetRows()
Es ist auch relevant, ob Du auf mehrere Tabellen zugreifen musst oer ob Du eine Art "View" hast, der dir die Daten schon aufbereitet bereitstellt.
.      \\\|///      Hoffe, geholfen zu haben.
       ( ô ô )      Grüße, André aus G in T  
  ooO-(_)-Ooo    (Excel 97-2019+365)
[-] Folgende(r) 1 Nutzer sagt Danke an schauan für diesen Beitrag:
  • Stefan1
Antworten Top
#14
Ich habe zusätzlich zu dbOpenForwardOnly im Zusammenspiel mit MoveNext oder nur einmaligen Treffersuche nun auch das dbOpenSnapshot im Zusammenspiel mit MoveFirst oder mehreren nicht indexierten Treffer beim OpenRecordSet (DAO) erfolgreich eingebaut bei Anwendungen Word/Excel mit VBA-Zugriff auf Access-Datenbanken. Besonders da wo dbOpenForwardOnly jetzt zum Einsatz kommt, sind die Abfragen spürbar schneller und ich würde sagen das zusätzliche Attribute dient auch der Stabilität allgemein. Wahrscheinlich könnte man noch besser optimieren und ich kann mir MoveNext bei mehreren Treffern oder auch MoveFirst den Vorteil bzw. Anwending nicht ganz vorstellen, weil bislang in einem Loop durchaus erfolgreich eines dieser beiden möglichen Attribute fehlen und doch Treffer erfolgen. Ich muss dazu sagen, dass ich die VBA-Programmierung nicht ursprünglich angelegt habe. Es ist quasi ein "Erbstück2. Dann frage ich mich, was denn der Vorteil von MoveFrist oder MoveNext den sein könnte (wieso nicht weglassen), höchstens bei einer vorgängigen Sortierung nach einem Kriterium noch verständlich. Zur Sicherheit und fehlerfreien Abarbeitung belasse ich es bei entsprechenden Kriterien beim dbOpenSnapshot, wenn das auch geringfügig langsamer ist als dbOpenForwardOnly und doch immer noch wesentlich schneller als der Defaultwert dbOpenDynaset, auch beim Fehlen dieser Eigenschaft.

Nochmals Danke an Euch für die Unterstützung. Den Vorschlag mit arrDyna() = objDynaset.GetRows() werde ich noch studieren, der ist interessant. Ob ein ReadOnly im DAO-Verfahren noch sinnvoll angewendet werden kann, bin nicht sicher ob das MultiUser-Anwendung oder eben die Datenaktualisierung (Neu, Mutation) von einer Drittanwendung einen Vorteil bringen könnte?
Antworten Top
#15
Hallo Stefan,

je weniger Ressourcen ein Objekt verbraucht, desto effizienter kann es sein. Wenn also ein Recordset nur ForwardOnly unterstützen muss, ist das natürlich ressourcenschonender als wenn das Recordset Locks, mögliche Updates und konkurrierende Zugriffe verwalten muss.

Grundsätzlich geht es ja um Zugriffe per SQL auf die Daten, auch wenn man nur Tabellen angeben kann. SQL hat viel mit Mengen zu tun und die Ergebnismenge einer solchen Abfrage wird in einem Recordset zugänglich gemacht bzw. verwaltet. Mit seinen Methoden Move... wird dann der Cursor entsprechend der Move-Methode innerhalb des Recordsets datensatzweise weiter bewegt. Will man also alle Datensätze der Ergebnismenge nacheinander ansprechen, geht das mit diesen Move-Methoden innerhalb einer Schleife.

Zusätzlich gibt es beim DAO Recordset auch die Möglichkeit, mit GetRows() mehrere DS als Array abzurufen (näheres in der Doku).

In Excel gibt es außerdem auch noch eine Methode Range.CopyFromRecordset, womit ein Recordset einer Range zugewiesen werden kann. 
Hinweis dazu: das funktioniert nur bedingt fehlerfrei bei großen Ergebnismengen.

Gruß
Knobbi38
[-] Folgende(r) 1 Nutzer sagt Danke an knobbi38 für diesen Beitrag:
  • Stefan1
Antworten Top
#16
Guten Tag miteinanderarr

Kann mit  dbOpenForwardOnly oder dbOpenSnapshot auch arrDyna() = objDynaset.GetRows() abgerufen werden oder ist das nur mit dbOpenDynaset möglich?

Das arrDyna() soll als Variant deklariert (Dim arrDyna() as Variant) sein und bei mehreren Treffer soll es Transponiert im Array sein. Was ist bei einem einzelnen Treffer? Wahrscheinlich nicht transponiert? Wie kann man das mit VBA sauber abfangen und mit einer Schlaufe auslesen. Da findet sich fast kein wirklich saubes Beispiel, das auch rasch und sicher ist.

Gruss
Stefan1
Antworten Top
#17
Hallo Stefan,

anbei mal ein Beispiel, wie eine Tabelle aus eines Access Datenbank Via DAO in ein Array (arr) geladen wird und in einer Listbox (Control in Userform) ausgegeben wird.

Der Arrayinhalt ist prinzipbedingt in den Koordinaten vertauscht und wird deshalb via .Column in die Listbox geladen.
Wenn dies für den restlichen nachfolgenden Code falls vorhanden stört, kann man bei kleineren Datenmengen Application.Transpose nutzen.
Bei großen Datenaufkommen ist es besser den nachfolgenden Code entsprechend anpassen. (Early Binding und gerade durch ist das bessere Timing).
Code:
Option Explicit
    Private db As DAO.Database
    Private rs As DAO.Recordset

Private Sub AusAccessLesen()
    Dim i&, j&, k&, arr()
    ' Verweis auf Microsoft Office 16.0 Access Database Engine Object Library erforderlich da Early Binding
    Set db = OpenDatabase("C:\MeineDatenbank.accdb", False, False, ";PWD=MeinGeheimesPasswort")
    Set rs = db.OpenRecordset("MeinTabellenName", dbOpenDynaset)
    With rs
        Do Until .EOF
            k = k + 1
            ReDim Preserve arr(1 To .Fields.Count, 1 To k)
            For j = 0 To rs.Fields.Count - 1
                If Not rs(j) = "Null" Then arr(j + 1, k) = rs(j)
            Next j
            .MoveNext
        Loop
        If (.EOF And .BOF) = False Then
            With ListBox1
                .ColumnCount = rs.Fields.Count
                .Column = arr
            End With
            .MoveFirst
        End If
    End With
    rs.Close
    db.Close
    Set rs = Nothing
    Set db = Nothing
End Sub

Private Sub UserForm_Initialize()
    AusAccessLesen
End Sub
Es ist etwas Datenbank Missbrauch was ich dir zeige. Normalerweise holt man sich nur das was gebraucht wird, verarbeitet es und schreibt die Änderungen wieder zurück.

Gruß Uwe
[-] Folgende(r) 1 Nutzer sagt Danke an Egon12 für diesen Beitrag:
  • Stefan1
Antworten Top
#18
Moin Ulrich,

(06.11.2024, 12:54)knobbi38 schrieb: @derHöpp:

Wo fehlt dir da der Zusammenhang?
In einem der vorherigen Threads ging es darum, dass nach der Nutzung von DAO ein übrig-gebliebener Access-Prozess gekillt werden müsste. Aber egal, was ich anstelle, ich schaffe es nicht, dass bei der Verwendung von DAO aus Excel oder Word heraus überhaupt ein Access-Prozess gestartet würde.
In diesem Thread sollte es eigentlich darum gehen, dass mehrere User auf die Datenbank zugreifen können sollen. Das bedeutet für mich (wie in deiner ersten Antwort beschrieben), dass der Options-Parameter von .OpenDatabase() auf False gesetzt wird (was standard ist) um einen exklusiven Zugriff zu verhindern. Gegebenenfalls kann man mit dem ReadOnly-Parameter das Schreiben von Anfang an verhindern (über Options) oder parallelle Zugriffe regeln (oder den Locktype). Alternativ lässt sich die Beschränkung auf das Lesen noch im Recordset festlegen, in dem entweder die Options.

Mittlerweile geht es um den Type des Recordsets, der bestimmt meiner Kenntnis nach aber nur das Verhalten des Cursors und hat nichts mit ReadOnly oder einem übriggebliebenen Prozess zu tun.

Aber wahrscheinlich geht es momentan nur mir so, dass ich das gedanklich nicht übereinbekomme.

Viele Grüße
derHöpp
[-] Folgende(r) 1 Nutzer sagt Danke an derHoepp für diesen Beitrag:
  • Stefan1
Antworten Top
#19
Hallöchen,

da ist sicher auch Deine Experimentierfreude gefragt...
Wenn man das Recordset nicht transponiert übergeben kann dann könnte man auch im zweiten Schritt das array in ein weiteres transponieren.

Wenn eine Abfrage nur einen einzelnen Datensatz ergibt, dann braucht es kein Array, man kann es trotzdem verwenden.
Wenn sicher ist, dass z.B. nur ein einzelner Feldinhalt zurückgegeben wird, nimmt man es natürlich auch nicht.

PHP-Code:
Dim arrDyna()
Set objDynaset = New ADODB.Recordset
objDynaset
.Open sql_stringDbaseadOpenForwardOnlyadLockReadOnly
If Not objDynaset.EOF Then
  arrDyna
() = objDynaset.GetRows()
End If 

Wenn Du das Array in einen Zellinhalt übergeben willst, und irgendwo hast Du einen Feldinhalt "Null" - damit meine ich nicht 0 - geht das nicht und Du musst die Daten in einer Schleife übertragen.

PHP-Code:
objDynaset.MoveFirst
  
'Daten ab Zeile 2
  While Not objDynaset.EOF
    For xCnt = 0 To objDynaset.Fields.Count - 1
      .Cells(yCnt + 2, xCnt + 1 + iOffset) = objDynaset.Fields(xCnt).Value
    Next
    objDynaset.MoveNext
    yCnt = yCnt + 1
  Wend 

Brauchst Du die Spaltenüberschriften aus der Datenbank, musst Du diese ggf. gesondert abrufen, im Prinzip

PHP-Code:
objDynaset.MoveFirst
  
'Spaltenbeschriftung in Zeile 1
  For xCnt = 0 To objDynaset.Fields.Count - 1
    .Cells(1, xCnt + 1 + iOffset) = objDynaset.Fields(xCnt).Name
    .Cells(1, xCnt + 1 + iOffset).Font.Bold = True
  Next 

...
.      \\\|///      Hoffe, geholfen zu haben.
       ( ô ô )      Grüße, André aus G in T  
  ooO-(_)-Ooo    (Excel 97-2019+365)
[-] Folgende(r) 1 Nutzer sagt Danke an schauan für diesen Beitrag:
  • Stefan1
Antworten Top
#20
Hallo Andrè,
 
das ist natürlich auch eine Möglichkeit. Das kann man auch mit If Not IsNull(... prüfen. Da wird es vermutlich noch mehrere Lösungsmöglichkeiten geben.
 
Gruß Uwe
[-] Folgende(r) 1 Nutzer sagt Danke an Egon12 für diesen Beitrag:
  • Stefan1
Antworten Top


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste