VBA - Retrieve multiple RecordSets from SQL query - vba

I have a Stored Procedure on the SQL Server and I pull the results via VBA (Library: MS ActiveX Data Objects Library, ADODB).
Everything works fine when I only expect the query to return the result for 1 SELECT statement.
Now the Query consists of 5 SELECT statements and I want get all records from each recordset to be put into an array so I can work with the data. I am not able to do so, please help me further.
SQL Query results look like this in SQL Server Management Studio:
I tried different approaches in VBA, but non is working and will lead to different errors.
Error Numbers are either "3251", "3704" or "91".
This is my function to put the results into a RecordSet:
Function getAnalysisInformationFromDB(ByRef rs As Recordset, ByVal sSQL As String) As Boolean
On Error GoTo errHandler
Set cnn = New ADODB.Connection
cnn.Open conString
Set rs = cnn.Execute(sSQL)
rs.MoveFirst
getAnalysisInformationFromDB = True
Exit Function
errHandler:
Dim sErrMsg As String
If Err Then
If Not cnn Is Nothing Then
If cnn.Errors.Count > 0 Then
Dim i As Integer
For i = 0 To cnn.Errors.Count - 1 Step 1
sErrMsg = sErrMsg & cnn.Errors.Item(i) & vbCrLf
Next
End If
End If
If sErrMsg = "" Then
If Err.Number = 3021 Then
sErrMsg = "AnalysisID not found in DB"
Else
sErrMsg = Err.Number & " " & Err.Description
End If
End If
End If
If sErrMsg <> "" Then
MsgBox sErrMsg, vbCritical
End If
If Not cnn Is Nothing Then
If cnn.State = adStateOpen Then cnn.Close
End If
Set cnn = Nothing
End Function
Different approaches no look like this:
Sub getData()
Dim sSQL As String
sSQL = "confidential" ' --> SQL Connection String etc...
Dim rsAnalysis
If Not getAnalysisInformationFromDB(rsAnalysis, sSQL) = True Then Exit Sub
Dim vHeader() As Variant
Dim vData() As Variant
Dim rsTemp
Do Until rsAnalysis Is Nothing
Set rsTemp = rsAnalysis.NextRecordset()
vData = rsTemp.GetRows
' Do something with the Array...
' ...
Loop
End Sub
Or (here it does not even jump to the error handler, eventhough an error occurs...):
Sub getData2()
Dim rsAnalysis
If Not getAnalysisInformationFromDB(rsAnalysis, sSQL) = True Then Exit Sub
Do Until rsAnalysis Is Nothing
rsAnalysis.MoveFirst
On Error GoTo check_RS
Dim iCount As Integer: iCount = -1
For Each s In rsAnalysis.Fields
iCount = iCount + 1
ReDim Preserve vHeader(iCount): vHeader(iCount) = s.name
Next
If Not rsAnalysis.BOF And Not rsAnalysis.EOF Then
vData = rsAnalysis.GetRows
End If
Stop
Erase vHeader
retry_RS:
Set rsAnalysis = rsAnalysis.NextRecordset()
Loop
check_RS:
If Err Then
Debug.Print Err.Number
If Err.Number = 91 Or Err.Number = 3704 Or Err.Number = 3251 Then
GoTo retry_RS
End If
End If
End Sub
edit: the error always happens when I try to hand over the recordset to the array variable (vData = rsAnalysis.GetRows)

Related

How to auto-backup Access Database

