Access 2007 VBA Error 2467 for function - ms-access

Having a very weird problem. I have a function which is called when a form field gets focus. The function is passed four arguments, three of which are values from form fields and the fourth is a global variable which is set when the form loads. The function uses these variables to calculate the value for the field which called the function. This function is called in two different places. Everything was working fine, and now suddenly the function works when called from one place and doesn't work from the other, generating a 2467 run-time error, 'The expression you entered refers to an object that is closed or doesn't exists'. I've checked that the values of the arguments being passed are correct, the function exists OK, so can't see why I'm getting this error. Anyone any ideas?
Private Sub cboFinalStage_GotFocus()
'lookup stage based on TNM values
cboFinalStage = FindStage(cboFinalStageT, cboFinalStageN, cboFinalStageM, gblCancer)
End Sub
Public Function FindStage(cboT As ComboBox, cboN As ComboBox, cboM As ComboBox,
strCancer As String) As String
'use the TNM values entered to find the correct stage for the site and return it
'error handling
If gcfHandleErrors Then On Error GoTo PROC_ERR
'declare variables
Dim strTemp As String
Dim strTable As String
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strQuery As String
Dim strSite As String
Dim strSiteFull As String
Dim strT As String
Dim strN As String
Dim strM As String
'initialise variables - if there are no values entered in the 3 comboboxes, exit
'load tumour first in case it isn't already loaded
Forms!frmContainer.subTumour.SourceObject = "fsubTumour"
If Not IsNull(Forms!frmContainer.subTumour.Form!txtICD10) Then
strSite = Left(Forms!frmContainer.subTumour.Form!txtICD10, 3)
strSiteFull = Forms!frmContainer.subTumour.Form!txtICD10
End If
If Not IsNull(cboT.Value) Then
strT = cboT.Value
Debug.Print "T is " & strT
End If
If Not IsNull(cboN.Value) Then
strN = cboN.Value
Debug.Print "N is " & strN
End If
If Not IsNull(cboM.Value) Then
strM = cboM.Value
Debug.Print "M is " & strM
End If
If (IsNull(strT) Or IsNull(strN) Or IsNull(strM)) Then
Debug.Print "null so exiting"
Exit Function
End If
'identify the correct AJCC lookup table by cancer site
Select Case [strCancer]
Case "bla"
strTable = "lkp_AJCC_bladder"
Case "bre"
strTable = "lkp_AJCC_breast"
...
End Select
Debug.Print "AJCC table is " & strTable
'query the AJCC lookup table for the stage
strQuery = "SELECT c_stage FROM " & strTable & " WHERE (((t_value)='" & strT & "')
AND ((n_value)='" & strN & "') AND ((m_value)='" & strM & "'))"
Debug.Print "query is " & strQuery
Set db = CurrentDb
Set rs = db.OpenRecordset(strQuery)
If Not rs.EOF Then
strTemp = rs.Fields(0).Value
Debug.Print "result is " & strTemp
End If
rs.Close
db.Close
'return stage
FindStage = strTemp
'error handling
PROC_EXIT:
Exit Function
PROC_ERR:
If (Err.Number = 2467) Then
MsgBox "Unable to evaluate the stage", vbOKOnly, "Processing error"
Resume PROC_EXIT
Else
MsgBox "Error: (" & Err.Number & ") " & Err.Description, vbCritical
Resume PROC_EXIT
End If
End Function

Related

How to check if the table is empty in Access 2003?

I need only empty tables in access database. Additionally, it would be great if I can get empty tables from list of tables that I have (part of all tables). But listing all empty tables would work also.
You can use a small VBA function that checks this. Something like:
Function fIsTableEmpty(strTableName As String) As Boolean
On Error GoTo E_Handle
Dim db As DAO.Database
Dim rsData As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb
strSQL = "SELECT COUNT(*) FROM [" & strTableName & "];"
Set rsData = db.OpenRecordset(strSQL)
fIsTableEmpty = True ' start by assuming that there are records
If Not (rsData.BOF And rsData.EOF) Then
If rsData(0) > 0 Then fIsTableEmpty = False
End If
fExit:
On Error Resume Next
rsData.Close
Set rsData = Nothing
Set db = Nothing
Exit Function
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "fIsTableEmpty", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume fExit
End Function
You can use DCount:
Public Function ListEmptyTables()
Dim Table As DAO.TableDef
For Each Table In CurrentDb.TableDefs
If Table.SourceTableName = "" Then
If DCount("*", Table.Name) = 0 Then
Debug.Print Table.Name
End If
End If
Next
End Function

