Index to all the "Audit Trail" posts
February 23, 2008 Tip: Triggering an Audit Trail
February 28, 2009 Revisited: Triggering an Audit Trail
March 24, 2009 ALTER TABLE and the Audit Trail
March 18, 2013 Reporting and the Audit Trail
I'm really glad Jeff Atwood's given me permission to reinvent the wheel because the code in Tip: Triggering an Audit Trail needed work.
It's pretty much a rewrite, not a refactoring:
- the audit log of table t is now called logged_t instead of t_log so all the logged_* tables appear separately in an alphabetic list instead of mixed in with the base tables.
- The log_id column is now UNSIGNED because you never know when you might need another bazillion rows :)
- The values allowed in logged_action are now defined in a CHECK constraint. Feel free to drop that constraint, it's more for documentation than anything else since the trigger is the only piece of code that fills in a value... on the other hand, there's no safety like safety.
- The values in logged_action have been expanded for clarity, and a new one added: 'before UPDATE'.
- The before- and after-images of updated rows are stored instead of just the after-images. In this case the value of logged_at is set explicitly so both before- and after-images have exactly the same value.
- The logged_action column is defined as VARCHAR ( 50 ) instead of the minimum required VARCHAR ( 13 ) so folks don't have accidents when translating the code to different languages. There's no difference in storage efficiency or performance between the two definitions; that depends on the amount of data stored, not the declaration of maximum length.
- The logged_description and logged_by columns have been dropped because this application doesn't need them. If you do, see the original Tip: Triggering an Audit Trail.
- The three audit-related columns are all located at the front of the logged_t row, for efficiency. This no longer gives Foxhound a reason to produce "long columns (max length 100 or more) not all at end of row" messages in the Table-level Curiosities section. If the base table t does have all its long columns at the end of the row, they are also at the end of row in logged_t.
CREATE TABLE exchange_rate ( from_currency_to_currency VARCHAR ( 50 ) NOT NULL PRIMARY KEY, exchange_rate DECIMAL ( 15, 5 ) NOT NULL, updated_at TIMESTAMP NOT NULL DEFAULT TIMESTAMP ); CREATE TABLE logged_exchange_rate ( log_id UNSIGNED BIGINT NOT NULL DEFAULT AUTOINCREMENT PRIMARY KEY, logged_action VARCHAR ( 50 ) NOT NULL CHECK ( logged_action IN ( 'after INSERT', 'before UPDATE', 'after UPDATE', 'before DELETE' ) ), logged_at TIMESTAMP NOT NULL DEFAULT TIMESTAMP, -- Columns from table to be logged... from_currency_to_currency VARCHAR ( 50 ), exchange_rate DECIMAL ( 15, 5 ), updated_at TIMESTAMP ); CREATE TRIGGER log_exchange_rate AFTER INSERT, UPDATE, DELETE ON exchange_rate REFERENCING OLD AS old_exchange_rate NEW AS new_exchange_rate FOR EACH STATEMENT BEGIN DECLARE @current_timestamp TIMESTAMP; CASE WHEN INSERTING THEN INSERT logged_exchange_rate WITH AUTO NAME SELECT 'after INSERT' AS logged_action, * FROM new_exchange_rate; WHEN UPDATING THEN SET @current_timestamp = CURRENT TIMESTAMP; INSERT logged_exchange_rate WITH AUTO NAME SELECT 'before UPDATE' AS logged_action, @current_timestamp AS logged_at, * FROM old_exchange_rate; INSERT logged_exchange_rate WITH AUTO NAME SELECT 'after UPDATE' AS logged_action, @current_timestamp AS logged_at, * FROM new_exchange_rate; WHEN DELETING THEN INSERT logged_exchange_rate WITH AUTO NAME SELECT 'before DELETE' AS logged_action, * FROM old_exchange_rate; END CASE; END; INSERT exchange_rate VALUES ( 'USD/CAD', 1.25210, DEFAULT ); UPDATE exchange_rate SET exchange_rate = 1.25211; DELETE exchange_rate; INSERT exchange_rate VALUES ( 'USD/CAD', 1.25212, DEFAULT ); COMMIT; SET TEMPORARY OPTION TIMESTAMP_FORMAT = 'YYYY-MM-DD HH:NN:SS.SSSSSS'; BEGIN SELECT * FROM exchange_rate; SELECT * FROM logged_exchange_rate ORDER BY log_id; END;
2 comments:
hii
it is not working properly,it gives me error of many keywords like Autoincrement,timestamp,after when,current,auto,case.i am using sql server 2005.can u explain how can i create trigger properly?
please give me reply asap.
my id is sonal.2086@gmail.com
SQL Anywhere is an actual database product, not just the name of this blog. No, this trigger will not work in SQL Server because THAT product lacks many features available in SQL Anywhere. See http://www.sqlservercentral.com/articles/software+development/71354/
Post a Comment