Recordset BOF/EOF cannot handle Nulls - ms-access

I have a form and want to display a message when there are no records. The SQL in the following code displays no records (Null) (as it should at present). The function does not work as I wish. It neither returns a number nor displays the message. If I put the function in a form that does have records, it counts them accurately.
Public Function NumRecs() As Integer
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT tblClient.ClientName, tblInvoices.SentToPayer, [Adjustment]+[MyFee]+[DBSFee] AS TotFees, tblClient.ClientID, tblDisclosure.ApplicantForenames, tblDisclosure.AppEmail " & _
"FROM ((tblInvoiceDetails INNER JOIN tblDisclosure ON tblInvoiceDetails.DiscLookup = tblDisclosure.ID) INNER JOIN tblInvoices ON tblInvoiceDetails.InvoiceLookup = tblInvoices.ID) INNER JOIN ((tblOfficerDetails INNER JOIN tblOfficers ON tblOfficerDetails.OfficerLookup = tblOfficers.ID) INNER JOIN tblClient ON tblOfficerDetails.ClientLookup = tblClient.ClientID) ON tblInvoices.AppLookup = tblClient.ClientID " & _
"WHERE (((tblInvoices.DatePaid) Is Null)) ")
If Not rs.BOF And Not rs.EOF Then
NumRecs = Me.Recordset.RecordCount
Else
DisplayMessage ("No records.")
NumRecs = 0
End If
rs.Close
Set rs = Nothing
End Function

"I have a form and want to display a message when there are no records."
You can accomplish that task without opening another DAO.Recordset. Just use RecordsetClone, which already exists.
Private Sub Form_Load()
Dim lngRowCount As Long
lngRowCount = 0
With Me.RecordsetClone
If Not (.BOF And .EOF) Then
.MoveLast
lngRowCount = .RecordCount
End If
End With
MsgBox lngRowCount & " records"
End Sub

Whenever I need a record count in DAO I always MoveLast and then MoveFirst however
Dim db as DAO.Database
Dim rst as DAO.Recordset
Dim strSQL as string
strSQL = "" ' your query here
Set db=CurrentDB()
Set rst=db.OpenRecordset(stSQL,dbOpenDynaSet)
With rst
If NOT (.EOF and .BOF) Then ' There are records to be had
Dim iRecCount as Integer
.MoveLast: .MoveFirst
' DAO typically requires the all records before the count
' count is correct
iRecCount = .RecordCount
Else ' There are NOT records to be had
' ADD YOUR MESSAGE HERE FOR NO RECORDS.
End If
.Close
End with
Set rst=nothing
Set db=nothing
Optionally I build up my Queries external to VBA and add parameters. This why I know my query is producing the results I expect. Then you can reference your query as an object of QueryDefs of CurrentDB() object. Then address you parameters as a property of QueryDef.
The following is a great read from Allen Browne on Recordsets.
http://allenbrowne.com/ser-29.html

All you really need is:
Public Function NumRecs() As Integer
Dim rs As DAO.Recordset
Set rs = Me.RecordsetClone
If rs.RecordCount = 0 Then
DisplayMessage ("No records.")
Else
rs.MoveLast
NumRecs = rs.RecordCount
End If
rs.Close
Set rs = Nothing
End Function