3021 runtime error at rs.Move when selecting record in the subform

I edited code by referring to How do I access the selected rows in Access?. But I got runtime error of 3021 at RS.Move F.SelTop - 1 with my code even though m_SelNumRecs is not zero. I am not sure if I have to add additional code to my code.
I have a form including a subform of frm_SubPerson. I select record(s) on the frm_SubPerson and want to conver the record(s) into pdf.
Public m_SelNumRecs As Long
Public m_SelTopRec As Long
Public m_CurrentRec As Long
Private Sub cmdConvert()
Dim mSelTop As Long
Dim mSelHeight As Long
Dim F As Form
Dim RS As Recordset
Dim filePath As String
Dim i As Integer
' Get the form and its recordset.
Set F = Me.frm_SubPerson.Form
Set RS = F.RecordsetClone
If m_SelNumRecs = 0 Then
MsgBox "no record is selected."
Exit Sub
End If
' Move to the first selected record.
RS.Move F.SelTop - 1 '3021 error
For i = 1 To m_SelNumRecs
DoCmd.OpenReport "report_Person", acViewPreview, , "report_Person.chName=" & "'" & RS!chName.Value & "'"
filePath = "D:\report_Person\" & "report_Person" & RS!chName & "_" & RS!chNum & "_" & RS!reYear.Value & "Year" & RS!reMonth & "Month" & ".pdf"
DoCmd.OutputTo acOutputReport, "", acFormatPDF, filePath
DoCmd.Close acReport, "report_Person"
RS.MoveNext
Next i
RS.Close
Set RS = Nothing
End Sub
Private Sub frm_SubPerson_Exit(Cancel As Integer)
With frm_SubPerson.Form
m_SelNumRecs = .SelHeight
m_SelTopRec = .SelTop
m_CurrentRec = .CurrentRecord
End With
End Sub

Compare two recordset variables gives type mismatch

