27

I know that the value itself for a RowVersion column is not in and of itself useful, except that it changes each time the row is updated. However, I was wondering if they are useful for relative (inequality) comparison.

If I have a table with a RowVersion column, are either of the following true:

  • Will all updates that occur simultaneously (either same update statement or same transaction) have the same value in the RowVersion column?
  • If I do update "A", followed by update "B", will the rows involved in update "B" have a higher value than the rows involved in update "A"?

Thanks.

David Pfeffer
  • 36,331
  • 28
  • 120
  • 198

8 Answers8

36

From MSDN:

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. This tracks a relative time within a database, not an actual time that can be associated with a clock. Every time that a row with a rowversion column is modified or inserted, the incremented database rowversion value is inserted in the rowversion column.

http://msdn.microsoft.com/en-us/library/ms182776.aspx

  • As far as I understand, nothing ACTUALLY happens simultaneously in the system. This means that all rowversions should be unique. I venture to say that they would be effectively useless if duplicates were allowed within the same table. Also giving credance to rowversions not being duplicated is MSDN's stance on not using them as primary keys not because it would cause violations, but because it would cause foreign key issues.
  • According to MSDN, "The rowversion data type is just an incrementing number..." so yes, later is larger.

To the question of how much it increments, MSDN states, "[rowversion] tracks a relative time within a database" which indicates that it is not a fluid integer incrementing, but time based. However, this "time" reveals nothing of when exactly, but rather when in relation to other rows a row was inserted/modified.

Brad
  • 14,569
  • 6
  • 34
  • 54
  • 4
    Brad: But does "later imply larger" across multiple rows, not just the same row? From the wording, it seems to indicate no, but experimentation seems to imply yes. – David Pfeffer Dec 17 '10 at 13:44
  • 6
    @Davied, The basis for the `rowversion` is database-based meaning that the value is somehow relative to a point in the database's past. Yes, later implies larger across the entire database. Think of it as a **database-wide identity** value. – Brad Dec 17 '10 at 13:46
13

Some additional information. RowVersion converts nicely to bigint and thus one can display better readable output when debugging:

CREATE TABLE [dbo].[T1](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Value] [nvarchar](50) NULL,
    [RowVer] [timestamp] NOT NULL
) 

insert into t1 ([value]) values ('a')
insert into t1 ([value]) values ('b')
insert into t1 ([value]) values ('c')
select Id, Value,CONVERT(bigint,rowver)as RowVer from t1
update t1 set [value] = 'x' where id = 3
select Id, Value,CONVERT(bigint,rowver)as RowVer from t1
update t1 set [value] = 'y' 
select Id, Value,CONVERT(bigint,rowver)as RowVer from t1

Id  Value   RowVer
1   a   2037
2   b   2038
3   c   2039

Id  Value   RowVer
1   a   2037
2   b   2038
3   x   2040

Id  Value   RowVer
1   y   2041
2   y   2042
3   y   2043
Peter Meinl
  • 2,466
  • 24
  • 36
  • Is it normal that your example show timestamp but in your statement you talk about rowversion? – Patrick Desjardins May 14 '13 at 12:56
  • 2
    timestamp is the synonym for the rowversion data type on MSSQL. But timestamp syntax is deprecated and be removed in a future version of Microsoft SQL Server. – endo64 Sep 29 '13 at 16:52
6

I spent ages trying to sort something out with this - to ask for columns updated after a particular sequence number. The timestamp is really just a sequence number - it's also bigendian when c# functions like BitConverter.ToInt64 want littleendian.

I ended up creating a db view on the table i want data from with an alias column 'SequenceNo'

SELECT     ID, CONVERT(bigint, Timestamp) AS SequenceNo
FROM         dbo.[User]

c# Code first sees the view (ie UserV) identically to a normal table

then in my linq I can join the view and parent table and compare with a sequence number

var users =  (from u in context.GetTable<User>()
                join uv in context.GetTable<UserV>() on u.ID equals uv.ID
                where mysequenceNo < uv.SequenceNo
                orderby uv.SequenceNo
                select u).ToList();

to get what I want - all the entries changed since the last time I checked.

user1587804
  • 93
  • 1
  • 7
  • Was looking for validation of this concept. – mdisibio Sep 03 '15 at 20:35
  • Only problem with this is that the rowversion is essentially an unsigned bigint which doesn't exist in SQLServer afaik. So the CONVERT wouldn't really do what you want once you get past the max signed bigint. – Matt Nov 17 '15 at 18:19
  • @matt if that max number is 9,223,372,036,854,775,807 I wouldn't be too concerned about reaching it in the timestamp column – MatthewToday Nov 23 '15 at 04:21
