I'm design a new db schema for a SQL Server 2012 database.
Each table should get two extra columns called modified
and created
which should be automatically change as soon a row gets inserted or updated.
I don't know how rather the best way to get there.
I assuming that trigger are the best way to handle it.
I was trying to find examples with triggers.. but the tutorials which I found insert data in another table etc.
I assumed it's a quite common scenario but I couldn't find the answer yet.
6条答案
按热度按时间6tr1vspr1#
The
created
column is simple - just aDATETIME2(3)
column with a default constraint that gets set when a new row is inserted:So when you insert a row into
YourTable
and don't specify a value forCreated
, it will be set to the current date & time.The
modified
is a bit more work, since you'll need to write a trigger for theAFTER UPDATE
case and update it - you cannot declaratively tell SQL Server to do this for you....and then
You need to join the
Inserted
pseudo table which contains all rows that were updated with your base table on your primary key for that table.And you'll have to create this
AFTER UPDATE
trigger for each table that you want to have amodified
column in.7y4bm7vi2#
Generally, you can have the following columns:
where
LastModifiedBy
andCreatedBy
are references to ausers
table (UserID
) and theLastModifiedOn
andCreatedOn
columns are date and time columns.You have the following options:
So, just edit all you
INSERT
andUPDATE
statements to include the currentUserID
and current date and time. If suchuser ID
can not be defined (anonymous user) you can use0
instead and the default value of the columns (in case nouser ID
is specified will beNULL
). When you seeNULL
values are inserted you should find the "guilty" statements and edit it.AFTER INSERT, UPDATE
trigger and populated the users columns there. It's easy to get the current date and time in the context of the trigger (useGETUTCDATE()
for example). The issue here is that the triggers do not allowed passing/accepting parameters. So, as you are not inserting theuser ID
value and you are not able to pass it to the trigger. How to find the current user?You can use SET CONTEXT_INFO and CONTEXT_INFO . Before all you
insert
andupdate
statements you must use theSET CONTEXT_INFO
to add thecurrent user ID
to the current context and in the trigger you are using theCONTEXT_INFO
function to extract it.So, when using triggers you again need to edit all your
INSERT
andUPDATE
clauses - that's why I prefer not to use them.Anyway, if you need to have only date and time columns and not created/modified by columns, using triggers is more durable and easier as you are not going to edit any other statements now and in the future.
With
SQL Server 2016
we can now use the SESSION_CONTEXT function to read session details. The details are set using sp_set_session_context (asread-only
orread and write
). The things are a little bit user-friendly:A nice example .
wztqucjr3#
Attention, above works fine but not in all cases, I lost a lot of time and found this helpfull:
set nocount on;
is needed else you get the error:q9rjltbz4#
vxf3dgd45#
One important thing to consider is that you should always have the inserted / updated time for all of your tables and rows be from the same time source. There is a danger - if you do not use triggers - that different applications making direct updates to your tables will be on machines that have different times on their clocks, or that there will not be consistent use of local vs. UTC in the application layer.
Consider a case where the system making the insert or update query that directly sets the updated / modified time value has a clock that is 5 minutes behind (unlikely, but worth considering) or is using local time versus UTC. If another system is polling using an interval of 1 minute, it might miss the update.
For a number of reasons, I never expose my tables directly to applications. To handle this situation, I create a view on the table explicitly listing the fields to be accessed (including the updated / modified time field). I then use an INSTEAD OF UPDATE, INSERT trigger on the view and explicitly set the updatedAt time using the database server's clock. This way I can guarantee that the timebase for all records in the database is identical.
This has a few benefits:
It works great on SQL Azure.
Take a look at this example of the trigger on the view:
I hope this helps, and I would welcome comments if there are reasons this is not the best solution.
m528fe3b6#
This solution might not work for all use cases but wherever possible its a very clean way. Create an stored procedure for inserting/updating row in table and only use this sp for modifying the table. In stored procedure you can always set created and updated column as required. e.g. setting updatedTime = GetUTCTime()