MS Access Error updating memo field with long text - vba

Searching this problem returns quite a few search hits, but many off-track answers, so I'm posting a concise description here, and answer below.
The problem afflicts Microsoft Access 2010, and some versions before. Access 2013 renames Memo type to Long Text. I don't know if it has the same problem.
The root problem is associated with running an UPDATE query on a table with a memo field, in certain particular circumstances. This might be an UPDATE query composed in the visual query window, or some VBA running SQL via DAO or ADO or similar. Or it could arise while updating via a form.
(The current post is concerned with this occurrence just within an Access database, though elsewhere you will find discussion of similar-sounding issues when Access is connected to an external database server.)
Instead of generating an immediate and obvious error alert, Access (or perhaps Jet) places the value #Error (which is not just the string "#Error"!) into the Memo field. This might easily go unnoticed until some later time, resulting in visible errors such as:
-- You use Compact and Repair. That seems to complete, but Access quietly adds a MSysCompactError table with a couple of rows. One error -1611 complains that Access was stopped and couldn't complete the operation. A second, more-specific-seeming error complains that it can't find field "Description". That appears to be an internal error that has no relevance.
-- You try to copy the table to another database. Access gives an error complaining that another user is using the table or has updated the table, and won't complete the operation.
-- Other operations on the rows that, unnoticed by you, happen to contain the #Error values fail.
Regardless, the root problem is whatever causes the #Error values to get placed into the Memo fields in the first place.
Many posters have noted that it occurs if the UPDATE attempts to put strings longer than about 2000 characters into the Memo field. That's a surprise, as Memo fields should be able to hold 1 gig characters or more depending on version, even if it only allows 65k through the UI.
So why does the error occur when Updating using >2000 characters?

The key factor that provokes this error is the Memo field having an index. Apparently, although the Memo type field can hold a bazillion characters, the index can't deal with more than about 2000.
Knowing that this is the precipitating factor, probably a number of workarounds come to mind. First, you can obviously just disable the index. This solution is easy to verify in a dummy database: Create two tables containing Memo fields, one with an index and the other without. Run update queries that put >2000 characters into each Memo and note the results.
But perhaps you think you need the index? Your use case might be satisfied if you create a second field that will contain an initial substring of the main Memo (shorter than 2000 characters), and index that instead. This could be used for sorting purposes for example. In most cases, where a memo contains narrative information, it's unlikely that the memo data values differ only after 2000 characters. Or perhaps you can devise a hash function and make a separate column of that.
What if you have a database that already contains these #Error values? Some advice floating around on the web, especially in relation to downstream problems like failure of Compact and Repair, suggests that your database is corrupt and should be abandoned. I'm not so sure. If you can delete the #Error-afflicted rows, then delete the index, and then recreate the deleted rows, you may be back in business. Compact and Repair should run properly at that point, giving some confidence that you fixed the offending part. (Make backups along the way, obviously.)

Workaround solution
Create two macros (Macro1 Macro2)
Macro 1
Get all the necessary information from the open form which includ this long text and close it.
Macro 2
Insert all needed actions (starting with the update query that you get error)
Create a form (Form_on_error) with only a button that run Macro2
Finally add at the end of macro 1
On Error
Go to :Macro Name
Macro Name: On_Error_2590
RunMacro Macro2
Submacro On_error_2590
OpenForm (Form_on_error)
End Submacro
.......and it works !!!
So, only when the update query get error, the user must click the button on the form : Form_on_error

Related

Preventing incomplete records from being added to table WITHOUT table change?

