Accessing value of recordset - excel

I have a function that obtains a recordset of attributes from Active Directory.
I can access most of the returned values like this
Set rs = cmd.Execute
Debug.Print (rs.Fields("distinguishedName").Value)
Debug.Print (rs.Fields("GivenName").Value)
However the returned value for postOfficeBox looks like it could be a variant.
How do I access the value? I tried
Debug.Print (rs.Fields("postOfficeBox").value(0))
That did not work - Run Time Error 450.

Thanks Tim Williams. I manage to get it to return a value like this:
Dim arrPOBox As Variant
Dim strPOBox As String
....
Set rs = cmd.Execute
arrPOBox = rs.Fields("postOfficeBox").Value
strPOBox = CStr(arrPOBox(0))

Related

MS-Access send records to Excel and Count Records in Excel

I have an access form with a button to send a record set to excel.
It works 70% of the time but for some reason I get an error "Runtime error '1004' Method 'Rows' of object '_Global' Failed".
Dim xlApp As Excel.Application
Dim xlwb As Excel.Workbook
Dim xlws As Excel.Worksheet
Dim xlrng As Excel.Range
rst.open [Select Query]
Loop through record set and copy values
i = 2
Do Until rst.EOF
dblTotHr = rst!Hours
i = 2
Do Until rst.EOF
dblTotHr = rst!Hours
xlws.Range("a" & i).Value = rst!A
xlws.Range("b" & i).Value = rst!B
xlws.Range("c" & i).Value = rst!C
i = i + 1
rst.MoveNext
Loop
Code that fails (sometimes):
lrow = xlws.Cells(Rows.Count, 1).End(xlUp).Row
Clean up:
xlApp.Visible = True
Set xlApp = Nothing
Set xlwb = Nothing
Set xlws = Nothing
Set xlrng = Nothing
Set rst = Nothing
Set rst1 = Nothing
Since this code works sometimes and not others with no pattern, I am confused on where to try and start looking for answers.
Any help is much appreciated!!
The fix is
lrow = xlws.Cells(xlws.Rows.Count, 1).End(xlUp).Row
Otherwise you cannot be sure Rows refers to the sheet xlws. Interesting that it sometimes resp. quite often works.
If you use Rows in a VBA code within Excel it refers to the ActiveSheet unless you add an explicit reference. This can even cause issues in Excel as the ActiveSheet can be a diagramm.
To automate Microsoft Excel, you establish an object variable that usually refers to the Excel Application object or the Excel Workbook object. Other object variables can then be set to refer to a Worksheet, a Range, or other objects in the Microsoft Excel object model. When you write code to use an Excel object, method, or property, you should always precede the call with the appropriate object variable. If you do not, Visual Basic establishes its own reference to Excel. This reference might cause problems when you try to run the automation code multiple times. Note that even if the line of code begins with the object variable, a call may be made to an Excel object, method, or property in the middle of the line of code that is not preceded with an object variable.
Further reading

Recordset retrieves only first row

