Is there a way to create a timestamp column in Oracle that automatically stores a timestamp of when the record has changed ?
Yes, via a trigger:
create or replace
TRIGGER schema.name_of_trigger
BEFORE INSERT OR UPDATE ON schema.name_of_table
FOR EACH ROW
BEGIN
:new.modified_on := SYSTIMESTAMP;
END;
This assumes your table has a field called modified_on.
As has been noted above, a trigger is an ideal candidate anytime you have multiple different places where the table gets updated. If you only have one function/procedure that can update the table, just do it there, and skip the trigger.
Tables I've modelled always include:
CREATED_USER
, VARCHAR2CREATED_DATE
, DATEUPDATED_USER
, VARCHAR2UPDATED_DATE
, DATE...columns. Why implement a trigger when you can set the value at the same time as the INSERT/UPDATE?
INSERT INTO TABLE (...CREATED_DATE, UPDATED_DATE) VALUES (...,SYSDATE, SYSDATE);
UPDATE TABLE
SET ...,
UPDATED_DATE = SYSDATE
For oracle I usually use a trigger to update the timestamp field
CREATE OR REPLACE TRIGGER update_timestamp
BEFORE INSERT OR UPDATE ON some_table
FOR EACH ROW
BEGIN
:NEW.TS := systimestamp;
END;
Oracle does not seem to have a built-in attribute for updating the timestamp field to the current timestamp (unlike other DBs like MySQL).
Pretty sure you have to do this with a trigger in Oracle:
create or replace TRIGGER parkedorder_tbiur
BEFORE INSERT OR UPDATE
ON parkedorder
REFERENCING OLD AS old_row NEW AS new_row
FOR EACH ROW
BEGIN
IF INSERTING
THEN
IF :new_row.ID IS NULL
THEN
SELECT parkedorder_seq.NEXTVAL
INTO :new_row.ID
FROM DUAL;
END IF;
END IF;
IF :new_row.lastupdated <> SYSDATE
OR :new_row.lastupdated IS NULL
THEN
SELECT sysdate
INTO :new_row.lastupdated
FROM DUAL;
END IF;
SELECT SYS_CONTEXT ( 'USERENV', 'OS_USER' )
INTO :new_row.lastupdatedby
FROM DUAL;
END;
Another way to deal with this is by turning on fine-grained audit. The individual rows won't have a timestamp, but you'll have a record of all changes. Overkill in most situations, though -- I usually just use triggers.
If you are OK with nearest .01 seconds, you can use date format and assign sysdate. If you need more detail, use the timestamp.
You can get very close to this by querying ORA_ROWSCN
: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/pseudocolumns007.htm#sthref825
This is more accurate if you created the table with the ROWDEPENDENCIES option.
It actually logs the commit time for the record ...
drop table tester
/
create table tester (col1 number, col2 timestamp)
rowdependencies
/
insert into tester values (1, systimestamp)
/
(approximate five second pause)
commit
/
select t.ora_rowscn,
SCN_TO_TIMESTAMP(t.ora_rowscn),
t.col1,
t.col2
from tester t
/
ORA_ROWSCN SCN_TO_TIMESTAMP(T.ORA_ROWSCN) COL1 COL2
---------------------- ------------------------------ ---------------------- -------------------------
9104916600628 2009-10-26 09.26.38.000000000 1 2009-10-26 09.26.35.109848000