So I working on an Access form and ive noticed that when i dont fill out all the fields and close the form, the fields that i did fill out populate into my table as a sort of "incomplete" record which messes up my numbering increment system that i have going. Is there any way of discarding all data entered on form close without making certain fields required in the table properties? I dont want to do this because it gives a message when trying to close and i want to avoid that if possible
The issue of autonumbering incrementing, and that of not wanting to save record with missing fields or values are TWO HUGE different issues.
Try going to a new record, type in a few things, hit esc 2 times (or go to ribbon and use un-do and now exit form.
The record will now be blank and if you exit, then no record is created (however, the auto number will have incremented) So auto number incrementing and saving of records are two VERY DIFFERENT and separate things.
When you start typing into the blank new record on the form - the record becomes "dirty", and a auto number is incremented and assigned to that record.
if you don't want the record to be saved with missing things, then in the forms before update event, you can check for missing fields, or even bad or wrong values, and if you set cancel = true, the record will NOT be saved, nor created.
So, you don't need to set required in the table design. There are often ALL kinds of things you might want to check for. Say you might require first name or last name (one or the other - such things can't be done at table level. So you can have as complex record verification as you want. And as noted, in most cases, you can and would use the forms before update event.
However, preventing a blank record, or a record being saved with missing information? Sure, not problem - a common requirement.
The above has ZERO, but absolute ZERO to do with the autonumber issue.
Access will issue and set the autonumber as SOON as the first key is typed into that form. As noted, you can use undo, and upon exit, NO REOCRD will be created nor saved.
However, the autonumber created will be tossed out - and skipped. The reason for this is for multi-user operation. If two users move to a new blank record, then when one starts typing, the autonumber is assigned. (even if you don't save the record). when the 2nd user starts typing, they also get a autonumber. Now, if both users hit undo (or esc key), then both can exit, and you note that 2 autonumbers will have been skipped. As noted, access works this way so two users can't be assigned the same PK value when adding records.
As a result, autonumbers can NEVER be deemed to not skip. And of course what about deleting records - again, you have gaps.
Autonumbers cannot be used for say invoice numbers, or some kind of external value. Autonumbers can NEVER be assigned ANY more meaning then that of just some "random" like PK value. You can't use those numbers for external business use if such numbers are to say only be sequential without gaps.
If you need a business incrementing number, such as invoice, or job number or whatever? The you need to create your own column, and manage that incrementing in code. (such as assigning that number in the before update event - but as I noted, yo can also CANCEL that before update event for any old reason - including missing fields or even if this is a odd day of the week (any criteria that floats your boat can be used here, and thus when they exit you can prompt them and tell them that the record is incomplete. Or in those special cases, you can even let them exit without a save, but some kind of message probably is better.
So, if you don't want some incomplete record to be saved? Then put whatever you wish into the forms before update event - and set cancel = true (that event has a cancel option built EXACTLY for this purpose). However, that goal of saving, or preventing a record save has VERY LITTLE to do with the issue of not having gaps in the autonumber - that you can't control, and that you cannot prevent. (prevent gaps).
If you need some external business numbering system, you can't use autonumbers. In fact users should never even see autonumbers, and they are for you the developer to build relations between tables.
As such, these internal house keeping auto numbers cannot be used for external business process(s) that require some kind of sequential number without gaps, since that is not their purpose, and worse yet, you can't control or avoid gaps in such numbers anyway.
You can undo, but autonumbers increments means numbers will and are boing to be skipped as a normal operation of the database system.
Since that number is automatic and under control of the database system, and NOT you the developer, the you can only accept how it works and use it - but you can't change the behavour of that auto number. This applies to all and any database systems. In fact later versions of sql server will skip forward by 10,000 when you reboot.
If you don't want to save a record, then put in your code to prevent as such.
If you need a separate issue of some incrementing number for business use? Then add a column to the database and design the increment system to work whatever way you want - but you can't control the built in system, and its not designed with the goal you have here in mind anyway.

Microsoft Access Table Shows Up Blank, But Query Correctly Pulls Data From Table

I am having an issue with my Microsoft Access database. One of my tables looks completely blank, but it has 11632 records listed in the bottom. Take a look at this screenshot. Though the table shows up blank, when I run the query it pulls the correct data from this table, so I know the data is there, it is just not appearing for some reason. I have tried on Access 2013 and 2016 on a different computer, and both have the same effect. I have also tried compacting and repairing, and also exporting the table but the file it exports to also appears blank, aside from the field names. Any ideas on what I could try?
Thanks!
Turn your import into a 2 step process (or more...). Write it raw into a scratch pad table. Then fire an append query, that has the appropriate criteria to result in only valid records going into the final table.
This isn't unusual at all given that some outside data sources may not have the controls to prevent bad records. Sometimes one must "wash" the data with several different query criteria/steps in order to filter out the bad guys.

Check if something got committed after an update in Informix 4GL program

I have to check upon saving my 4GL program if changes were actually made in this update. Sometimes users will just update and save but no updates were actually made to the tables.
I would assume that throughout the update it must do a commit work to roll the changes into the table.
Is there any way for me to check at the end of the update if something actually got committed? Or? Any other suggestions?
I can't save previous_data and then compare with current_data since there are so many code in different places where updates can be done.
Thank you!
You can check the SQLCA record for the number of rows affected by the UPDATE immediately after it completes and before you do any other SQL operation (such as COMMIT). That may still count identity 'changes', but it the closest approximation to what you want that is available.
My interpretation of the question is you have something like
INPUT ...
...
END INPUT
IF int_flag THEN
# Don't update database
ELSE
# Update database
END IF
If the user accepts the dialog, the code to update the database is going to execute. If the user has not made any changes in the INPUT then this could be considered a waste of time.
I know with Genero, we have added syntax so that you can better detect that changes have occurred in the dialog and thus only update the database if a change has occurred. http://www.4js.com/online_documentation/fjs-fgl-manual-html/#c_fgl_prog_dialogs_touched_flag.html
If still on old 4gl, field_touched should be available to you. I know we can do
AFTER INPUT
IF int_flag THEN
EXIT INPUT
END IF
IF field_touched(*) THEN
# User has made a change in the dialog
and by using * test all fields in the dialog without explicitly having to list them, you may have to list the fields explicitly. So it might be simpler than you think to test after the dialog.
Similarly for complex data structures with records and arrays, in Genero we can do comparisons by parsing to JSON or XML, and then to string, so those techniques can also make the before/after comparison one liners.
Otherwise if you want to do the test after the database statement has executed, triggers might be an option for you. Create the triggers to insert a record into an audit table only if a genuine change has occurred in the UPDATE.

Table '' could not be loaded

I was hoping someone out there may have experienced this before.
I have a database that (as far as I'm aware) is in perfect working order. I have no problems with it whatsoever. I'm trying to add a column to some of the tables but when I save the changes I get the following message
This error message is then stuck in a loop and the only thing I can do is kill the SQL Management Studio process.
The database exists, the table exists, I can run any query I want against it, I just can't make any changes to it.
The steps I'm taking are:
Right click table
Select "design"
Right click "add new column" in designer
Fill in the details as normal
Click Save
Anyone know how I can resolve this?
Thanks.
It's telling you that you haven't specified the name of the table. The name of the table should be between the two single quotes.
Without knowing how you're doing this it's hard to tell more, but the first two possibilities off the top of my head are:
If you're looping through tables in code to do something, you may be hitting a record with no table name.
If it's pure SQL, perhaps an error in your syntax

Find or Strip Invalid characters from Database

We are using a database where the front end software has allowed the input of invalid characters. (I have no control or re-writing of the software.)
The types of characters are carriage returns, line breaks, �, ¶, basically anything that is not 0-9, a-z or standard punctuation causes us issues with the database and how we use the data.
I'm looking for a way to scan the entire database to identify these invalid codes and either display them as results or strip them out?
I had been looking at This site wondering if there was a way of searching for a certain range? But I might be barking up the wrong tree.
I'm fairly new to SQL so be gentle with me, thanks.
The only way I could think to do this would be to write a stored procedure which uses system tables to get a list of all fields in the database/schema in question. Have it exclude system tables (or only include those that are user defined) then dynamically write out SQL update statements based on the columns/tables found in the system table inquiries. Using regular expressions or character removal like in this article
The system tables in question are:
SELECT
table_name,column_name
FROM
information_schema.columns
Psudo code would be:
Get list of tables we want to do this for
For each table in list
get list of columns for table that have string data.
For each column in table
generate update statement to strip unwanted characters
--Consider writing out table, column key, before after values to history table. incase this
has to be undone.
--Consider counter so I have an idea of what was updated
execute updatestatement
next column
next table
write out counter
Since you say
the data then moves to a second program that cannot handle these
characters and this causes the process to fail.
I'm wondering if you can leave the unreadable data where it is and create a new column for changed data that's only populated if/when the 2nd process fails. You'll still have to test every character of the data in the failed cell, but you wouldn't have to test every character of every row. After you determine the updated text to process, you can call the 2nd process again with the updated value.