I am trying to retrieve records from Oracle SQL database and write them into a dictionary. Catch is that this code works as expected on my machine but no on my coworker's. On his end Recordset retrieves only one record even if that Recordset has RecordCount higher than one, meanwhile that same query pull up multiple records for me.
Initially I thought that MoveNext method is causing problems but once I switched to GetRows method issue persists. Anyway since this code works on my machine I'm fairly certain that my code correct, but you never know so I am including function in question here. The commented part contains the loop when I was using MoveNext but like I said changing that loop does not help with my problem.
Public Function WriteQueryToDict(SQL As String) As Dictionary
'First column of the query must contain key that will be used to locate records in the dictionary
'Output is a dictionary with first column as key, and the rest in an array that is indexed from 0
Dim Results As Recordset
Dim ResultsArray() As Variant
Dim cursorField As Integer
Dim cursorRow As Integer
Dim Output As Dictionary
Dim key As Variant
Dim record() As Variant
Set Results = RunQuery(SQL)
Set Output = New Dictionary
If Not (Results.BOF And Results.EOF) Then
' New loop
ResultsArray = Results.GetRows()
ReDim record(0 To (UBound(ResultsArray, 1) - 1))
For cursorRow = 0 To UBound(ResultsArray, 2)
key = ResultsArray(0, cursorRow)
For cursorField = 1 To UBound(ResultsArray, 1)
record(cursorField - 1) = ResultsArray(cursorField, cursorRow)
Next
Output.Add key, record
Next
' Original loop
'Results.MoveFirst
'Do
' For cursorField = 1 To Results.fields.Count - 1
' record(cursorField) = Results.fields(cursorField).Value
' Next
'
' key = Results.fields(0)
' Output.Add key, record
' Results.MoveNext
'Loop Until Results.EOF
End If
Set WriteQueryToDict = Output
End Function
In case this might be relevant this is function that does the actual connection + querying:
Private Function RunQuery(SQL As String) As Recordset
Dim Username As String
Dim Password As String
Dim DBConn As ADODB.Connection
Username = ThisWorkbook.Sheets("Configuration").Range("C3").Value
Password = ThisWorkbook.Sheets("Configuration").Range("C4").Value
Set DBConn = New ADODB.Connection
With DBConn
.Provider = "OraOLEDB.Oracle.1;user id = " & Username & "; password = " & Password
.CONNECTIONSTRING = "Data Source=" & DB
.Open
End With
Set RunQuery = DBConn.Execute(SQL)
End Function
I am guessing that this has to do with some setting set outside of my code, my colleague has no knowledge to configure oracle drivers on his own so I am at loss as to what tis might be. Anyway I've never seen my code produce such differences between two different machines so I'm not sure what am I looking for to fix this problem, I will share additional details as needed if you can tell what might be missing here.
Thank you
UPDATE:
When debugigng I setup a breakpoint inside WriteQueryToDict right before the loop starts, that way I was able to Play with Recordset itself first check the RecordCount property to make sure that we have records to iterate over last time I ran this on his machine I saw about 60 records, then call MoveFirst and my epectation is that now I will be able to call MoveNext 60 times before EOF turns true, instead it turn true after first call. while at it I tried setting cursorLocation to Client but that didn't have any effect.

How to send parameters to microsoft access query so that I can import an access parameter query to excel?

I need to import a microsoft access query that has popup input parameters into excel. I tried the code below but it does not work. I receive error 93 that tells me that object or object variable is not set.
I would like to be able to reference two cells in excel that contain the values of the current and previous month and then send these values as inputs to the access query, but for now I entered them in VBA to keep it simple.
Any help would be greatly appreciated!
Thank you!
Sub Acess_Connection()
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim qdf As DAO.QueryDef
Dim i As Long
Dim wsh As Worksheet
Set dbs = DBEngine.OpenDatabase("filepath")
Set qdf = dbs.QueryDefs("parameter_query")
qdf.Parameters("Date_PreviousMonth") = "31.12.2018"
qdf.Parameters("Date_CurrentMonth") = "31.01.2019"
Set rst = qdf.OpenRecordset("parameter_query")
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
I tested setting query parameters via VBA with a very simple query and it works with following adjustments.
query object must have PARAMETERS clause and parameters under appropriate field(s)
use # delimiters for date criteria #12/31/2018#
Set rst = qdf line does not use query name as argument, the variable qdf provides the name so correct to
Set rst = qdf.OpenRecordset() which will use the default recordset type.
for early binding, select Microsoft Office 14.0 Access Database Engine Object Library in VBA editor, at least for more recent versions of Excel
You may have to pass valid date values to the parameters:
qdf.Parameters("Date_PreviousMonth").Value = #12/31/2018#
qdf.Parameters("Date_CurrentMonth").Value = #01/31/2019#
Try adding square brackets around your parameters name so:
qdf.Parameters("[" & "Date_PreviousMonth" & "]") = "31.12.2018"

VBA: Counting rows in a table (list object)

I am trying to write some VBA in Excel that can take the name of a table (list object) as a parameter and return the number of rows.
The following works, but isn't allowing me to pass in a string with the table name.
MsgBox ([MyTable].Rows.Count)
The following gives the error:
Object required
v_MyTable = "MyTable"
MsgBox (v_MyTable.Rows.Count)
The following gives the error:
Object variable or With block variable not set
v_MyTable_b = "[" & "MyTable" & "]"
MsgBox(v_MyTable_b.Rows.Count)
I also tried working with ListObjects, which I am new to. I get the error:
Object doesn't support this property or method
Dim tbl As ListObject
Set tbl = ActiveSheet.ListObjects("MyTable")
MsgBox(tbl.Rows.Count)
Thanks for any help!
You need to go one level deeper in what you are retrieving.
Dim tbl As ListObject
Set tbl = ActiveSheet.ListObjects("MyTable")
MsgBox tbl.Range.Rows.Count
MsgBox tbl.HeaderRowRange.Rows.Count
MsgBox tbl.DataBodyRange.Rows.Count
Set tbl = Nothing
More information at:
ListObject Interface ListObject.Range Property ListObject.DataBodyRange Property ListObject.HeaderRowRange Property
You can use this:
Range("MyTable[#Data]").Rows.Count
You have to distinguish between a table which has either one row of data or no data, as the previous code will return "1" for both cases.
Use this to test for an empty table:
If WorksheetFunction.CountA(Range("MyTable[#Data]"))
You can use:
Sub returnname(ByVal TableName As String)
MsgBox (Range("Table15").Rows.count)
End Sub
and call the function as below
Sub called()
returnname "Table15"
End Sub

