タイトルどおり、何かの原因でSEQUENCEの現在値と、それを主キーとするテーブルのレコードが不一致な状態になったとき、一致するまでSEQUENCEを廻す。
まずは直感的に思いつきやすいOracleから…ここではシーケンスの現在値を変数 :SEQ_CURRENT_VAL で保持しているものとする。
Oracle
select
SEQ_ID.nextval
from
dual
connect by
level <= (
select
max(ID)
from
TABLE
) - :SEQ_CURRENT_VAL;
へっぽこプログラマーには理解しにくいconnect by
だがここでは、単純にlevel
=行数となるので、最大値-シーケンスの現在値=値の差
廻す。
SQL Server
connect by
が使えないので、WITH句共通テーブル式(CTE)を使う。ここでは、トランザクションデータの主キーの最大値を変数 @MAX_ID で保持しているものとする。
with CTE as (
select
convert(int, current_value) ID
from
sys.sequences
where
name = 'SEQ_ID'
union all
select
ID + 1
from
CTE
where
ID < @MAX_ID
)
select
next value for SEQ_ID
from
CTE
where
ID < @MAX_ID
トランザクションデータの主キーの最大値と、SEQUENCEの現在値が一致していたとしても、CTEの上のテーブルの結果が返ってしまうで、SEQUENCEを廻すSELECT句でも、トランザクションデータの主キーの最大値と比較する必要がある。また
色々駄目な失敗例
with CTE as (
select
NEXT VALUE FOR SEQ_ID ID
union all
select
NEXT VALUE FOR SEQ_ID
from
CTE
where
ID <= @MAX_ID
)
select
*
from
CTE
みたいなのは、
メッセージ 11721、レベル 15、状態 1、行 3
NEXT VALUE FOR 関数は、DISTINCT、UNION、UNION ALL、EXCEPT、INTERSECT のいずれかの演算子を使用するステートメントで直接使用することはできません。
となってエラーになるし、そもそも、SEQUENCEも無駄に廻ってしまう。