I have a bound form with several subforms. some of these subforms can 0 or more records, others have 1 or more.
The form is always open in read-only and on it there are an "edit" and a "close" button.
When the user clicks on the edit button I save the content of the current record togehter with all records of the subforms so that when he/she clicks on the close button I can ask wether to save or not and, if not, discard the changes restoring from saved records.
So far this is the code of the edit button (where GclnAllCnts is a global variable of type Dictionary):
Private Sub EditLibroBtn_Click()
On Error GoTo Err_EditLibroBtn_Click
Dim lngID As Long
Dim ctlCnt As Control
Dim rs As Recordset
lngID = Me.ID
Set GclnAllCnts = New Dictionary
GclnAllCnts.Add Me.Name, Me.RecordsetClone
For Each ctlCnt In Me.Controls
If (ctlCnt.ControlType = acSubform) Then
Set rs = ctlCnt.Form.RecordsetClone
If rs.RecordCount > 0 Then
GclnAllCnts.Add ctlCnt.Name, ctlCnt.Form.RecordsetClone
Else
GclnAllCnts.Add ctlCnt.Name, Null
End If
End If
Next
DoCmd.Close acForm, Me.Name
DoCmd.OpenForm GCstMainFrmName, , , "ID = " & lngID, acFormEdit, acDialog
Exit_EditLibroBtn_Click:
Set ctlCnt = Nothing
Set rs = Nothing
Exit Sub
Err_EditLibroBtn_Click:
MsgBox err.Description & vbNewLine & "Error number: " & err.Number, vbCritical, "Errore"
Resume Exit_EditLibroBtn_Click
End Sub
And this is the code of the close button:
Private Sub ChiudiBtn_Click()
On Error GoTo Err_ChiudiBtn_Click
Dim intBoxAwr As Integer
Dim stSQL As String
Dim vKey As Variant
Dim ctlCnt As Control
Dim clnAllCnts As Dictionary
Dim bSaveNeeded As Boolean
bSaveNeeded = False
If (Me.AllowEdits And Me.ID <> "" And Not IsNull(Me.ID)) Then
Set clnAllCnts = New Dictionary
clnAllCnts.Add Me.Name, Me.RecordsetClone
For Each ctlCnt In Me.Controls
If (ctlCnt.ControlType = acSubform) Then
Set rs = ctlCnt.Form.RecordsetClone
If rs.RecordCount > 0 Then
clnAllCnts.Add ctlCnt.Name, ctlCnt.Form.RecordsetClone
Else
clnAllCnts.Add ctlCnt.Name, Null
End If
End If
Next
If clnAllCnts.Count <> GclnAllCnts.Count Then
bSaveNeeded = True
Else
For Each vKey In clnAllCnts.keys()
If Not GclnAllCnts.Exists(vKey) Then
bSaveNeeded = True
Exit For
Else
'*********** Next Gives error **********
If clnAllCnts.Item(vKey) <> GclnAllCnts.Item(vKey) Then
bSaveNeeded = True
Exit For
End If
End If
Next
End If
If bSaveNeeded Then
intBoxAwr = MsgBox("Salvare le modifiche al libro?", vbYesNo + vbQuestion, "Salvare")
If intBoxAwr = vbYes Then
'etc., omitting code
End Sub
The error I get is Type mismatch (nr. 13) and it is given by the <> comparison (I can Debug.print IsNull(clnAllCnts.Item(vKey)) and IsNull(GclnAllCnts.Item(vKey)).
How can I compare the two recordset variables?
Comparing two Recordset objects by simply saying If rst1 <> rst2 could be dicey anyway, because what does that really mean? Such an expression could very well return True every time, if rst1 and rst2 really are different objects (even if they are of the same object Type).
It appears that you are interested in whether the contents of the two Recordsets is the same. In that case, I would be inclined to serialize the recordset data and store the resulting String instead of storing the Recordset object itself.
The following VBA Function may prove helpful in that case. It loops through a recordset object and produces a JSON-like string containing the current recordset data.
(Note that the function may NOT necessarily produce valid JSON. It doesn't escape non-printing characters like vbCr and vbLf. It doesn't escape backslashes (\). It stores all values as either "string" or null. In other words, in its current form it is not designed to produce a string that could later be deserialized.)
Private Function rstSerialize(ByVal rst As DAO.Recordset)
' loop through the recordset and generate a JSON-like string
' NB: This code will NOT necessarily produce valid JSON!
'
Dim s As String, fld As DAO.Field, rowCount As Long, fldCount As Long
s = "{"
If Not (rst.BOF And rst.EOF) Then
rst.MoveFirst
rowCount = 0
Do Until rst.EOF
If rowCount > 0 Then
s = s & ", "
End If
s = s & """row"": {"
fldCount = 0
For Each fld In rst.Fields
If fldCount > 0 Then
s = s & ", "
End If
s = s & """" & fld.Name & """: " & IIf(IsNull(fld.Value), "null", """" & fld.Value & """")
fldCount = fldCount + 1
Next
s = s & "}"
rowCount = rowCount + 1
rst.MoveNext
Loop
End If
s = s & "}"
rstSerialize = s
End Function
Data Example: If the Recordset contained
DonorID Amount
------- ------
1 10
2 20
the function would return the string
{"row": {"DonorID": "1", "Amount": "10"}, "row": {"DonorID": "2", "Amount": "20"}}
Usage Example: On a form that contains a subform, a button on the main form could do the following
Private Sub Command3_Click()
Dim rst As DAO.Recordset, originalState As String
Set rst = Me.MemberDonationsSubform.Form.RecordsetClone
originalState = rstSerialize(rst)
rst.MoveFirst
rst.Edit
rst!Amount = rst!Amount + 1
rst.Update
Debug.Print "(Recordset updated.)"
If rstSerialize(rst) = originalState Then
Debug.Print "Recordset does not appear to have changed."
Else
Debug.Print "Recordset appears to have changed."
End If
End Sub
which would print the following in the VBA Immediate Window
(Recordset updated.)
Recordset appears to have changed.

VBA DoCmd.OutputTo With QueryDef

I've been looking a while now for a solution to export a query with open parameters. I need to export a Query as a Formatted Excel Spreadsheet and can't create additional Tables, Queries, Forms, or Reports to the Database being used. I use DoCmd.OutputTo as it exports a formatted query unlike DoCmd.TransferSpreadsheet however I can't seem to export the query with defined parameters. I need to include the parameters or else the user will be forced to input the start and end date three times a piece as the database for some reason asks for the startDate and endDate twice and in order to keep the excel spreadsheet and the subsequent outlook section consistant i would have to ask the user to input their previous parameters again
Sub Main()
On Error GoTo Main_Err
'Visually Display Process
DoCmd.Hourglass True
Dim fpath As String
Dim tname As String
Dim cname As String
Dim tType As AcOutputObjectType
Dim tempB As Boolean
fpath = CurrentProject.path & "\"
'tType = acOutputTable
'tname = "APPROVED SWPS FOR LOOK AHEAD & BAR CHART"
tType = acOutputQuery
tname = "ASFLA&BC Query"
cname = "Temp BPC Calendar"
Dim qdfQry As DAO.QueryDef
Dim strStart As String
Dim strEnd As String
Set qdfQry = CurrentDb().QueryDefs(tname)
'strStart = InputBox("Please enter Start date (mm/dd/yyyy)")
'strEnd = InputBox("Please enter Start date (mm/dd/yyyy)")
qdfQry.Parameters("ENTER START DATE") = FormatDateTime("6/30/12", vbShortDate) 'strEnd
qdfQry.Parameters("ENTER END DATE") = FormatDateTime("7/1/12", vbShortDate) 'strStart
tempB = Backup(fpath, qdfQry, tType)
If (Not tempB) Then
MsgBox "Excel Conversion Ended Prematurely..."
Exit Sub
End If
' tempB = sendToOutlook(qdfQry, cname)
' If (Not tempB) Then
' MsgBox "Access Conversion Ended Prematurely..."
' Exit Sub
' End If
MsgBox "Procedure Completed Successfully"
Main_Exit:
DoCmd.Hourglass False
Exit Sub
Main_Err:
DoCmd.Beep
MsgBox Error$
Resume Main_Exit
End Sub
'************************************************************************************
'*
'* Excel PORTION
'*
'************************************************************************************
Public Function Backup(path As String, db As DAO.QueryDef, Optional outputType As AcOutputObjectType) As Boolean
On Error GoTo Error_Handler
Backup = False
Dim outputFileName As String
Dim name As String
Dim tempB As Boolean
'Set Up All Name Variablesand
name = Format(Date, "MM-dd-yy") & ".xls"
'Cleans Directory of Any older files and places them in an archive
SearchDirectory path, "??-??-??.xls", name
'See If File Can Now Be Exported. If Already Exists ask to overwrite
outputFileName = path & name
tempB = OverWriteRequest(outputFileName)
If tempB Then
'Formats The Table And Exports Into A Formatted SpreadSheet
'Checks if an output type was added to the parameter if not defualt to table
If Not IsMissing(outputType) Then
DoCmd.OutputTo outputType, db.name, acFormatXLS, outputFileName, False
Else
DoCmd.OutputTo acOutputTable, db.name, acFormatXLS, outputFileName, False
End If
Else
Exit Function
End If
Backup = True
Error_Handler_Exit:
Exit Function
Error_Handler:
MsgBox "MS Access has generated the following error" & vbCrLf & vbCrLf & "Error Number: " & _
Err.number & vbCrLf & "Error Source: Main Excel Backup" & vbCrLf & "Error Description: " & _
Err.Description, vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
The SQL currently given looks like similar to below with omitted fields for for clarity
PARAMETERS [ENTER START DATE] DateTime, [ENTER END DATE] DateTime;
SELECT [SWPS].STATION,
[SWPS].START_DATE,
[SWPS].END_DATE,
FROM [SWPS]
WHERE ((([SWPS].STATION)
Like ("*"))
AND (([SWPS].START_DATE)<=[ENTER END DATE])
AND (([SWPS].END_DATE)>=[ENTER START DATE])
AND (([SWPS].SWP_STATUS) In ("A","P","W","T","R")));
I suggest you change the sql of the query.
Dim qdfQry As DAO.QueryDef
Dim strStart As String
Dim strEnd As String
''You could use a query specifically for this
Set qdfQry = CurrentDb.QueryDefs(tname)
sSQL=qdfQry.SQL
NewSQL = "SELECT [SWPS].STATION, [SWPS].START_DATE, [SWPS].END_DATE, " _
& "FROM [SWPS] WHERE [SWPS].STATION Like '*' " _
& "AND [SWPS].SWP_STATUS In ('A','P','W','T','R') " _
& "AND [SWPS].START_DATE)<=#" & Format(DateStart, "yyyy/mm/dd") & "# " _
& "AND [SWPS].END_DATE)>=#" & Format(DateEnd, "yyyy/mm/dd") & "#"
qdfQry.SQL = NewSQL
''Do the excel stuff
''Reset the query
qdfQry.SQL = sSQL

MS Access: How to bypass/suppress an error?

I'm executing a query like this
select field from table;
In that query, there is a loop running on many tables. So, if the field is not present in a table I get a
Runtime Error 3061
How can I by pass this error such as that on this error flow should go to another point?
This is the code I have recently after going through this forum.
Option Explicit
Private Sub UpdateNulls()
Dim rs2 As DAO.Recordset
Dim tdf As DAO.TableDef
Dim db As Database
Dim varii As Variant, strField As String
Dim strsql As String, strsql2 As String, strsql3 As String
Dim astrFields As Variant
Dim intIx As Integer
Dim field As Variant
Dim astrvalidcodes As Variant
Dim found As Boolean
Dim v As Variant
Open "C:\Documents and Settings\Desktop\testfile.txt" For Input As #1
varii = ""
Do While Not EOF(1)
Line Input #1, strField
varii = varii & "," & strField
Loop
Close #1
astrFields = Split(varii, ",") 'Element 0 empty
For intIx = 1 To UBound(astrFields)
'Function ListFieldDescriptions()
Dim cn As New ADODB.Connection, cn2 As New ADODB.Connection
Dim rs As ADODB.Recordset, rs3 As ADODB.Recordset
Dim connString As String
Dim SelectFieldName
Set cn = CurrentProject.Connection
SelectFieldName = astrFields(intIx)
Set rs = cn.OpenSchema(adSchemaColumns, Array(Empty, Empty, Empty, SelectFieldName))
'Show the tables that have been selected '
While Not rs.EOF
'Exclude MS system tables '
If Left(rs!Table_Name, 4) <> "MSys" Then
strsql = "Select t.* From [" & rs!Table_Name & "] t Inner Join 01UMWELT On t.fall = [01UMWELT].fall Where [01UMWELT].Status = 4"
End If
Set rs3 = CurrentDb.OpenRecordset(strsql)
'End Function
strsql2 = "SELECT label.validcode FROM variablen s INNER JOIN label ON s.id=label.variablenid WHERE varname='" & astrFields(intIx) & "'"
Set db = OpenDatabase("C:\Documents and Settings\Desktop\Codebook.mdb")
Set rs2 = db.OpenRecordset(strsql2)
With rs2
.MoveLast
.MoveFirst
astrvalidcodes = rs2.GetRows(.RecordCount)
.Close '
End With
With rs3
.MoveFirst
While Not rs3.EOF
found = False
For Each v In astrvalidcodes
If v = .Fields(0) Then
found = True
Debug.Print .Fields(0)
Debug.Print .Fields(1)
Exit For
End If
Next
If Not found Then
msgbox "xxxxxxxxxxxxxxxx"
End If
End If
.MoveNext
Wend
End With
On Error GoTo 0 'End of special handling
Wend
Next intIx
End Sub
I'm getting a
Type Mismatch Runtime Error
in Set rs3 = CurrentDb.OpenRecordset(strsql)
I guess I'm mixing up ado and dao but I'm not certainly sure where it is.
Use the On Error statement that VBA supplies:
Sub TableTest
On Error Goto TableTest_Error
' ...code that can fail... '
Exit Sub
:TableTest_Error
If Err.Number = 3061 Then
Err.Clear()
DoSomething()
Else
MsgBox Err.Description ' or whatever you find appropriate '
End If
End Sub
Alternatively, you can switch off automatic error handling (e.g. breaking execution and displaying an error message) on a line-by-line basis:
Sub TableTest
' ... fail-safe code ... '
On Error Resume Next
' ...code that can fail... '
If Err.Number = 3061 Then
Err.Clear()
DoSomething()
Else
MsgBox Err.Description
End If
On Error Goto 0
' ...mode fail-safe code... '
End Sub
There are these statements available:
On Error Resume Next switches off VBA-integrated error handling (message box etc.) completely, execution simply resumes on the next line. Be sure to check for an error very early after you've used that, as a dangling error can disrupt the normal execution flow. Clear the error as soon as you caught it to prevent that.
On Error Goto <Jump Label> resumes execution at a given label, primarily used for per-function error handlers that catch all sorts of errors.
On Error Goto <Line Number> resumes at a given line number. Stay away from that, it's not useful, even dangerous.
On Error Goto 0 it's close cousin. Reinstates the VBA integrated error management (message box etc.)
EDIT
From the edited qestion, this is my proposal to solve your problem.
For Each FieldName In FieldNames ' assuming you have some looping construct here '
strsql3 = "SELECT " & FieldName & " FROM table"
On Error Resume Next
Set rs3 = CurrentDb.OpenRecordset(strsql3)
If Err.Number = 3061 Then
' Do nothing. We dont care about this error '
Err.Clear
Else
MsgBox "Uncaught error number " & Err.Number & " (" & Err.Description & ")"
Err.Clear
End If
On Error GoTo 0
Next FieldName
Be sure to clear the error in any case before you go on with a loop in the same Sub or Function. As I said, a dangling error causes code flow to become unexpected!
Rather than trapping the error, why not use the TableDefs to check for the field or use a mixture of ADO and DAO? ADO Schemas can provide a list of tables that contain the required field:
Function ListTablesContainingField()
Dim cn As New ADODB.Connection, cn2 As New ADODB.Connection
Dim rs As ADODB.Recordset, rs2 As ADODB.Recordset
Dim connString As String
Dim SelectFieldName
Set cn = CurrentProject.Connection
SelectFieldName = "Fall" 'For tksy '
'Get names of all tables that have a column called 'ID' '
Set rs = cn.OpenSchema(adSchemaColumns, _
Array(Empty, Empty, Empty, SelectFieldName))
'Show the tables that have been selected '
While Not rs.EOF
'Exclude MS system tables '
If Left(rs!Table_Name, 4) <> "MSys" Then
' Edit for tksy, who is using more than one forum '
If tdf.Name = "01UMWELT" Then
strSQL = "Select * From 01UMWELT Where Status = 5"
Else
strSQL = "Select a.* From [" & rs!Table_Name _
& "] a Inner Join 01UMWELT On a.fall = 01UMWELT.fall " _
& "Where 01UMWELT.Status = 5"
End If
Set rs2 = CurrentDb.OpenRecordset(strSQL)
Do While Not rs2.EOF
For i = 0 To rs2.Fields.Count - 1
If IsNull(rs2.Fields(i)) Then
rs2.Edit
rs2.Fields(i) = 111111
rs2.Update
End If
Next
rs2.MoveNext
Loop
End If
rs.MoveNext
Wend
rs.Close
Set cn = Nothing
End Function
Try this:
On Error Resume Next ' If an error occurs, move to next statement.
...statement that tries the select...
If (Err <> 0) Then
...act on error, or simply ignore if necessary...
End If
On Error Goto 0 ' Reset error handling to previous state.