I want to autoback up my access database with the below code and it didn't work for me. I got an error "cannot find the input table or query "WinAutoBackup" Please view the picture. Also, did I use CurrentProject correctly?
[Function fMakeBackup() As Boolean
Dim Source As String
Dim Target As String
Dim retval As Integer
On Error GoTo sysBackup_Err
Source = CurrentDb.name
Target = "CurrentProject.path\backups\"
Target = Target & Format(Now, "yyyymmdd-hhnn") & ".accdb"
If DateDiff("d", DLookup("\[BackupDate\]", "WinAutoBackup", "\[BckID\]
=1"), Date) = 3 Then
retval = 0
Dim objFSO As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
retval = objFSO.CopyFile(Source, Target, True)
Set objFSO = Nothing
DoCmd.SetWarnings False
DoCmd.RunSQL "UPDATE WinAutoBackup SET WinAutoBackup.BackupDate =
Date();"
DoCmd.SetWarnings True
MsgBox "Backup successfull. Next auto backup in 3 days"
Else
Exit Function
End If
sysBackup_Exit:
Exit Function
sysBackup_Err:
MsgBox Err.Description, , "sysBackup()"
Resume sysBackup_Exit
End Function][1]
Start with including:
Option Explicit
at the top of the module.
Then try with:
Function fMakeBackup() As Boolean
Dim objFSO As Object
Dim Source As String
Dim Target As String
Dim retval As Integer
' Disable error handling during development.
' On Error GoTo sysBackup_Err
Source = CurrentDb.Name
' Adjust if if backup folder is not \backups\.
Target = CurrentProject.Path & "\backups\"
Target = Target & Format(Now, "yyyymmdd-hhnn") & ".accdb"
' To run every time, use this line in plade of If DateDiff ...:
' If True Then
If DateDiff("d", DLookup("[BackupDate]", "[WinAutoBackup]", "[BckID] = 1"), Date) >= 3 Then
Set objFSO = CreateObject("Scripting.FileSystemObject")
retval = objFSO.CopyFile(Source, Target, True)
Set objFSO = Nothing
DoCmd.SetWarnings False
DoCmd.RunSQL "UPDATE WinAutoBackup SET WinAutoBackup.BackupDate = Date() WHERE [BckID] = 1;"
DoCmd.SetWarnings True
MsgBox "Backup successful. Next auto backup in 3 days."
End If
sysBackup_Exit:
Exit Function
sysBackup_Err:
MsgBox Err.Description, , "sysBackup()"
Resume sysBackup_Exit
End Function

MS Word Drop down list or combo box from MS Access Database

I'm trying to populate a combo box or drop down list from an access database. I used the following website for code template. I modified it to suit my needs. I keep getting the error: 5941 The requested member of the collection does not exist"
Source code: http://www.fontstuff.com/mailbag/qword02.htm
My Code:
Private Sub Document_Open()
On Error GoTo Document_Open_Err
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=*path to database removed for post*;"
rst.Open "SELECT DISTINCT TOP 25 [Equipment] FROM tblEquipment ORDER BY [Equipment];", _
cnn, adOpenStatic
rst.MoveFirst
With ActiveDocument.FormFields("Equipment").DropDown.ListEntries
.Clear
Do
.Add rst![Equipment]
rst.MoveNext
Loop Until rst.EOF
End With
Document_Open_Exit:
On Error Resume Next
rst.Close
cnn.Close
Set rst = Nothing
Set cnn = Nothing
Exit Sub
Document_Open_Err:
MsgBox Err.Number & vbCrLf & Err.Description, vbCritical, "Error!"
Resume Document_Open_Exit
End Sub
Code that almost works:
Private Sub Document_Open()
On Error GoTo Document_Open_Err
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=*removed for post*;"
rst.Open "SELECT DISTINCT TOP 25 [Field1] FROM Equipment_List ORDER BY [Field1];", _
cnn, adOpenStatic
rst.MoveFirst
With ActiveDocument.FormFields("Equipment").DropDown.ListEntries
.Clear
Do
.Add rst![Field1]
rst.MoveNext
Loop Until rst.EOF
End With
Document_Open_Exit:
On Error Resume Next
rst.Close
cnn.Close
Set rst = Nothing
Set cnn = Nothing
Exit Sub
Document_Open_Err:
MsgBox Err.Number & vbCrLf & Err.Description, vbCritical, "Error!"
Resume Document_Open_Exit
End Sub
I'm updating my last post here. See the code below; set a reference to DAO and make a couple minor tweaks to suit your needs.
Option Explicit
'Requires a reference to the '"Microsoft DAO 3.51 (or 3.6) Object Library."
Private Sub Userform_Initialize()
Dim myDataBase As DAO.Database
Dim myActiveRecord As DAO.Recordset
Dim i As Long
'Open the database to retrieve data
Set myDataBase = OpenDatabase("D:\Data Stores\sourceAccess.mdb")
'Define the first recordset
Set myActiveRecord = myDataBase.OpenRecordset("Table1", dbOpenForwardOnly)
'Set the listbox column count
ListBox1.ColumnCount = myActiveRecord.Fields.Count
i = 0
'Loop through all the records in the table until the EOF marker is reached.
Do While Not myActiveRecord.EOF
'Use .AddItem method to add a new row for each record
ListBox1.AddItem
ListBox1.List(i, 0) = myActiveRecord.Fields("Employee Name")
ListBox1.List(i, 1) = myActiveRecord.Fields("Employee DOB")
ListBox1.List(i, 2) = myActiveRecord.Fields("Employee ID")
i = i + 1
'Get the next record
myActiveRecord.MoveNext
Loop
'Close the database and clean-up
myActiveRecord.Close
myDataBase.Close
Set myActiveRecord = Nothing
Set myDataBase = Nothing
lbl_Exit:
Exit Sub
End Sub
Private Sub CommandButton1_Click()
Dim oRng As Word.Range
Dim oBM As Bookmarks
Set oBM = ActiveDocument.Bookmarks
Set oRng = oBM("EmpName").Range
oRng.Text = ListBox1.Text
oBM.Add "EmpName", oRng
Set oRng = oBM("EmpDOB").Range
oRng.Text = ListBox1.List(ListBox1.ListIndex, 1)
oBM.Add "EmpDOB", oRng
Set oRng = oBM("EmpID").Range
oRng.Text = ListBox1.List(ListBox1.ListIndex, 2)
oBM.Add "EmpID", oRng
Me.Hide
lbl_Exit:
Exit Sub
End Sub
Code Source:
https://gregmaxey.com/word_tip_pages/populate_userform_listbox_or_combobox.html

Import a query from Access into Excel based on an adjustable input

I want to import a query from Access to an Excel Spreadsheet. I would like the code to be adjustable sp that on sheet 1 in cell B9 I can type the name of the query as it appears in Access. So anytime I want to import a new query I just have to change the name in B9. My current VBA hardcodes the name of the query and I am not sure how to change this. This is what I have so far which imports the specific query listed.
Sub GetQuery()
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim i As Long
Dim wsh As Worksheet
Set dbs = DBEngine.OpenDatabase("C:\Desktop\DataProject\Database.accdb")
Set rst = dbs.OpenRecordset("Query One")
Set wsh = Worksheets("Sheet1")
For i = 0 To rst.Fields.Count - 1
wsh.Cells(1, i + 1).Value = rst.Fields(i).Name
Next
wsh.Range("A1").Resize(ColumnSize:=rst.Fields.Count).Font.Bold = True
wsh.Range("A2").CopyFromRecordset rst
rst.Close
Set rst = Nothing
dbs.Close
Set dbs = Nothing
End Sub
Any help would be appreciated!
Well, not sure if this is really useful, but maybe you can adap it to your needs:
Option Explicit
Dim ValueB9 As String
Private Sub Worksheet_Calculate()
If ThisWorkbook.Worksheets("Sheet1").Range("B9").Value = "" Or ThisWorkbook.Worksheets("Sheet1").Range("B9").Value = ValueB9 _
Or Left(ThisWorkbook.Worksheets("Sheet1").Range("B9").Formula, 1) <> "=" Then
Exit Sub
Else
On Error GoTo ErrorHandle:
ValueB9 = ThisWorkbook.Worksheets("Sheet1").Range("B9").Value
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim i As Long
Dim wsh As Worksheet
Set dbs = DBEngine.OpenDatabase("C:\Desktop\DataProject\Database.accdb")
Set rst = dbs.OpenRecordset(ValueB9)
Set wsh = Worksheets("Sheet1")
For i = 0 To rst.Fields.Count - 1
wsh.Cells(1, i + 1).Value = rst.Fields(i).Name
Next
wsh.Range("A1").Resize(ColumnSize:=rst.Fields.Count).Font.Bold = True
wsh.Range("A2").CopyFromRecordset rst
rst.Close
Set rst = Nothing
dbs.Close
Set dbs = Nothing
End If
Exit Sub
ErrorHandle:
If Err.Number = 3078 Then
MsgBox "Query name is wrong"
Else
MsgBox Err.Description, vbCritical, "Error number " & Err.Number
End If
End Sub
This code will trigger every time you input the name of your query in cell B9 in Sheet1. You have to input the name in the cell like this:
="YOUR QUERY NAME"
If you don't type it like a formula, (for example, if you just type the name of the query) it won't trigger. If you type wrong the query name, it will throw error.
Try to adapt it to your needs.

Export Each Access Table To Individual Workbook

I have been using this syntax which will export every table in a database to ONE excel workbook, but now my needs are to export every table to it's own workbook. How could this be tweaked to export each table to it's own workbook?
Sub ExportToExcel()
Dim td As DAO.TableDef, db As DAO.Database
Dim out_file As String
out_file = "C:\fromaccess.xlsx"
Set db = CurrentDb()
For Each td in db.TableDefs
If Left(td.Name, 4) = "MSys" Then
'Do Nothing
Else
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, td.Name, out_file, True, Replace(td.Name, "dbo_","")
End If
Next
End Sub
EDIT
I tried the suggestion by #HA560 but get an error of
Run-time error '91':
Object variable or With block variable not set
This is updated code:
Sub ExportToExcel()
Dim td As DAO.TableDef, db As DAO.Database
Dim out_file As String
Dim xl As Excel.Application
out_file = "C:\fromaccess.xlsx"
Set db = CurrentDb()
For Each td in db.TableDefs
xl.Workbooks.Add
If Left(td.Name, 4) = "MSys" Then
'Do Nothing
Else
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, td.Name, out_file, True, Replace(td.Name, "dbo_","")
End If
Next
End Sub
Bit of a long one which includes a three procedures. After running you should have a list of table names and TRUE/FALSE in the immediate window saying whether the export was successful.
ExportAll - The main procedure.
CreateXL - this creates an instance of Excel. It uses late binding, so no need to set references.
QueryExportToXL - this is the code to export the table. I haven't used TransferSpreadsheet as I like more control.
You need to pass a worksheet reference to the function.
You can pass either a query name or a recordset to the function.
You can pass an alternative sheet name.
The default cell to paste into is A1, but you can change this.
By default it adjusts the column widths to fit.
You can pass a collection of heading names to use instead of the field names.
There's not much error handling in there - such as passing a different number of heading names than there are fields, giving illegal sheet names.
It needs work :)
Public Sub ExportAll()
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim rst As DAO.Recordset
Dim oXL As Object
Dim oWrkBk As Object
Set db = CurrentDb
'Create instance of Excel.
Set oXL = CreateXL
For Each tdf In db.TableDefs
If Left(tdf.Name, 4) <> "MSys" Then
'Create workbook with single sheet.
Set oWrkBk = oXL.WorkBooks.Add(-4167) 'xlWBATWorksheet
'Open the table recordset.
Set rst = tdf.OpenRecordset
'In the immediate window display table name and TRUE/FALSE if exported successfully.
Debug.Print tdf.Name & " - " & QueryExportToXL(oWrkBk.worksheets(1), , rst, tdf.Name)
'Save and close the workbook.
oWrkBk.SaveAs "<path to folder>" & tdf.Name
oWrkBk.Close
End If
Next tdf
End Sub
'----------------------------------------------------------------------------------
' Procedure : CreateXL
' Author : Darren Bartrup-Cook
' Date : 02/10/2014
' Purpose : Creates an instance of Excel and passes the reference back.
'-----------------------------------------------------------------------------------
Public Function CreateXL(Optional bVisible As Boolean = True) As Object
Dim oTmpXL As Object
'''''''''''''''''''''''''''''''''''''''''''''''''''''
'Defer error trapping in case Excel is not running. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''
On Error Resume Next
Set oTmpXL = GetObject(, "Excel.Application")
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
'If an error occurs then create an instance of Excel. '
'Reinstate error handling. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
If Err.Number <> 0 Then
Err.Clear
On Error GoTo ERROR_HANDLER
Set oTmpXL = CreateObject("Excel.Application")
End If
oTmpXL.Visible = bVisible
Set CreateXL = oTmpXL
On Error GoTo 0
Exit Function
ERROR_HANDLER:
Select Case Err.Number
Case Else
MsgBox "Error " & Err.Number & vbCr & _
" (" & Err.Description & ") in procedure CreateXL."
Err.Clear
End Select
End Function
'----------------------------------------------------------------------------------
' Procedure : QueryExportToXL
' Author : Darren Bartrup-Cook
' Date : 26/08/2014
' Purpose : Exports a named query or recordset to Excel.
'-----------------------------------------------------------------------------------
Public Function QueryExportToXL(wrkSht As Object, Optional sQueryName As String, _
Optional rst As DAO.Recordset, _
Optional SheetName As String, _
Optional rStartCell As Object, _
Optional AutoFitCols As Boolean = True, _
Optional colHeadings As Collection) As Boolean
Dim db As DAO.Database
Dim prm As DAO.Parameter
Dim qdf As DAO.QueryDef
Dim fld As DAO.Field
Dim oXLCell As Object
Dim vHeading As Variant
On Error GoTo ERROR_HANDLER
If sQueryName <> "" And rst Is Nothing Then
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Open the query recordset. '
'Any parameters in the query need to be evaluated first. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set db = CurrentDb
Set qdf = db.QueryDefs(sQueryName)
For Each prm In qdf.Parameters
prm.Value = Eval(prm.Name)
Next prm
Set rst = qdf.OpenRecordset
End If
If rStartCell Is Nothing Then
Set rStartCell = wrkSht.cells(1, 1)
Else
If rStartCell.Parent.Name <> wrkSht.Name Then
Err.Raise 4000, , "Incorrect Start Cell parent."
End If
End If
If Not rst.BOF And Not rst.EOF Then
With wrkSht
Set oXLCell = rStartCell
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Paste the field names from the query into row 1 of the sheet. '
'Or the alternative field names provided in a collection. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If colHeadings Is Nothing Then
For Each fld In rst.Fields
oXLCell.Value = fld.Name
Set oXLCell = oXLCell.Offset(, 1)
Next fld
Else
For Each vHeading In colHeadings
oXLCell.Value = vHeading
Set oXLCell = oXLCell.Offset(, 1)
Next vHeading
End If
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Paste the records from the query into row 2 of the sheet. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set oXLCell = rStartCell.Offset(1, 0)
oXLCell.copyfromrecordset rst
If AutoFitCols Then
.Columns.Autofit
End If
If SheetName <> "" Then
.Name = SheetName
End If
'''''''''''''''''''''''''''''''''''''''''''
'TO DO: Has recordset imported correctly? '
'''''''''''''''''''''''''''''''''''''''''''
QueryExportToXL = True
End With
Else
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'There are no records to export, so the export has failed. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
QueryExportToXL = False
End If
Set db = Nothing
On Error GoTo 0
Exit Function
ERROR_HANDLER:
Select Case Err.Number
Case Else
MsgBox "Error " & Err.Number & vbCr & _
" (" & Err.Description & ") in procedure QueryExportToXL."
Err.Clear
Resume
End Select
End Function
After for each use workbooks.add()method...out_file=activeworkbook.path

Loop All Processes Memory

How could I, using "ReadProcessMemory" API, loop through all running processes of the machine and scan for an Array of strings and return a true/false value if any one or more are contained in the memory of the process - using VB6?
Example:
Strings() = {"#STRING1#", "#ANOTHERSTRING#", "$TRING"}
Loop # Processes
If InStr(ProcessMemory(#), Strings) Then
MsgBox(Process(#) & " Contains one of the strings!")
End If
Loop
i dont know but i used wmi in my program
something how that
Public Sub KillProcess(ByVal processName As String)
On Error GoTo ErrHandler
Dim oWMI
Dim ret
Dim sService
Dim oWMIServices
Dim oWMIService
Dim oServices
Dim oService
Dim servicename
Set oWMI = GetObject("winmgmts:")
Set oServices = oWMI.InstancesOf("win32_process")
For Each oService In oServices
servicename = LCase$(Trim$(CStr(oService.Name) & ""))
If InStr(1, servicename, LCase(processName), vbTextCompare) > 0 Then
ret = oService.Terminate
End If
Next
If Not oServices Is Nothing Then Set oServices = Nothing
If Not oWMI Is Nothing Then Set oWMI = Nothing
ErrHandler:
Err.Clear
End Sub