Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the practical use of timestamp column in sql server with example?

Tags:

sql-server

I came across the timestamp datatype in sql server.What is the practical use of timestamp column in sql server with example?

like image 223
satyajit Avatar asked Jul 21 '13 02:07

satyajit


People also ask

What is the use of TIMESTAMP in SQL Server?

You can use the timestamp column to just give return the rows that have changed since a point in time (by providing the previous timestamp).

What is the purpose of using the TIMESTAMP data type?

The TIMESTAMP datatype is an extension of the DATE datatype. It stores year, month, day, hour, minute, and second values. It also stores fractional seconds, which are not stored by the DATE datatype.

What is TIMESTAMP column in SQL Server?

Timestamp is a synonym for rowversion. Rowversion data type is not a date or time 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. This counter is the database rowversion.

Where do we use TIMESTAMP?

Timestamps are used for keeping records of information online or on a computer. A timestamp displays when certain information was created, exchanged, modified or deleted. The following are examples of how timestamps are used: Computer files may contain a timestamp that shows when the file was last changed.


2 Answers

I have used TIMESTAMP data type (ROWVERSION, SQL2005+) to avoid the lost update problem:

The lost update problem: A second transaction writes a second value of a data-item (datum) on top of a first value written by a first concurrent transaction, and the first value is lost to other transactions running concurrently which need, by their precedence, to read the first value. The transactions that have read the wrong value end with incorrect results.

Example: lost update:

t  : User 1 read payment order (PO) #1 (amount 1000) t+1: User 2 read payment order (PO) #1 (amount 1000)  t+2: User 1 change the amount for PO #1 to 1005 t+3: User 2 change the amount for PO #1 to 1009 (change make by User 1 is lost because is overwritten by change make by User 2) t+4: The amount is **1009**. 

Example: How to prevent the lost update:

t  : User 1 read payment order (PO) #1 (amount 1000, timestamp 0x00000000000007D1) t+1: User 2 read payment order (PO) #1 (amount 1000, timestamp 0x00000000000007D1)  t+2: User 1 change the amount for PO #1 to 1005 and it checks if row has the same `timestamp` (column `RW` in this case; 0x00000000000007D1). The check succeeds and the change is `COMMIT`ed. This will change, also, the timestamp (column 'RW'). The new timestamp is 0x00000000000007D4. t+3: User 2 change the amount for PO #1 to 1009 and it checks if row has the same `timestamp` (column `RW` in this case; 0x00000000000007D4). The checks fails because the initial timestamp (@rw=0x00000000000007D1) is <> than current timestamp (column `RW`=0x00000000000007D4). An error is raised the catch block "intercepts" the error and this transaction is cancelled (`ROLLBACK`). t+4: The amount {remains|is} **1005**. 

Example: T-SQL script for How to prevent the lost update (warning: you have to use two SSMS windows/two sessions)