In order to get the recordcount with DAO, you need to MoveLast. Also, try changing the 'EOF' check (see below):
Public Function NumRecs() As Integer
Dim dbs As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL as String
strSQL = "SELECT tblClient.ClientName, tblInvoices.SentToPayer, [Adjustment]+[MyFee]+[DBSFee] AS TotFees, tblClient.ClientID, tblDisclosure.ApplicantForenames, tblDisclosure.AppEmail " & _
"FROM ((tblInvoiceDetails INNER JOIN tblDisclosure ON tblInvoiceDetails.DiscLookup = tblDisclosure.ID) INNER JOIN tblInvoices ON tblInvoiceDetails.InvoiceLookup = tblInvoices.ID) INNER JOIN ((tblOfficerDetails INNER JOIN tblOfficers ON tblOfficerDetails.OfficerLookup = tblOfficers.ID) INNER JOIN tblClient ON tblOfficerDetails.ClientLookup = tblClient.ClientID) ON tblInvoices.AppLookup = tblClient.ClientID " & _
"WHERE (((tblInvoices.DatePaid) Is Null))"
Set dbs = CurrentDB
Set rs = dbs.OpenRecordset(strSQL)
If Not rs.EOF Then
rs.MoveLast ' ADD THIS LINE
NumRecs = rs.RecordCount
Else
DisplayMessage ("No records.")
NumRecs = 0
End If
rs.Close
Set rs = Nothing
dbs.Close
Set dbs = Nothing
End Function`

Related

db.OpenRecordset returns something that isn't a recordset; but run as queries they do

I'm trying to generate a bill by route, so I've broken it down by customers belonging to a specific route, and then for each customer totaling their weekly rates to compile a monthly rate.
The problem is, even opening a recordset with a SELECT * IN [table] returns nothing, so there must be some glaring error. Here's my code, I'd be very appreciative if someone could set me straight.
Dim rs As DAO.Recordset
Dim rs2 As DAO.Recordset
Dim rs3 As DAO.Recordset
Dim custNo As Integer
Dim month_total_v As Integer
Dim weekTotal As Integer
Dim weekStart As Date
Dim sql As String
'sql = "SELECT cust_no FROM Roster WHERE route = Forms![routeBill]![route]"
Set rs = CurrentDb.OpenRecordset("SELECT CUST_NO FROM Roster WHERE ROUTE = 'Forms![routeBill]![route]'")
month_total_v = 0
MsgBox ("Boop.")
If Not (rs.EOF) Then
rs.MoveFirst
Do Until rs.EOF = True
MsgBox ("Boop.")
custNo = rs!CUST_NO
Set rs2 = CurrentDb.OpenRecordset("SELECT wk_rate, wk_strt_dt FROM Roster WHERE wk_strt_dt >= Forms![routeBill]![Text53] AND wk_strt_dt <= Forms![routeBill]![Text4] AND cust_no = custNo")
If Not (rs2.EOF And rs2.BOF) Then
rs2.MoveFirst
Do Until rs2.EOF = True
MsgBox "Boop."
weekStart = WK_STRT_DT
month_total_v = month_total_v + rs2!WK_RATE
Set rs3 = CurrentDb.OpenRecordset("SELECT * FROM monthTotal where cust_no = custNo and billMonth=month(weekStart) and billYear=year(weekStart)") 'specify date ranges to pick from to shorten query
If rs3.EOF Then
sql = "INSERT INTO monthTotal (cust_no, month_total, billMonth, billYear) VALUES (custNo, month_total_v, month(weekStart), year(weekStart))" 'Append, record does not exist
DoCmd.RunSQL sql
Else
sql = "UPDATE monthTotal SET month_total = month_total_v WHERE cust_no = custNo AND billMonth = month(weekStart) AND billYear = year(weekStart)" 'Update, record exists
DoCmd.RunSQL sql
End If
rs2.MoveNext
Loop
Else
'pass
End If
rs.MoveNext
Loop
End If
This query will not return any records when none of the stored ROUTE values contain the literal text, 'Forms![routeBill]![route]' ...
SELECT CUST_NO FROM Roster WHERE ROUTE = 'Forms![routeBill]![route]'
Elsewhere you have a WHERE clause which includes AND cust_no = custNo. But, since custNo is a VBA variable, the db engine doesn't know anything about it and will interpret it to be the name of a parameter for which you haven't supplied a value.
You can avoid those types of problems by using a parameter query in a DAO.QueryDef. Then supply the parameter values (from form controls, VBA variables, whatever ...) and use the QueryDef.OpenRecordset method to load your recordset.
Here is a simple example ...
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim strSelect As String
strSelect = "SELECT CUST_NO FROM Roster WHERE ROUTE = [which_route]"
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strSelect)
qdf.Parameters("which_route").Value = Forms![routeBill]![route]
Set rs = qdf.OpenRecordset
With rs
If .BOF And .EOF Then
MsgBox "no matches found"
Else
.MoveLast
MsgBox .RecordCount & " matches"
End If
.Close
End With
Note the parameter query technique avoids the need to add quotes around text values (and then also cope with text values which may include quotes within them) and format Date/Time values and enclose them within # delimiters.
The problem is here:
FROM Roster WHERE wk_strt_dt >= Forms![routeBill]![Text53] AND wk
You should outquote Forms![routeBill]![Text53]:
FROM Roster WHERE wk_strt_dt >= " & Forms![routeBill]![Text53] & " AND wk
You also need to get the dates right:
WHERE wk_strt_dt >= #" & Format(Forms![routeBill]![Text53], "yyyy\/mm\/dd") & "# AND wk_strt_dt ... etc

Ms Access 2007 record set not auto filling into textbox

I have a module with a procedure inside that looks like this:
Public Sub OpenRecordset()
Dim qdf As QueryDef
Set qdf = CurrentDb.QueryDefs("QOff2")
qdf.Parameters(0).Value = [Forms]![Form]![Text10]
Dim db As Database
Dim rs As Recordset
Dim StrBusinesses As String
Set rs = qdf.OpenRecordset
If rs.EOF And rs.BOF Then
MsgBox ("No businesses exist for this Customer")
Exit Sub
Else
rs.MoveFirst
End If
StrBusinesses = ""
Do While Not rs.EOF
StrBusinesses = StrBusinesses & rs!Fnam & ", "
rs.MoveNext
Loop
rs.Close
StrBusinesses = Left(StrBusinesses, Len(StrBusinesses) - 2)
Forms!Form.Badge = StrBusinesses
Set rs = Nothing
End Sub
I am trying to get this module to input the query results into a textbox (forms!form.badge), but I can't seem to get it to do it like my 5 other dlookup functions. When I open up the module and push the green play button, it shows up on the correct textbox but also shows up on the other records as well. It also doesn't show up automatically, nor does it update as you enter in the parameters. Isn't a module supposed to help autofil numerous variables into a text box in place of dlookup for multiple values?
No. If Forms!Form!Badge is an unbound textbox, a value assigned to it will be shown identically for all records.
To individualize, you will need a lookup function which takes the ID or other unique value of the record as parameter(add to textbox):
=LookupBadges([Forms]![Form]![Text10])
Public Function LookupBadges(ByVal Value As Variant) As Variant
Dim db As Database
Dim qd As QueryDef
Dim rs As Recordset
Dim Businesses As String
Set db = CurrentDb
Set qd = db.QueryDefs("QOff2")
qd.Parameters(0).Value = Nz(Value)
Set rs = qd.OpenRecordset
If rs.RecordCount > 0 Then
rs.MoveFirst
Do While Not rs.EOF
Businesses = Businesses & rs!Fnam.Value & ", "
rs.MoveNext
Loop
End If
rs.Close
Businesses = Left(Businesses, Len(Businesses) - 2)
LookupBadges = Businesses
Set rs = Nothing
Set qd = Nothing
Set db = Nothing
End Function

using a variable to Set rst

I'm trying to open a record set using a SQL string. I get run time error 3061 "Too Few Parameters." any help would be appreciated.
Dim stAppName As String
Dim stURL As String
Dim rst As Recordset
Dim dbs As Database
Dim stringToSearch As Integer
Dim strSQL As String
Set dbs = CurrentDb
stringToSearch = InputBox("What is your route #?", "Enter route #: ")
strSQL = "SELECT ESRP.* FROM ESRP WHERE ESRP.Route=stringToSearch"
Set rst = dbs.OpenRecordset(strSQL)
Please change the code line of strSQL as follows, as suggested by Fionnuala you need to use variable outside the quotes.
Assuming Route field is Text data type, we need to put single quote for strings, if its number no single quote, for dates put # instead of single quote
strSQL = "SELECT ESRP.* FROM ESRP WHERE ESRP.Route='" & stringToSearch & "'"
It's a little sample, maybe it can help you
Public Function fn_SQL_dbOpenRecordset(Optional vsql As String = "") As Recordset
Dim dbs As DAO.Database
Dim rs As Recordset
On Error GoTo END_CODE
'Set the database
Set dbs = CurrentDb
Set rs = dbs.OpenRecordset(vsql, dbOpenForwardOnly) 'you can use: dbOpenDynamic; dbOpenSnapshot; dbOpenTable
Set fn_SQL_dbOpenRecordset = rs
Exit Function
END_CODE:
Set fn_SQL_dbOpenRecordset = Nothing
End Function
Public Sub Program_Test()
On Error GoTo ERROR_SUB
Dim rs As Recordset
Dim sName As String
sName = "Joe"
sName = "'" & sName & "'" 'WARNING: BE CAREFUL WITH SQL INJECTION !!! Google it
Set rs = fn_SQL_dbOpenRecordset("select * from table1 d where PersonName = " & sName)
Dim i As Long
i = 0
While Not rs.EOF
Debug.Print rs(0).Value & " - " & rs(1).Value
rs.MoveNext
Wend
ERROR_SUB:
On Error Resume Next
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
End Sub

looping through recordset in access

Im trying to get a recordset loop code working, i have my bellow code which keeps inputing a zero. My second piece of code is identical code but displaying the qty in a message box. The number it is displaying is the number i want to input into my field. I just cant seem to get it to put the number in the field !Qty?
Dim Val As Integer
Dim rs As DAO.Recordset
Set rs = Forms!frmReceive!sfrmReceiveDetailEntry.Form.RecordsetClone
With rs
Do While Not rs.EOF
rs.Edit
Val = Nz(DLookup("[RemainingQty]", "tblQtySoFarTEMP", "[OrderDetailPK]= " & rs! [OrderDetailFK]))
rs!Qty = Val
rs.Update
rs.MoveNext
Loop
End With
Set rs = Nothing
Displaying value in message box
Dim val As Integer
Dim rs As DAO.Recordset
Set rs = Forms!frmReceive!sfrmReceiveDetailEntry.Form.RecordsetClone
With rs
Do While Not rs.EOF
val = Nz(DLookup("[RemainingQty]", "tblQtySoFarTEMP", "[OrderDetailPK]= " & rs! [OrderDetailFK]))
MsgBox val
rs.MoveNext
Loop
End With
Set rs = Nothing
I worked it out in the end, this is my working code!
'If YES then run the following code
AreYouSure = MsgBox("You are about to Receive All of Order" & txtOrderNumber.Value & " , Are you Sure?, The whole order and it's Quantities will be updated?", vbYesNo, "Receive All?")
If (AreYouSure = vbYes) Then
'disable warnings
DoCmd.SetWarnings False
'Create recordsetclone of subform
'loop recordset and lookup remaining qty to receive all
Set rs = Forms!frmReceive!sfrmReceiveDetailEntry.Form.RecordsetClone
With rs
Do While Not rs.EOF
rs.Edit
rs("Qty") = Nz(DLookup("[RemainingQty]", "tblQtySoFarTEMP", "[OrderDetailPK]= " & rs![OrderDetailFK]))
rs.Update
rs.MoveNext
Loop
End With
Set rs = Nothing

DAO method in MS Access

I am unable to get the count of records by openining Ms Access Query, I use the following code.
Private Sub CmdGetData_Click()
Dim WRK As Workspace
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim StrSql As String
Set WRK = DBEngine.Workspaces(0)
Set db = CurrentDb
StrSql = "select * from [QrySalePatti]"
Set rs = db.OpenRecordset(StrSql, dbOpenDynaset)
Do While (Not rs.EOF)
rs.MoveFirst
rs.MoveLast
MsgBox rs.RecordCount
Loop
exitRoutine:
If Not (db Is Nothing) Then
db.Close
Set db = Nothing
End If
Set WRK = Nothing
End Sub
You should not need a Do While loop to get the RecordCount.
Set rs = db.OpenRecordset(StrSql, dbOpenDynaset)
With rs
If Not (.BOF And .EOF) Then
.MoveLast
End If
MsgBox .RecordCount
End With
However if your goal is only to count the rows from QrySalePatti, you could use a SELECT Count(*) query and read the value returned from that.
StrSql = "SELECT Count(*) AS row_count FROM [QrySalePatti]"
Set rs = db.OpenRecordset(StrSql)
MsgBox rs!row_count
Or you could use a DCount expression.
MsgBox DCount("*", "QrySalePatti")