今回は、SQLServerのIDENTITYプロパティについてお話していきたいと思います。
お仕事で使っていて、便利だけど注意することがありましたので今回記事としてまとめてみました。
IDENTITYプロパティとは?
IDENTITYプロパティとは、SQL Serverで自動的に連続した番号を生成することができる機能です。Oracleでの「シーケンス」に相当する機能になると思います。このIDENTITYプロパティは、テーブル作成時またはテーブル定義変更時に列に対して設定することで使用できます。
実際に、IDENTITYプロパティの動作を確認してみましょう。
以下のように動作確認用のテーブルを作成します。
CREATE TABLE test_table_1 ( num int IDENTITY(1, 1) ,col1 varchar(20) );
int型カラムのnumの後ろにある、IDENTITY(1, 1)がIDENTITYプロパティの設定部分です。
構文としては、IDENTITY(初期値, 増分値)となっていて、今回は初期値、増分値どちらも1を設定しています。ちなみに、このIDENTITYプロパティは1つのテーブルにつき1つだけ作成することができます。
また、設定対象のカラムのデータ型はint、bigint、smallint、tinyint、decimalのみ許可されています。varcharや、date型などのデータ型では指定することができません。decimalの場合は小数点以下を指定しなければ問題ないようです。
それでは、データをINSERTしてみます。IDENTITYプロパティは、INSERT時に自動的に連番が生成されます。
実行結果をみると、カラムnumにはIDENTITYプロパティの初期値である1が設定されていることが確認できます。
INSERT文を見るとIDENTITYプロパティを設定したカラムであるnumを指定していません。このようにIDENTITYプロパティを設定したカラム以外を指定して実行する必要があります。もし、カラム指定してINSERT文を実行した場合は、以下のようにエラーになります。
それでは、もう一度データをINSERTしてみましょう。結果を見ると、今度はカラムnumには2が設定されています。これは、IDENTITYプロパティの増分値に1を設定しているため、前の連番(1)に+1をした値である2が設定されていることになります。
IDENTITYプロパティの注意点①
上記までで、IDENTITYプロパティの基本的なことを確認しました。
これからは、IDENTITYプロパティを使っていくうえで理解しておくべき注意点をお話したいと思います。
2点ほどあるので、ここでは1つ目についてお話します。
実は、IDENTITYプロパティは完全な連番を生成することができません。
それについて、実際に動作を見ながら確認してみましょう。
以下は、明示的なトランザクションを開始してINSERT文を実行してSELECT文で実行結果を確認しています。
これをコミットせずにロールバックします。
そして、もう一度IDENTITYプロパティを使って連番を生成した場合は、先ほどINSERT文を実行したときに生成した連番(3)ではなくその次の値(4)で連番が生成されます。
上記のような挙動をするため、場合によってはIDENTITYプロパティを設定したカラムの値が飛び飛びとなって、データが作成されることを理解して使う必要があります。
IDENTITYプロパティの注意点②
次は、2つ目の注意点についてお話します。
個人的には1つ目の注意点は、そうなるんだなぁ~と思う程度でしたが、この2つ目の注意点でお話する挙動については驚きました。
実は、このIDENTITYプロパティは値の一意性を保証しません。
それはどういうことかというと、一つのトランザクションで複数のレコードをINSERTするようなケースの場合には同じID値(IDENTITYプロパティで付与される値)が設定されてしまう可能性があるということです。
再現するのが面倒なので(すみません)、ここで実際に確認はしませんが、以前お仕事で私が経験したときのお話をさせていただきます。
あるとき、IDENTITYプロパティを設定したテーブルに一つのトランザクションで複数のレコードを一度にINSERTするプログラムをテストしていました。
このIDENTITYプロパティを設定していたカラムは主キーになっていたのですが、このプログラムを実行すると、ときどき主キーの一意制約違反でエラーとなりました。
何回か実行してみると、あるときは正常終了して、あるときはエラーになるという驚きの挙動でした・・・
不思議に思いながら、IDENTITYプロパティの公式ページを見てみると、以下はその抜粋ですが値の一意性を保証しないことが記載されています。また、トランザクション内の連続した値も保証しないことが記載されているので、今回のプログラムでは同じID値(IDENTITYプロパティで付与される値)が取得されて、INSERT時に主キーの一意制約違反となっていることがわかりました。
上記のような挙動をするため、確実に連番を生成したい要件がある場合はアプリケーション側で採番の機能を実装する必要がありそうです。
おわりに
いかがでしたでしょうか。IDENTITYプロパティは、単純な連番を生成したい場合は簡単に使えるので非常に便利だと思います。
しかし、本記事でお話してきた注意点を考慮していないと場合によっては問題になるかもしれないので、しっかり理解しておく必要がありそうです。
今回も最後までお読みいただきありがとうございました。この辺で失礼いたします。