CREATE DATABASE TestRowVersion; GO USE TestRowVersion; GO  CREATE TABLE dbo.PaymentOrder(     PaymentOrderID INT IDENTITY(1,1) PRIMARY KEY,     PaymentOrderDate DATE NOT NULL,     Amount NUMERIC(18,2) NOT NULL,     CreateDate DATETIME NOT NULL DEFAULT (GETDATE()),     UpdateDate DATETIME NULL,     RW ROWVERSION NOT NULL -- R[ow] V[ersion] ); GO  INSERT  dbo.PaymentOrder (PaymentOrderDate,Amount) VALUES  ('2013-07-21',1000); INSERT  dbo.PaymentOrder (PaymentOrderDate,Amount) VALUES  ('2013-07-22',2000); INSERT  dbo.PaymentOrder (PaymentOrderDate,Amount) VALUES  ('2013-07-23',3000); GO  SELECT * FROM dbo.PaymentOrder; /* PaymentOrderID PaymentOrderDate Amount  CreateDate              UpdateDate RW -------------- ---------------- ------- ----------------------- ---------- ------------------ 1              2013-07-21       1000.00 2013-07-21 09:35:38.750 NULL       0x00000000000007D1 2              2013-07-22       2000.00 2013-07-21 09:35:38.750 NULL       0x00000000000007D2 3              2013-07-23       3000.00 2013-07-21 09:35:38.750 NULL       0x00000000000007D3 */ GO  -- User 1 (SQL Server Management Studio/SSMS window #1)     -- [t] Client app, user 1: it loads first PO     SET NOCOUNT ON;     GO     DECLARE @PaymentOrderID INT=1;  -- parameter      SELECT  po.PaymentOrderID,             po.PaymentOrderDate,             po.Amount,             po.RW      FROM    dbo.PaymentOrder po      WHERE   po.PaymentOrderID=@PaymentOrderID;      -- Client app, user 1: during 15 seconds it edit the amount from 1000.00 to 1005.00     WAITFOR DELAY '00:00:15';     GO      -- [t+2] Client app, user 1: it sends this change (new amount) from client app to database server      -- with the old row version value     DECLARE @PaymentOrderID INT=1;              -- parameter     DECLARE @rw BINARY(8)=0x00000000000007D1;   -- parameter     DECLARE @NewAmount NUMERIC(18,2)=1005.00;   -- parameter      BEGIN TRY         BEGIN TRANSACTION             UPDATE  dbo.PaymentOrder             SET     Amount=@NewAmount             WHERE   PaymentOrderID=@PaymentOrderID             AND     RW=@rw; -- it checks the timestamp (current timestamp versus original timestamp)             DECLARE @rowcount INT=@@ROWCOUNT; -- How many rows were affected by the last statement (UPDATE in this case) ?             SELECT @rowcount AS [@@ROWCOUNT];             IF @rowcount<>1                 RAISERROR('Lost update or row deleted.', 16, 1);         COMMIT TRANSACTION         PRINT 'UPDATE succeded';     END TRY     BEGIN CATCH         IF @@TRANCOUNT>0             ROLLBACK;          DECLARE @ErrMsg NVARCHAR(2002);         SET @ErrMsg=ERROR_MESSAGE();         RAISERROR(@ErrMsg,16,1);     END CATCH;     GO      -- [t+4] Client app, user 1: it reloads first PO     DECLARE @PaymentOrderID INT=1;  -- parameter      SELECT  po.PaymentOrderID,             po.PaymentOrderDate,             po.Amount,             po.RW      FROM    dbo.PaymentOrder po      WHERE   po.PaymentOrderID=@PaymentOrderID;       GO  -- User 2 (warning: run this script in another SQL Server Management Studio window: File > New Database Engine Query !; SSMS window #2)     -- [t+1] Client app, user 1: it loads first PO     SET NOCOUNT ON;     GO     DECLARE @PaymentOrderID INT=1;  -- parameter      SELECT  po.PaymentOrderID,             po.PaymentOrderDate,             po.Amount,             po.RW      FROM    dbo.PaymentOrder po      WHERE   po.PaymentOrderID=@PaymentOrderID;      -- Client app, user 1: during 20 seconds it edit the amount from 1000.00 to 1005.00     WAITFOR DELAY '00:00:20';     GO      -- [t+4] Client app, user 1: it sends this change (new amout) from client app to database server      -- with the old row version value     DECLARE @PaymentOrderID INT=1;              -- parameter     DECLARE @rw BINARY(8)=0x00000000000007D1;   -- parameter     DECLARE @NewAmount NUMERIC(18,2)=1009.00;   -- parameter      BEGIN TRY         BEGIN TRANSACTION             UPDATE  dbo.PaymentOrder             SET     Amount=@NewAmount             WHERE   PaymentOrderID=@PaymentOrderID             AND     RW=@rw; -- it checks the timestamp (current timestamp versus original timestamp)             DECLARE @rowcount INT=@@ROWCOUNT; -- How many rows were affected by the last statement (UPDATE in this case) ?             SELECT @rowcount AS [@@ROWCOUNT];             IF @rowcount<>1                 RAISERROR('Lost update or row deleted.', 16, 1);         COMMIT TRANSACTION         PRINT 'UPDATE succeded';     END TRY     BEGIN CATCH         IF @@TRANCOUNT>0             ROLLBACK;          DECLARE @ErrMsg NVARCHAR(2002);         SET @ErrMsg=ERROR_MESSAGE();         RAISERROR(@ErrMsg,16,1);     END CATCH;     GO      -- [t+4] Client app, user 1: it reloads first PO     DECLARE @PaymentOrderID INT=1;  -- parameter      SELECT  po.PaymentOrderID,             po.PaymentOrderDate,             po.Amount,             po.RW      FROM    dbo.PaymentOrder po      WHERE   po.PaymentOrderID=@PaymentOrderID;       GO 

Results for User 1 (Amount 1000 -> 1005):

PaymentOrderID PaymentOrderDate Amount                                  RW -------------- ---------------- --------------------------------------- ------------------ 1              2013-07-21       1000.00                                 0x00000000000007D1  @@ROWCOUNT <- Timestamp check succeeds  ----------- 1  UPDATE succeded PaymentOrderID PaymentOrderDate Amount                                  RW -------------- ---------------- --------------------------------------- ------------------ 1              2013-07-21       1005.00                                 0x00000000000007D4 

Results for User 2 (Amount 1000 -> 1009):

PaymentOrderID PaymentOrderDate Amount                                  RW -------------- ---------------- --------------------------------------- ------------------ 1              2013-07-21       1000.00                                 0x00000000000007D1  @@ROWCOUNT <- Timestamp check fails  ----------- 0  Msg 50000, Level 16, State 1, Line 27 Lost update. PaymentOrderID PaymentOrderDate Amount                                  RW -------------- ---------------- --------------------------------------- ------------------ 1              2013-07-21       1005.00                                 0x00000000000007D4 

Note: changed the error message to RAISERROR('Lost update or row deleted.', 16, 1);

like image 197
Bogdan Sahlean Avatar answered Oct 07 '22 20:10

Bogdan Sahlean


Let's take an example of a sale order table to illustrate what timestamp does.

create table saleorder (ordernumber int, amount int, timestamp); insert into saleorder (ordernumber, amount) values (1, 100), (2, 100), (3, 200); select * from saleorder 

Notice the data in timestamp column. Documentation of timestamp (SQL Server 2005) says: This (i.e. timestamp) 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 timestamp column is modified or inserted, the incremented database timestamp value is inserted in the timestamp column.

Let's see how the data looks like:

ordernumber amount  timestamp 1           100     0x00000000000007D1 2           100     0x00000000000007D2 3           200     0x00000000000007D3 

Alright. Order 1 was added first and order 3 was entered last. What happens if we were to update amount of order 1?

update saleorder set amount = 200 where ordernumber = 1 select * from saleorder 

Ah, notice that order 1's timestamp is now 0x7D4 (Decimal 2004). In relation to other rows, we know that order 1 was updated most recently. But, more importantly, the value of timestamp comes when concurrent writes are happening.

ordernumber amount  timestamp 1           200     0x00000000000007D4 2           100     0x00000000000007D2 3           200     0x00000000000007D3 

Let's say John and Mary are both in sales attending to order 3 using a web application developed in, say, .NET. John pulls up the order and makes changes. John hasn't saved the data yet. Mary pulls the same order and changes it. John saves first. Mary attempts to save the data. .NET application can first look to see if the timestamp Mary pulled is still the same that the database has for order 3.

If the timestamp Mary pulled with order 3 is now different (because John saved data and timestamp automatically got changed), the .NET application can alert Mary and ask her to refresh the record on her screen to see the latest change (or probably highlight the change on-screen).

Think of timestamp as a row version. Interestingly, SQL Server's latest editions use rowversion datatype, which is synonymous with timestamp datatype. Documentation of rowversion (SQL Server 2012) has some interesting examples.

like image 41
zedfoxus Avatar answered Oct 07 '22 18:10

zedfoxus