Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting latest rowversion/timestamp value in update statement - Sql Server

I'm using rowversion columns for handling optimistic concurrency and want to get the new rowversion value back when I've done an update so that my data layer has the latest value and can perform another update with getting a concurrency exception (unless the record has been update by someone else).

I was just doing a get in the data layer after doing an update but this wasn't very efficient or perfectly reliable.

For the following table:

CREATE TABLE PurchaseType
(
    PurchaseTypeCode nvarchar(20) NOT NULL PRIMARY KEY CLUSTERED (PurchaseTypeCode),
    Name nvarchar(50) NOT NULL,
    TS rowversion NOT NULL
)

I tried:

CREATE PROCEDURE PurchaseType_UpdateWithGet
@PurchaseTypeCode nvarchar(20),
@Name nvarchar(50),
@TS rowversion OUTPUT    
AS

UPDATE PurchaseType
SET Name = @Name
WHERE PurchaseTypeCode = @PurchaseTypeCode
 AND TS = @TS

SELECT @TS = TS FROM PurchaseType WHERE PurchaseTypeCode = @PurchaseTypeCode
GO

but wasn't entirely happy because of the possibility of not getting the rowverion value from someone else's update. Then I came across the OUTPUT statement in rowversion documentation (http://msdn.microsoft.com/en-us/library/ms182776.aspx / http://msdn.microsoft.com/en-us/library/ms177564.aspx) and tried this:

CREATE PROCEDURE PurchaseType_UpdateWithOutput
@PurchaseTypeCode nvarchar(20),
@Name nvarchar(50),
@TS rowversion OUTPUT    
AS

DECLARE @Output TABLE (TS BINARY(8))

UPDATE PurchaseType
SET Name = @Name
    OUTPUT inserted.TS into @Output
WHERE PurchaseTypeCode = @PurchaseTypeCode
    AND TS = @TS

SELECT TOP 1 @TS = TS FROM @Output
GO

This works well. In my very basic tests (just running 10000 calls and timing it) the OUTPUT option takes about 40% longer but still less than half a millisecond. Neither took any measurable time with SET STATISTICS TIME ON.

My question is, does anyone know of a better/simpler way to do this?

I had hoped for a function I could use similar to SCOPE_IDENTITY() for identity columns but can't find anything like that. Anyone know if I'm missing something?

Thanks in advance.

like image 530
Simon Vane Avatar asked Jul 06 '12 08:07

Simon Vane


People also ask

Does sqlServer use rowversion/timestamp data?

I am relatively fresh to SQLServer's use of ROWVERSION / TIMESTAMP data, and normally just query for required rows based on modified dates. How is the ROWVERSION assigned to a new row in a database?

How to return the current rowversion value for a database?

If an update statement is run against the row, the rowversion value is updated. If no update statements are run against the row, the rowversion value is the same as when it was previously read. To return the current rowversion value for a database, use @@DBTS.

How do I get the last used rowversion in SQL Server?

You can use the @@DBTS function to get the current rowversion of a given database in SQL Server. More specifically, it returns the last-used rowversion value of the current database. To use the @@DBTS function, simply select it within a SELECT statement. As mentioned, the rowversion value is specific to each database.

How do I record the date and time in rowversion?

The rowversion data type is just an incrementing number and does not preserve a date or a time. To record a date or time, use a datetime2 data type. 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.


1 Answers

From MSDN:

@@DBTS returns the last-used timestamp value of the current database. A new timestamp value is generated when a row with a timestamp column is inserted or updated.

like image 94
Guillermo Gutiérrez Avatar answered Sep 21 '22 06:09

Guillermo Gutiérrez