5

Just as a note, timestamp is deprecated in SQL Server 2008 onwards. rowversion should be used instead.

From this page on MSDN:

The timestamp syntax is deprecated. This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.

marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
Town
  • 14,143
  • 3
  • 47
  • 71
  • 1
    but if I execute `CREATE TABLE TBL(PriKey int PRIMARY KEY, VerCol rowversion) ; ` the data type of `VerCol` is `timestamp` ! what is the point?! – sepehr Jun 10 '17 at 07:06
  • 2
    Annoyingly, SSMS doesn't recognise rowversion as a valid datatype, only timestamp. – Steve Jones Apr 21 '18 at 15:19
  • At least the supervisors of the scripting kiddies at Redmond stepped in there and killed the "timestamp" concept only one version later. Hopefully the kiddies were fired after being asked to look up the words "time" and "timestamp" in a dictionary. On their way home, they would have figured out their timestamp had no information about _time_, and wondered if they could hope to ever get a job elsewhere. – Reversed Engineer Feb 14 '20 at 08:28
5

What makes you think Timestamp data types are evil? The data type is very useful for concurrency checking. Linq-To-SQL uses this data type for this very purpose.

The answers to your questions:

1) No. This value is updated each time the row is updated. If you are updating the row say five times, each update will increment the Timestamp value. Of course, you realize that updates that "occur simultaneously" really don't. They still only occur one at a time, in turn.

2) Yes.

Randy Minder
  • 43,558
  • 44
  • 173
  • 312
  • Your answer #1 seems to imply that the answer to my second question should be No, not yes. If the value is truly just an increment, let's for simplicity say that I have rows with values 1, 3, and 8. (Yes, I'm aware in reality these would be 8-byte arrays.) Wouldn't the updated values be 2, 4, and 9 if they're simply incremented, rather than them all being 9? This means a subsequent row updated, with an initial value of 5, would become 6 rather than 9, which is less than the values from the original. – David Pfeffer Dec 17 '10 at 13:36
  • 1
    @David - You are making this too complicated. Each time a row that contains a Timestamp column is updated, the value in that Timestamp column is incremented. I don't know how, or by how much. I just know it's incremented. Therefore, if 'A' updates and then 'B', after the 'B' update, the value in the Timestamp column will be greater than it was for 'A'. – Randy Minder Dec 17 '10 at 13:39
  • Randy: That doesn't make sense to me, but its possible I'm making it too complicated. If its a simple increment, and both rows start at the same value, then row A is updated and then row B is updated, shouldn't they have the *same* Timestamp (both should be 1 + the original) rather than B having a higher value than A? – David Pfeffer Dec 17 '10 at 13:41
  • @David - Ok, let's say you are updating 'A' and 'B' and both have the same Timestamp value to start with. After you update 'A', SQL Server has incremented the value in that row. Now they are not equal anymore ('A' is actually greater than the value in 'B' before the update). Now you update 'B'. SQL Server increments the value again, based on the value in the column after the 'A' update, not the original value in 'B'. After the 'B' update, the value in the row is greater than after the 'A' update. – Randy Minder Dec 17 '10 at 13:46
3

Rowversion does break one of the "idealistic" approaches of SQL - that an UPDATE statement is a single, atomic action, and acts as if all UPDATEs (both to all columns within a row, and all rows within the table) occur "at the same time". But in this case, with Rowversion, it is possible to determine that one row was updated at a slightly different time than another.

Note that the order in which rows are updated (by a single update statement) is not guaranteed - it may, by coincidence follow the same order as the clustered key for the table, but I wouldn't count on that being true.

Damien_The_Unbeliever
  • 220,246
  • 21
  • 302
  • 402
2

To answer part of your question: you can end up with duplicate values according to MSDN:

Duplicate rowversion values can be generated by using the SELECT INTO statement in which a rowversion column is in the SELECT list. We do not recommend using rowversion in this manner.

Source: rowversion (Transact-SQL)

Michiel van Oosterhout
  • 22,190
  • 14
  • 84
  • 123
0

Every database has a counter that is incremented one by one on every data modification that is done in the database. If the table containing the affected (by update/insert) row contains a timestamp/rowversion column, the current counter value of the database is stored in that column of the updated/inserted record.

Ilia Rostovtsev
  • 12,128
  • 10
  • 47
  • 80