I have a need to audit changes where triggers are not performing well enough to use. In the audit I need to know exactly who made the change based on a column named LastModifiedBy (gathered at login and used in inserts and updates). We use a single SQL account to access the database so I cant use that to tie it to a user.
Scenario: Now we are researching the SQL transaction Log to determine what has changed. Table has a LastUpdatedBy column we used with trigger solution. With previous solution I had before and after transaction data so I could tell if the user making the change was the same user or a new user.
Problem: While looking at tools like DBForge Transaction Log and ApexSQL Audit I cant seem to find a solution that works. I can see the Update command but I can't tell if all the fields actually changed (Just because SQL says to update a field does not mean it actually changed value). ApexSQL Audit does have a before and after capability but if the LastUpdatedBy field does not change then I don't know what the original value is.
Trigger problem: Large data updates and inserts are crushing performance because of the triggers. I am gathering before and after data in the triggers so I can tell exactly what changed. But this volume of data is taking a 2 second update of 1000 rows and making it last longer than 3 minutes.
I have a SQL view created from normalized tables linked into Access. I created a form off of it to help control user access. I can make all the updates I want in the linked view, but - in the form - if I try to change a record I already updated I get the following error; "The data has been changed. Another user edited this record and saved the changes before you attempted to save your changes."
Dirty is set to False and all tables that will update have a timestamp.
Sounds like the auto form save event fires more than once.
You might want to have more control over the update transaction, with the following:
Do not link the form record source property to the table or query
Use queries to load data:
select based recordset as in Rst1 = dbCurr.OpenRecordset();
and update data using Rst1.update or action query DoCmd.RunSQL "UPDATE Query;"
Test the timestamp field before you save the changes.
The cost is you will need a bit more code to transfer data from the recordset/query to the FormFields and viceversa; plus you need to build a save or update button to initiate the data save transaction.
I was wondering how I would be able to update a table of mine without modifying the data. I have an application which allows users to enter data, but if they make a mistake they can modify the data entered. But when the user modifies the data it overwrites the data previously entered.
Is there a way of keeping the old data but if the user does modify the data it will show on another added column which may say, "data modified".
This is what I have taken from my application in the regional source
select "PROBLEM_ID",
"PROBLEM_TYPE_ID",
"DATE_REPORTED",
"DESCRIPTION",
"POSTCODE"
from "#OWNER#"."CS_PROBLEMS"
You can write a "post update for each row" trigger to save the old date in a history table. Or a "pre update for each row" trigger to set extra columns in the existing table. Then you can create a screen or procedure to retrieve the historical data. Or restore with a manual process.
I am really posting this out of desperation after searching around a lot for an answer and trying a few different things with no success.
I have an Access database where I have recently migrated the tables to SQL 2005, Access continues to function to the users as a front-end providing forms, reports, and queries.
However, since moving to the Access FE/SQL BE setup, the users have been reporting that sometimes, when they are entering a new record, they click into a subform (saving the record) or click save on the menu itself, it jumps to an existing record. The new record has been saved, but for some reason access switches to a different record as it refreshes. The user then has to close out, find the saved record, and continue editing it.
Scenario: A user is entering a quote and fills out all the quote details, customer,
date, etc, then clicks in the line-items subform to add a product (or clicks save in the menu), and suddenly
the quote form (and line-item subform) is showing the details of some random quote. The random quote could be recent, or from years ago, and has nothing in common with the quote they were entering.
This weird behavior only happens on inserting a new record, never on editing an existing record. Users tell me that it happens 'more often' when they go to add a new (quote, customer, whatever) after opening the database.
I have noticed it is only happening on forms that have subforms, so my first thought is that it had to do with Access sending through the subform data before the form data is saved, causing a PK violation. But this doesn't appear to be happening: there are no errors on the SQL server, and the record is successfully saved. Forcing the users to save the main form record before adding subform records (i.e. on a quote, forcing them to save the quote before they can add line items) didn't work, it just causes the jump (sometimes) on the save.
It isn't vba running on the save or on current, I have set breakpoints on all the event handlers as it jumps and no vba is being executed. Some of the 'jumping' forms have no vba on the form. But all have subforms. I suspect it has to do with record locking.
The server running the tables is SQL Server 2005, the users are using a mix of Access 2000 and 2003, mostly XP SP3 with a couple of old Win2k boxes. They are using Merge replication and a couple of users are running replicated SSEE2005 editions and subscribing to the main server. Most users are not replicated, just connecting directly to the server via ODBC or SQL native client connections. But I have verified that this is happening to all users, usually once or twice a day, and it has happened to me before. So it isn't a user issue.
The worst part about this behavior is that it only happens some of the time and I haven't managed to find a scenario that will always cause it to happen.
If anyone has experienced anything like this before, please let me know how you sorted it out, or even suggestions would be welcome.
Update:
(1/10/09) Problem solved, thanks to David Fenton. Setting the form to Data Entry mode (Form.DataEntry = true) before opening it to add records does indeed prevent the jumping. Client reports no issues at all since I changed this a week ago.
A client is reporting occasional similar problems. It started immediately after they started using merge replication.
I've informed several contacts within the Microsoft Access product group as well as my fellow Access and SQL Server MVPs.
Please email me your email address so I can forward that to my contacts at Microsoft as I would assume they would want to contact you directly. tony at granite.ab.ca
BTW excellent trouble shooting and detailed problem description.
It definitely sounds like a record locking issue. Are you using autonumbers as PK? Have you tried 2 computers adding a record on the same form at the same time (meaning one of them will fire the insert event while the other has added a new record on the form one but is still editing it)?
Could you check in a way or another if the PK of the inserted record after insertion in the table stays similar to the PK given before the insertion (by adding for example a few 'debug.print's to your code)?
A scenario could be 2 pending inserts been given by the machine the same PK, the second one being then automatically changed at insert time, resulting in your form loosing the 'active' record.
I'm wondering about the scenario where you are using a form to add records that has any other records for the user to jump to.
That is, I don't believe in using the same form to edit records as is used to create them.
Instead, I use an unbound dialog to collect all the required fields, insert the record in SQL, then open the main editing form to that single record (not a form with the whole table navigated to the record that was just added).
Keep in mind that in a main form/subform scenario, creating a record in the subform when the parent form is unsaved causes the parent record to be saved. You might want to check if there is any code in the Insert and Update events of the main form that would cause a requery of the main form on the insert of a new record (triggered by editing the subform).
But I would still suggest that the best architecture is to avoid this kind of possible scenario by loading only single records, so there is no other record to jump to. That would certainly limit the possibilities of where the user could end up when the problem occurs.
I have seen behavior 'like' this when there are multiple ways of doing the same thing. (i.e. tabbing out of the textbox triggering the lostfocus vs clicking a button) So make sure that this isn't the case, if you haven't already.
This problem is coused by merge replication trigger. In this trigger (this problem strart from sql 2005 server , in SQL 2000 server this not nake problems) replication insert some data in replication tables with identities and access get this number of identity instead real form indentity insert. I read that access use ##IDENTITY insetad of SCOPE_IDENTITY and this is problem . To avoid this you should change merge trigger in way that in insert trigger on begining you save current value from ##identity in variable and on the end of trigger insert value in temp table as identity with start value of what is written in variable. this will correct ##iddentity and acces will get right value.
at begin of trigger
DECLARE #identity int
DECLARE #strsql varchar(128)
set #identity=##IDENTITY
ar end something like
set #strsql='select identity(int,'+CAST(#identity as varchar(15)) +',1) as id into #temp'
exec(#strsql)
et the and it should be placed between
if ##error <> 0
goto FAILURE
and
return
Problem in acces will erace not only on form but directly in ODBC link table too.
I'm looking for way how to add this automaticly to merge replication trigger (mainly insert).
This is bug in Access and SQL comunication. Access take identity of new record from ##IDENTITY and when you finish entering record it reload data based on value from ##IDENTITY value from SQL. In SQL 200 inserted merge trigger and Acces usualy work ok. From SQL 2005 merge trigger have some part in which data are entered in some merge replication table which have identity to and change value of #IDDENTITY form that of newly entered rcord from Access.
One solution is to chanege all merege insert trigger to save #IDDENTITY on begining of it in variable and at the end of trigger insert dumy record in #temp table as identity column with starting value of variable previosly saved.
This solution I found somewhere the net when before week I was affected with this problem too. I was moving database from SQL 200 to SQL 2008 and then I found this problem with identity in Access. I suspect replication because when I was removing one of subscription all start to work well but after recreating it erased again.
I use this for solving problem (takem from somewhere on net).
at the begining of merge insert trigger
DECLARE #identity int
DECLARE #strsql varchar(128)
set #identity=##IDENTITY
and at the end of merge insert trigger
set #strsql='select identity(int,'+CAST(#identity as varchar(15)) +',1) as id into #temp'
exec(#strsql)
last code should be placed on the place of /*insert end on this place */ in merge replication code
if ##error <> 0
goto FAILURE
/*insert end on this place */
return
But I'm searching for a way to do that automaticly for all existing merge trigger on publication and on all existing merge trigger on existing and future subscriptions.
I'm slowly learning SQL and how to use form builder 6. The situation is I have a simple table named 'players' within the table I have three columns:
player_no (primary key)
position
goals
Within form builder 6 I have created a very simple form using these three fields. The form is named 'TEAM'. At at the foot of the form I have a button labelled 'Add'. The goal is for the user to enter a player_no, position and goals and then to click 'Add'. This information is then to go into my table.
All attempts so far have failed miserably. I have set up a trigger on the button (WHEN_MOUSE_CLICK). I have then entered the following code:
BEGIN
INSERT INTO players ( player_no )
VALUES ( :TEAM.player_no )
END
For the purpose of testing it out I have only been using the one (player_no) field. This then compiles with no errors yet when I run the form and enter a player_no and hit the button I get the following error in the status bar:
frm-40735: WHEN-MOUSE-CLICK trigger raised unhandled exception ORA-01400
Am I doing something horribly wrong? I am very much new to SQL and Form Builder so any help would be greatly appreciated.
ORA-01400: cannot insert Null seems like one of your fields are not null and you omited them on insert. or value :TEAM.player_no is null during insert.
Also, somewhere from web:
FRM-40735: ON-INSERT trigger raised
unhandled We have had similar problem
since 11.5.9. We clear Jinitiator
cache, and temporary internet files
(tools>internet options then under
temporary internet files the clear
files button). Seems to work.
One of the benefits of using Form Builder is that you almost always don't need to write the DML statements yourself.
Just make the block based on the table - then the user can add and modify as many records as they like, then when they save (i.e. COMMIT), the Forms runtime automatically works out what INSERTs and UPDATEs are required to save the changes.