rowversion (Transact-SQL)

データベース内で自動的に生成され、一意の 2 進数を公開するデータ型です。rowversion は、一般的にはバージョンを記録するテーブル行のメカニズムとして使用されます。記憶領域のサイズは 8 バイトです。データ型 rowversion は単に数値を加算していくだけのもので、日付や時刻を保持する機能はありません。日付や時刻を記録するには datetime2 型を使用します。

説明

各データベースには、データベース内の rowversion 列を含むテーブルで実行される Insert 操作または Update 操作ごとに増加するカウンタがあります。このカウンタは、データベース rowversion です。このカウンタは、時計に関連付けられる実際の時刻ではなく、データベース内の相対的な時間を追跡します。1 つのテーブルに許可される rowversion 列は、1 つだけです。rowversion 列のある行が変更または挿入されるたびに、増加したデータベース rowversion 値が rowversion 列に挿入されます。このため、rowversion 列はキー、特に主キーとして適切ではありません。行を更新すると rowversion 値が変わるので、キーの値も変わります。列が主キー内にある場合、以前のキーの値は無効になり、この以前の値を参照する外部キーも無効になります。動的カーソルでテーブルを参照する場合、すべての更新操作はカーソル上の行の位置を変更します。列がインデックス キー内にある場合、データ行を更新すると、インデックスも更新されます。

timestamp は rowversion データ型のシノニムであり、データ型のシノニムの動作が適用されます。DDL ステートメントでは、可能な限り timestamp ではなく rowversion を使用してください。詳細については、「データ型のシノニム (Transact-SQL)」を参照してください。

Transact-SQL timestamp データ型は、ISO 標準で定義されている timestamp データ型とは異なります。

注意

timestamp 構文は推奨されません。 この機能は、将来のバージョンの Microsoft SQL Server では削除される予定です。新しい開発作業では、この機能の使用を避け、現在この機能を使用しているアプリケーションは修正するようにしてください。

CREATE TABLE または ALTER TABLE ステートメントでは、timestamp データ型の列名を指定する必要はありません。次に例を示します。

CREATE TABLE ExampleTable (PriKey int PRIMARY KEY, timestamp);

列名を指定しない場合、SQL Server データベース エンジンは timestamp 列名を生成しますが、rowversion のシノニムの場合は動作が異なります。rowversion を使用する場合は、列名を指定する必要があります。次に例を示します。

CREATE TABLE ExampleTable2 (PriKey int PRIMARY KEY, VerCol rowversion) ;
注意

rowversion 列が SELECT リスト内にある SELECT INTO ステートメントを使用すると、重複する rowversion 値が生成される場合があります。このような rowversion は使用しないことをお勧めします。

NULL 値を許容しない rowversion 列は、binary(8) 列と同じ意味です。NULL 値を許容する rowversion 列は、varbinary(8) 列と同じ意味です。

行の rowversion 列を使用すると、行が前回読み取られて以降、行の値が変更されたかどうかがすぐにわかります。行が変更された場合、rowversion 値が更新されています。行が何も変更されていない場合、rowversion 値は前回の読み取り時と同じです。データベースの現在の rowversion 値を返すには、@@DBTS を使用します。

rowversion 列をテーブルに追加して、複数のユーザーが同時に行を更新しているときに、データベースの整合性を保つことができます。テーブルに対するクエリを再度実行せずに、行数や更新された行を把握する必要がある場合もあります。

たとえば、MyTest という名前のテーブルを作成するとします。次の Transact-SQL ステートメントを実行して、テーブルにいくつかのデータを入力します。

CREATE TABLE MyTest (myKey int PRIMARY KEY
    ,myValue int, RV rowversion);
GO 
INSERT INTO MyTest (myKey, myValue) VALUES (1, 0);
GO 
INSERT INTO MyTest (myKey, myValue) VALUES (2, 0);
GO

次に、以下のサンプル Transact-SQL ステートメントを使用して、更新中に MyTest テーブルにオプティミスティック同時実行制御を実装します。

DECLARE @t TABLE (myKey int);
UPDATE MyTest
SET myValue = 2
    OUTPUT inserted.myKey INTO @t(myKey) 
WHERE myKey = 1 
    AND RV = myValue;
IF (SELECT COUNT(*) FROM @t) = 0
    BEGIN
        RAISERROR ('error changing row with myKey = %d'
            ,16 -- Severity.
            ,1 -- State 
            ,1) -- myKey that was changed 
    END;

myValue は、行を前回読み取った時期を示す行の rowversion 列値です。この値は、実際の rowversion 値で置き換える必要があります。実際の rowversion 値は、0x00000000000007D3 などになります。

また、サンプル Transact-SQL ステートメントをトランザクションに置くことができます。トランザクションの範囲内で @t 変数に対してクエリを実行すると、MyTest テーブルに対するクエリを再度実行しなくても、テーブルの更新済みの myKey 列を取得できます。

timestamp 構文を使用した場合の同じ例を次に示します。

CREATE TABLE MyTest2 (myKey int PRIMARY KEY
    ,myValue int, TS timestamp);
GO 
INSERT INTO MyTest2 (myKey, myValue) VALUES (1, 0);
GO 
INSERT INTO MyTest2 (myKey, myValue) VALUES (2, 0);
GO
DECLARE @t TABLE (myKey int);
UPDATE MyTest2
SET myValue = 2
    OUTPUT inserted.myKey INTO @t(myKey) 
WHERE myKey = 1 
    AND TS = myValue;
IF (SELECT COUNT(*) FROM @t) = 0
    BEGIN
        RAISERROR ('error changing row with myKey = %d'
            ,16 -- Severity.
            ,1 -- State 
            ,1) -- myKey that was changed 
    END;