views:

289

answers:

4

I have an sql server table with a timestamp column. Is there a way to force the timestamp column to change without an actual update of the record?

The reason I am asking is because I want the record's timestamp to change when a record is inserted/updated/deleted in a child table.

Timestamp may not be the best way to go about doing this. If not, what should I do? I don't want to use datetime because I don't feel that's a good way of versioning. I don't want to use an integer, because I don't want to have to read the value to increment it.

Suggestions?

+1  A: 

I don't want to use an integer, because I don't want to have to read the value to increment it.

UPDATE Table SET
    IntColumn = IntColumn + 1

While that does technically require a read, I don't see any problems with it.

You could always just update to the same value:

UPDATE Table SET
    SomeColumn = SomeColumn

which will trigger rowversion update as well.

ADDITION: You could do a view with the max rowversion of the children:

SELECT Parent.*, MaxChildRowVersion as ChildVersion
FROM Parent
JOIN (
    SELECT ParentId, MAX(RowVersion) as MaxChildRowVersion
    FROM Child
    GROUP BY ParentId
) as Child ON
     Parent.ParentId = Child.ParentId

But, no, you can't directly update a rowversion column (though you could implement your own updatable with @@DBTS, binary(8) and INSTEAD OF triggers...)

Could you give examples of your last point? It sounds promising.

No, really it doesn't. ;) It's too much work when you could just update to the same value instead or use a view. Those are the 2 easiest options.

But, to be complete, a binary(8) column with a default of @@DBTS (which returns the database version number), and an AFTER UPDATE trigger that also updates the binary column to the new @@DBTS will give you a psuedo-rowversion type that you can then update manually. It'd be no faster or better than just updating some other column to it's same value though.

Mark Brackett
Could you give examples of your last point? It sounds promising.
Ronnie Overby
+1  A: 

Have you looked into using triggers? It seems a more natural fit for what you're after.

I worked on an application that had timestamps across the board once upon a time; exactly what we were supposed to do with them proved to be kind of elusive so we audited them out of the schema. You could read timestamp in to objects you create based off of the data and check to see if it's changed when you go to update and rollback if you see that the data's dirty, but that's a lot of boilerplate for not a lot of gain (at least in the domain I was working in).

48klocs
I have actually. But I still need to do something in my trigger to get a timestamp column to update. That was my question.
Ronnie Overby
A: 

What I am going to do, until a better idea comes along, is to add a DateTime column to my parent table called DateChildrenChanged.

I will add a trigger on the child table that will set the DateChildrenChanged column to the current DateTime and when that happens, the timestamp column on the parent table will also be updated.

This way I'm using the timestamp column for versioning.

I'm still very open to ideas.

Ronnie Overby
I think that's the best way to go. Keep your TIMESTAMP/ROWVERSION for versioning of the actual row. If you need to version your child rows - have a TIMESTAMP/ROWVERSION column there, too
marc_s
+2  A: 

Ronnie,

First of all the timestamp syntax is being deprecated by Microsoft, so you need to use rowversion, second the rowversion is always related to the row.

From the documentation:

rowversion

Each database has a counter that is incremented for each insert or update operation that is performed on a table that contains a rowversion column within the database. This counter is the database rowversion.

However, because the way it's implemented in SQL server, you need to use triggers to achieve what you want.

Something like this:

CREATE TRIGGER tgUpdateParentRowVersion ON ChildTable FOR INSERT, DELETE, UPDATE
AS
BEGIN
   /*
    * The updates below force the update of the parent table rowversion
    */
   UPDATE ParentTable
      SET ChildUpdate = ChildUpdate + 1
     FROM ParentTable a 
     JOIN inserted    i on a.pkParentTable = i.fkParentTable

   UPDATE ParentTable
      SET ChildUpdate = ChildUpdate - 1
     FROM ParentTable a 
     JOIN deleted     d on a.pkParentTable = d.fkParentTable
END
Paulo Santos
Regarding deprecation, I though it was the other way around: rowversion was being deprecated. I could be wrong...
Ronnie Overby
@Ronnie: you **are** wrong and Paulo is right. TIMESTAMP is being deprecated since its name caused a lot of confusion (people thinking there was a way to convert that back to a date and time). ROWVERSION is the new way to go
marc_s
I stand corrected. Thanks.
Ronnie Overby