Okay, I have built reports in MS Access 2007, and each report runs off of several (40+) queries. The queries are opening tables, subqueries, etc, and I don't think Access is closing them. I could be wrong, but for some reason I think this is causing the overflow.
But anyways, I am trying to figure out why it is happening all of a sudden, and what I can do to resolve it. I had the reports working fine when I just had a schema and some dummy data, but when the database was actually populated, the individuals who gave us the data created a few more look up tables, so now a typical query using 3 tables is now using 5.
Do you think this increase in look up tables (and therefore more objects being opened by Access) is the reason I am getting overflow errors, or could it be something else? Also, I don't know VBA, so are there any simple solutions (e.g. breaking up the reports, which would take a while) that would be worth pursuing?
Thanks
Make sure you really understand your "overflow" condition. This code displays "Error 6 (Overflow)", without the quotes, in the Immediate Window.
Dim i As Integer
Dim strMsg As String
On Error GoTo ErrorHandler
i = 32767
i = i + 1
ExitHere:
On Error GoTo 0
Exit Sub
ErrorHandler:
strMsg = "Error " & Err.Number & " (" & Err.description _
& ")"
Debug.Print strMsg
GoTo ExitHere
The explanation for that error is that 32,767 is the maximum value a VBA Integer can accept. So, attempting to add one would give 32,768 which is greater than an Integer can hold ... so overflow.
Other numeric data type also have limits. For example, 2147483647 is the maximum value which can be stored as a VBA Long.
I might be totally off base here, but I would check whether your complex report includes sorting and grouping options where perhaps you produce totals. And if so, whether the data you added pushes the values for any of those totals beyond the capacity of their respective data types.
If you're getting a different error message which includes the word "overflow", it might help to tell us the exact text of the error message.
Related
I have some VBA that programmatically updates the location of linked tables so that the front end of my database can be easily pointed at a different back end, without needing to click around in the Linked Table Manager. The technique is explained in this Microsoft blog post. This should be as simple as running the following code for each linked table in CurrentDb.TableDefs:
tableDef.Connect = ";DATABASE=" & newBackEndPath
tableDef.RefreshLink
However, when the table contains a multi-valued field, Access provides the following unhelpful and misleading error message:
Run-time error '3125':
'[table name]' is not a valid name. Make sure that it does not include invalid characters or punctuation and that it is not too long.
The same error appears when manually updating the links from the Linked Table Manager, although sometimes after a few attempts, the update will work without an error message. To work around the problem, I'm trying to refresh the link by creating a new TableDef and then renaming it over the old one:
Dim tdf As TableDef
Set tdf = CurrentDb.CreateTableDef(originalTableName & "_Copy")
tdf.Connect = ";DATABASE=" & newBackEndPath
tdf.SourceTableName = tableName
With CurrentDb.TableDefs
.Append tdf
.Refresh ' Required?
End With
RefreshDatabaseWindow ' Required?
DoEvents ' Required?
DoCmd.Rename originalTableNameName, acTable, originalTableNameName & "_Copy"
This usually works, but sometimes DoCmd.Rename throws the following run-time error:
Run-time error '7874':
Microsoft Access can't find the object '[table name]_Copy'.
If I enter the debugger, this usually triggers some kind of refresh and the _Copy table appears in the navigation pane. If I press F5 at this point, DoCmd.Rename executes with no problems. Clearly, there is some delay after the TableDef is appended before it can actually be found and renamed. I've added the TableDefs.Refresh, RefreshDatabaseWindow and DoEvents lines in an attempt to force the new table to appear, but they don't seem to help. Even forcing a delay of a few seconds doesn't seem to work, but somehow, opening the debugger does.
Is there any reliable way to refresh a linked table that contains a multi-valued field?
(I ignored the advice to avoid using multi-valued fields when I started this project, because I wanted users to be able to filter on multi-valued fields using the Quick Filters on a split form datasheet. This function is very helpful, but I'm beginning to wish I just built my own filtering UI after encountering this and numerous other bugs in the implementation of multi-valued fields.)
You could try a different approach altogether, by using DoCmd.TransferDatabase:
DoCmd.TransferDatabase acLink, "Microsoft Access", newBackEndPath, acTable, tableName, tableName
DoCmd.TransferDatabase is similar to using the GUI to link the table. It handles steps like refreshing the database pane for you. I usually recommend using TableDefs instead, but this situation might be an exception.
Of course, I support Sergey's advice to not use a multi-valued field. I'm a fan of the user experience of multi-valued fields and the associated comboboxes, but it has far-going consequences to use a MVF, like not being able to migrate your database to SQL server in the future
I am trying to use the recordset.Find "name =" & me.txtbox.value. To find a particular record/row. I can do this quite easily if i do it exactly as above searching only with 1 variable.
I tried to do the follow as i found other have done this online. traceRecordset.Find "[PART_ID]=" & Me.txtSection.Value & " AND " & "[ID]= " & Me.txtCopy.Value
this is the exact line of code that follows, the error does not throw on this line
Me.txtLastscrap = traceRecordset.Fields("APROPERTY_2")
This would give me more flexibility when populating a textbox with a particular value. It seems others have attempted this with no issues. However, i receive the following error.
Arguments are of the wrong type, are out of acceptable
range or are in conflict with one another
Any thoughts?
NOTE: if i do traceRecordset.Find "[PART_ID]=" & Me.txtSection.Value it works and it also works with traceRecordset.Find "[ID]= " & Me.txtCopy.Value so individually they function correctly. Only when used together does it throw an error. If the types were the issue one of them would not work when used independently correct?
NOTE2: Here is my adodb connection line. Not sure if this has any effect
Dim dbTrace As ADODB.Connection
Dim traceRecordset As New ADODB.Recordset
Set dbTrace = CurrentProject.Connection
traceRecordset.Open "Select * from TRACE", _
dbTrace, adOpenKeyset, adLockOptimistic, adCmdText
According to the ADO Recordset.Find documentation,
Only a single-column name may be specified in criteria. This method
does not support multi-column searches.
...
Criteria:
A String value that contains a statement specifying the column name, comparison operator, and value to use in the search.
Since you are already writing VBA within an Access project, DAO works just as well and as of Access 2016, the DAO Recordset type is still the default used by Forms and QueryDef objects. DAO recordsets support FindFirst, FindNext, FindPrevious and FindLast all supporting multi-column queries. This single feature might not justify switching from ADO, but if all you're doing is opening, searching and enumerating recordset rows, ADO doesn't provide any significant benefit.
I needed to copy some values from MS Access table into Excel using VBA code. I had done this many times and considered myself experienced. In my code I export the data using the following statements:
sh.range("A" & row).Value = rs("MyField")
where sh is Excel sheet, row is integer (long) and rs is recordset (either DAO or ADO, without any effect on the problem under consideration).
My code worked well on my computer with installed MS Office 2007. But when my client ran the code on his machine with MS Office 2010, it failed and kept failing very randomly. E.g. when debugging VBA in MS Access module step by step by pressing F8 it always worked. But when I pressed 'run' F5, it failed very soon.
After many trials and errors (I tried to open the recordset using different options and recordset types and caching the records etc.), I finally found that if I write
sh.range("A" & row).Value = rs("MyField").Value
everything works just fine. But according to the docs (e.g. http://msdn.microsoft.com/en-us/library/office/ff197799(v=office.15).aspx ) the Value property is the default property of the field object, which in turn is the default collection of the recordset object.
But it seems that I cannot rely on the defaultness, which I have been doing in most of my code. Actually I found a solution to my problem, but I still have no idea about the cause. Does anyone know why is the code doing this? What is the problem?
PS: I also found that if I expand the one-line statement into two lines (three with declaration):
dim v as Variant
v = rs("MyField")
sh.range("A" & row).Value = v
it also works...
Since rs("MyField") is a Field object, if you do ...
MsgBox TypeName(rs("MyField"))
... Access will tell you its type is Field.
So TypeName() is one example where the object itself is referenced directly instead of its default .Value property.
But something like Debug.Print always references .Value, so Debug.Print rs("MyField") is the same as Debug.Print rs("MyField").Value
If you know exactly when .Value will be referenced implicitly and when it will not, you can add it only when absolutely required and omit it the rest of the time.
However, some Access developers recommend always including .Value to avoid such confusion. If that seems like too much effort to you, at least consider including .Value when you do any assignment ...
something = rs("MyField").Value
... and be watchful for any other contexts where you don't get what you want without .Value
I am getting an Overflow error in Access when this line runs
intAT = Nz(DLookup("at_ID", "qryAT", "at_sc_ID=" & Me.sc_ID & " AND at_OT=0"), 0)
If I add Debug.Print Nz(DLookup("at_ID", "qryAT", "at_sc_ID=" & Me.sc_ID & " AND at_OT=0"), 0) just before that line, it prints the id number just fine, but still errors during the assignment on the next line.
I can also get it to work by adding a criterion to the query that limits all the results to those that occur before a certain day and time. It ONLY works limiting the query to before that particular time, not after an earlier time. If any of the records after that time are included, it overflows again. I have looked at the data that was entered after that time and it all seems fine, but I am not sure what exactly I should be looking for. The at_ID associated with the first record that causes it to fail is 32838 if that helps at all.
My guess is that intAT was declared as Integer type. But 32,838 is too large for an Integer. (Integer can hold numbers from –32,768 to 32,767) So it triggers error #6, "Overflow".
Use a Long Integer instead.
Dim lngAT As Long
lngAT = Nz(DLookup("at_ID", "qryAT", "at_sc_ID=" & Me.sc_ID & " AND at_OT=0"), 0)
I am writing a VBA function to import data from one table to another in Access. The table I'm importing into has more strict data constraints (i.e. types, size etc.), so I'm expecting a lot of errors.
Rather than sift through every VBA error that comes up, I want my recordset loop to skip the entire current record and make a note of it in a separate table whenever it runs into an error. So every other line I've inserted On Error GoTo RecordError. But for some reason it's not handling every error. My code just breaks and tells me what the error is. I have the "Break on Unhandled Exceptions" option checked already.
Here's a screenshot that should explain it.
Why would it be breaking on the line immediately following an Error handler?
I think you're not understanding how VB(A) error handling works. Follow these principles:
An On Error... statement only applies to the routine (Sub or Function) in which it appears (though it will also catch errors that "bubble up" from routines that are called from within the routine in which you use it).
On Error sets a state. That is, Once you issue an On Error... it remains in force for the rest of the routine, unless superceded by a new On Error....
There are four forms of On Error...:
On Error GoTo <label>: <label> must be defined in the same routine, by writing the label name immediately followed by a colon (:) on a line by itself.
On Error Resume: immediately retries the error-throwing statement. Hardly ever used, since it's potentially infinite.
On Error Resume Next: ignores the error & continues. Sometimes useful at the end of routines for cleanup (for instance, if you want to Close a Recordset that may or may not be open). Alternatively, this form can also be used if you check the Err object immediately after any potentially error-throwing line (if Err.Number is zero (0), the statement succeeded without throwing an error). This is way too much work for most situations.
On Error GoTo 0: turns off error handling.
Given this, it's usual to place the On Error... statement immediately followng the routine's declaration (the Sub or Function statement), though some people put their Dim statements in between. If you want to temporarily change the manner of error handling within a routine, put the "new" one right before the code to which it is to apply, and (if used), the "revert" (reissuing the original), right after.
Even given all that, I have no idea why it would break on the error-throwing line when "Break on Unhandled Errors" is selected, unless you've managed to confuse it so much that it thinks there's no active error handling (and I'd be surprised if it compiled if that were the case).
Note that David Heffernan gave you the essential part of this in his answer, and it was here before mine....
The reason it is not working is because you cannot use On Error Goto ... within an error handler.
see http://www.cpearson.com/excel/errorhandling.htm
you cannot use On Error to skip a few lines, instead on error should go to a error handler which then resume's to the desired next line (in your example you could probably get away with one error handler which contains a resume next which will take you back to the next field).
thanks to Tim Williams on this question: The second of 2 'On Error goto ' statements gets ignored
and BTW ParseInt on a ZIP will destroy zip codes that begin with a 0, zipcodes should probably be treated as text.
You need to place the On Error line before the code whose errors you wish to handle.
What's more you only need to have one On Error line. The error handler then stays active until the subroutine exits or you execute another On Error statement.
Error handling with VBA is a real PITA. I'd propose you to have a look at this answer to the 'MS-Access, VBA and error handling' question, and have it adapted to your own situation. You can easily write down some code that will store all your error messages in a table, building a de facto error reporting system.
Setting the debug mode to 'break on all errors' will make the program execution stop at the line that causes an error even when the error handler has been correctly written. This can be confusing as it appears that error handling is not working.
Nobody has really answered your question.
Say your code is something like this (a skeletal framework):
Public Sub MySub()
On Error GoTo errHandler
Dim rs As DAO.Recordset
Set rs = CurrentDB.OpenRecords([SQL SELECT])
If rs.RecordCount >0 Then
rs.MoveFirst
Do Until rs.EOF
[do whatever that produces the error]
errSkipToNext:
rs.MoveNext
Loop
End If
exitRoutine:
If Not (rs Is Nothing) Then
rs.Close
Set rs = Nothing
Exit Sub
errHandler:
Select Case Err.Number
Case X, Y, Z ' where these are error numbers you want to ignore
Err.Clear
' do whatever it is you need to do in order to record the offending row
Call RecordError(rs!PK, Err.Number) ' PK is a field that identifies the bad record
GoTo errSkipToNext
Case Else
MsgBox Err.Number & ": " & Err.Description, vbExclamation, _
"Error!"
Resume exitRoutine
End Select
End Sub
In this code, you use a SELECT CASE in your error handler to decide which errors you want to ignore. In my code framework above, I listed the error numbers as X, Y, Z, but you'd replace that with the real error numbers you want to ignore, instead.
You don't want to ignore every single error because you might end up ignoring important errors elsewhere in your subroutine. If you don't want to figure out what the limited number of errors you want to ignore happen to be, I would suggest that you set a flag at the beginning of the code block that produces the errors you want to ignore, then use an `If bolErrorInCodeBlockToIgnore Then to decide if you're ignoring all errors or not. Something like this:
Public Sub MySub()
On Error GoTo errHandler
Dim rs As DAO.Recordset
Dim bolErrorInCodeBlockToIgnore As Boolean
Set rs = CurrentDB.OpenRecords([SQL SELECT])
If rs.RecordCount >0 Then
rs.MoveFirst
Do Until rs.EOF
bolErrorInCodeBlockToIgnore = True
[do whatever that produces the error]
errSkipToNext:
rs.MoveNext
Loop
End If
exitRoutine:
If Not (rs Is Nothing) Then
rs.Close
Set rs = Nothing
Exit Sub
errHandler:
If bolErrorInCodeBlockToIgnore Then
Err.Clear
' do whatever it is you need to do in order to record the offending row
Call RecordError(rs!PK, Err.Number) ' PK is a field that identifies the bad record
bolErrorInCodeBlockToIgnore = False
GoTo errSkipToNext
Else
MsgBox Err.Number & ": " & Err.Description, vbExclamation, _
"Error!"
Resume exitRoutine
End If
End Sub
I would much prefer the first, as I'm a firm believer in only ignoring known errors, not any old error that happens. But it might be quite difficult to come up with tests that will produce all the possible errors you want to ignore.
I have seen error handling fail too. Here is one example.
Public Function Have(ByVal item As Variant) As Boolean
'Have = Have data. Simplifies handling nulls and empty strings in validation code
On Error GoTo Procerr
If IsNull(item) Then
Have = False
**ElseIf Len(Trim(item)) = 0 Then 'Faster than Item <> ""**
Have = False
ElseIf item = 0 Then
Have = False
Else
Have = True
End If
exitproc:
Exit Function
Procerr:
'Errors sometimes occur if an unbound control is referenced
Have = False
End Function
The code sometimes fails on the line flagged with **. Here is the error message.
Note that the error handler has failed. In this case, the form that called the code returned had its recordsource set on the fly to an empty recordset, hence the fields on the screen are not visible. The form is a continuous form, so records and fields are not visible when the form is loaded with an empty recordset. The have() function is not directly called by my code, but somehow seems to be triggered by the me.requery method. The have() has been called hundreds of millions of times in my code but this is the only instance that causes it to fail and the error handler is not involked.
To Lance Roberts re original question. utf-8 unicode can sometimes play havoc with ms-access as it seems to be allow data to be confused for instruction codes (my guess). utf-8 can get into your data if data was originally loaded from a text file. utf-8 with a byte order mark (BoM) is particularly nasty. When you run some procedure that works with the data, strange errors can occur and it may look like your file has become corrupt. In other cases, text handling functions give wrong answers, e.g. Mid() will see the BOM and if you specify a starting point will start at the BOM, but Len() ignores the BOM. I am speculating that if you have this issue, then ms-access may not handle errors correctly. I have had similar issues importing data and importing utf-8 as ANSI was the cause. Note that utf-8 and ANSI are identical most of the time for plain English data so your errors may not be on every line. My errors were mostly with time-date fields. Try exporting the data first and then forcing it to be ANSI and remove any BoM and and reimporting it.