VBA storing database values in variables

I have to write some VBA code in excel to go with my VB.NET program and I am struggling with the basics of VBA as I have not used it before. I found some code which allowed me to get the values from my temporary table and put them directly in appropiate fields in the excel spreadsheet. I am populating a purchase order document, so information passed over are things like subtotal, vat, shipping, total, etc.
This is the code I have used to populate a single cell:
'get quantity
strQry = "SELECT quantity from [temp];"
Set rs = New ADODB.Recordset
With rs
Set .ActiveConnection = cn
.Open strQry
End With
'append data to document
Worksheets("PurchaseOrder").Range("D22").CopyFromRecordset rs
quantity = rs.Fields("quantity") 'setting the quatity in a variable
The last line of code is my attempt of storing the value of quantity in a variable, which I need to use to calculate the sub total as sub total was not passed over to excel. The code to populate the cells works fine, it is just putting the data in a variable to manipulate which I am struggling with. Populating the cells directly from the database works fine, but I am getting an error on that last line.
After storing quantity in a variable, I would also like to store the cost per unit in a variable, remove the £ sign at the start using a substring equivalent, convert it to a decimal then times the cost per unit by the quantity to get the sub total.
I tried using this following code:
'get price
strQry = "SELECT costPerUnit from [temp];"
Set rs = New ADODB.Recordset
With rs
Set .ActiveConnection = cn
.Open strQry
End With
'append data to document
Worksheets("PurchaseOrder").Range("N22").CopyFromRecordset rs
costPerUnit = Right(rs(0), Len(costPerUnit) - 1) 'setting the cost per unit in a variable
subtotal = costPerUnit * quantity
Worksheets("PurchaseOrder").Cells("Q47").Value = "£ " & subtotal
Any help is appreciated. Thankyou.
Ok. So until filling the of the Recordset you have done it correct and then you have to see that the Recordset is more like a table and can have none or multiple rows with multiple columns.
First you have to check if the query returned any result or if the Recordset is empty (rs.BOF and rs.EOF are true). Then you would loop through the rows (rs.MoveNext).
To access a single value you can either give the index of the column or the column name.
The following example loops through rows and through columns but also extracts again the column "quantity" at the end:
If (rs.EOF) And (rs.BOF) Then
Exit Function
Else
rs.MoveFirst
Do Until rs.EOF
For j = 1 To rs.Fields.Count
valueOfColumnJ = rs.Fields(j - 1).Value
Next j
quantity = rs.Fields("quantity")
rs.MoveNext
Loop
End If
Recordsets have a cursor and any reference to the recordset is going to return properties (like the value of a field) based on where that cursor is.
When you called CopyFromRecorset, you moved the cursor to the end (EOF = True). Then when you tried to get the Fields("quantity"), there was no active record of the recordset, so you got an error.
You could have first done rs.MoveFirst if you have the right type of recordset. Then quantity would have equaled the quantity field from the first record. Probably not what you want.
There is not a one-liner (as far as I know) that will get you the total of all the fields in your recordset. You have to loop like Graffl shows.
What might be the better path is to use Excel. You already have the data in there, so insert a formula to get the subtotal you want.
Worksheets("PurchaseOrder").Cells("Q47").Formula = _
"=SUMPRODUCT(P23:P46*Q23:A46)"
or something like that.
you can save Recordset to array
as shown below
Sub Check_gg_date_time_Unique(i As Integer)
Dim filmSet As New ADODB.Recordset
Dim dbConn As New ADODB.Connection
Dim filmName As String, lastrow As Integer
Dim Varray As Variant
dbConn.ConnectionString = "Provider=MSDASQL.1;Data Source=Excel_to_MySQL_Maintenance"
dbConn.Open
Set filmSet = dbConn.Execute("select count(wono) from maintennce_db.work_order where post_gg_date_time = '2022-08-30 14:21:37'")
Varray = filmSet.GetRows(1)
If Varray(0, 0) = 0 Then
'Do whatever you want
End If
End Sub

Resources