T-SQL: SEQUENCE を使って連続したシーケンス番号を振る方法
SEQUENCE を使って連続したシーケンス番号を振る方法
前回 「 SEQUENCE を使ってシーケンス番号を振る方法 」 では、SEQUENCE オブジェクトを生成し、NEXT VALUE FOR を使ってシーケンス番号を生成してみました。
NEXT VALUE FOR を使ってシーケンス番号を生成すると、もし他のプロセスも同時にシーケンス番号を生成していた場合、番号が飛び飛びになる可能性があります。
どうしても番号が飛んでほしくない時は sp_sequence_get_range を使って、シーケンス番号を一度にまとめて取得することができます。
今回は、sp_sequence_get_range を使ってシーケンス番号を一度にまとめて取得して利用する方法をご紹介します。
SEQUENCE オブジェクトを生成する
今回使用する 「 1 から始まって 1 ずつ増える SEQUENCE オブジェクト 」 の TestSequence2 を以下のスクリプトを実行して作成しておきます。
CREATE SEQUENCE TestSequence2 START WITH 1;
詳しくは SEQUENCE を使ってシーケンス番号を振る方法 をご覧ください。
連続したシーケンス番号を生成する
生成した SEQUENCE オブジェクトから連続したシーケンス番号を生成するには sp_sequence_get_range というシステム・ストアドプロシージャを使います。
sp_sequence_get_range の構文は以下の通りです。
sp_sequence_get_range [ @sequence_name = ] N'<sequence>' , [ @range_size = ] range_size , [ @range_first_value = ] range_first_value OUTPUT [, [ @range_last_value = ] range_last_value OUTPUT ] [, [ @range_cycle_count = ] range_cycle_count OUTPUT ] [, [ @sequence_increment = ] sequence_increment OUTPUT ] [, [ @sequence_min_value = ] sequence_min_value OUTPUT ] [, [ @sequence_max_value = ] sequence_max_value OUTPUT ] [ ; ]
- sequence_name: 番号を取得するシーケンスオブジェクト名
- range_size: 番号を何個取得するか
- range_first_value: 最初シーケンス番号の値
- range_last_value: 最後のシーケンス番号の値
- range_cycle_count: 今回シーケンス番号を取得するのに何回サイクルしたか
- sequence_increment: 指定したシーケンスオブジェクトのインクリメント
- sequence_min_value: 指定したシーケンスオブジェクトの最小値
- sequence_max_value: 指定したシーケンスオブジェクトの最大値
いろいろありますが、必須なのは最初の 3 つだけです。
それでは、実際にsp_sequence_get_range を使って、連続したシーケンス番号を取得してみましょう。
先ほど生成した TestSequence2 から、連続したシーケンス番号を 6 個取得するクエリーは次の通りです。
DECLARE @size BIGINT = 6, @first_value SQL_VARIANT, @last_value SQL_VARIANT; EXEC sys.sp_sequence_get_range @sequence_name = N'dbo.TestSequence2', @range_size = @size, @range_first_value = @first_value OUTPUT, @range_last_value = @last_value OUTPUT; SELECT @first_value AS FirstValue, @last_value AS LastValue;
@first_value と @last_value はシーケンスオブジェクトの定義によって返ってくる型が違いますので、SQL_VARIANT 型で定義しておきます。
TestSequence2 は 1 ずつ増えるシーケンスオブジェクトなので @first_value の 1 から @last_value の 6 までの連続したシーケンス番号を TestSequence2 から取得したことになります。
前回、SEQUENCE を使ってシーケンス番号を振る方法でご紹介した、NEXT VALUE FORを使った、ST + 8 桁の数字となる学生番号の生成を、sp_sequence_get_range を使ってやってみましょう。
1 から始まり、1 ずつ増えて、MAXVALUE が 99999999 となる StudentNoSequence2 シーケンスを生成しておきます。
CREATE SEQUENCE StudentNoSequence2 START WITH 1 MAXVALUE 99999999;
そして、次のようなクエリーで学生番号を生成し、Student テーブルの StudentNo カラムの値を更新することができます。
DECLARE @size BIGINT = 6, @first_value SQL_VARIANT, @last_value SQL_VARIANT; EXEC sys.sp_sequence_get_range @sequence_name = N'dbo.StudentNoSequence2', @range_size = @size, @range_first_value = @first_value OUTPUT, @range_last_value = @last_value OUTPUT; ------------------------------------------------------------- SELECT @first_value AS FirstValue, @last_value AS LastValue; DECLARE @base_seq_no BIGINT = CAST(@first_value AS BIGINT) - 1; ------------------------------------------------------------- UPDATE S1 SET S1.StudentNo = S2.StudentNo FROM Student AS S1 INNER JOIN (SELECT 'ST' + RIGHT( '00000000' + CAST( @base_seq_no + ROW_NUMBER() OVER (ORDER BY LastName, FirstName) AS NVARCHAR) , 8) AS StudentNo, StudentID FROM Student) AS S2 ON S1.StudentID = S2.StudentID; ------------------------------------------------------------- SELECT * FROM Student;
まず、sp_sequence_get_range を実行して、6 個分のシーケンス番号を確保し、開始のシーケンス番号 @first_value を取得します。
@last_value は参考の為に取得していますが使用していません。
@first_value は SQL_VARIANT 型なので BIGINT にキャストし、マイナス 1 してベースとなる番号を @base_seq_no として取得しておきます。
次に、Student のレコードに LastName, FirstName 順で ROW_NUMBER() を使って連番を振り、@base_seq_no に追加することによって、シーケンス番号を決定しています。
決定したシーケンス番号を NVARCHAR にキャストし、左側に 0 を 8 個追加して RIGHT 関数で右から 8 桁取得することによって左側をゼロパディングし、頭に 'ST' を追加して学生番号を生成しています。
確実に連続したシーケンス番号を振りたい時には NEXT VALUE FOR ではなく sp_sequence_get_range を使ってくださいね!