0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

動詞で綴るマスタデータの系譜型モデル~実装ガイド~(2026 Edition)

0
Last updated at Posted at 2026-03-22

本記事では、マスタデータの操作を「動詞」を軸に分類し、その系譜をデータベースに保持する実装方法を解説します。

この設計は、通常の、追加・更新・削除、に加えて、削除からの復元に対応します。
 加えて、簿記のような誠実な説明能力を持ちます。


なお本記事では冒頭から HOW の解説に入ります。概念の説明についてはリンク先をご一読ください。

※簡略化のため、すべて SQL での解説となります
※末尾に動作確認用の SQL があります

1.データベースのテーブル構造

投影テーブル(Projection / Base Table)

アプリケーションが参照する最新の情報です。
画面表示や計算に使うのはこのテーブルです。

room_id、room_name の項目を持つ一般的な「マスタ」です。
(その他の項目は管理項目)

削除時は、投影テーブルからは物理削除します。

create table master_room (
  room_id varchar(16) not null,
  revision int not null,
  updater varchar(15) not null,
  update_time datetime not null,
  room_name varchar(100) not null,
  primary key (room_id)
);
  • 説明のため最小構成の項目です。実運用ではデータ項目(属性)は増やしてください
  • データ型は要件に合わせてご調整ください

履歴テーブル(History / Event Store)

業務で発生したすべての出来事を記録します
insertのみ不変(Immutable)な記録です。
そして、ここでは「event_verb = 何が起きたか(動詞)」が主役となります。

削除時は、履歴テーブルに「削除」のデータを追加(insert)します。

create table master_room_history (
  room_id varchar(16) not null,
  revision int not null,
  updater varchar(15) not null,
  update_time datetime not null,
  event_verb_type tinyint not null,
  parent_rev int not null,
  merge_parent int not null,
  room_name varchar(100) not null,
  primary key (room_id, revision)
);

退避テーブル(Cold Store)

履歴テーブルは運用を続けると肥大化します。
一定期間で、この退避テーブルに移動させることで、システムの処理速度の低下を回避します。

create table master_room_archive (
  room_id varchar(16) not null,
  revision int not null,
  updater varchar(15) not null,
  update_time datetime not null,
  event_verb_type tinyint not null,
  parent_rev int not null,
  merge_parent int not null,
  room_name varchar(100) not null,
  primary key (room_id, revision)
);

動詞マスタ

マスタを変化させる動作を、これらの「動詞」で表現します。
すべての履歴は動詞と共に存在します。

create table system_event_type (
  event_type_id tinyint not null,
  event_name varchar(20) not null,
  event_name_ja varchar(10) not null, -- 日本語名(数文字)を追加
  is_terminal bit not null, -- 1: 投影から消える(無の状態), 0: 投影に残る(有の状態)
  is_origin bit not null, -- 1: 系譜の起点(init)となる
  description varchar(100),
  constraint pk_system_event_type primary key (event_type_id)
);

insert into system_event_type (event_type_id, event_name, event_name_ja, is_terminal, is_origin, description) values
( 1,'init'     ,'発生', 0, 1, '実体の新規登録(または削除からの復活)'),
( 2,'revise'   ,'更新', 0, 0, '既存リビジョンの属性変更'),
( 9,'terminate','終了', 1, 0, '実体の終了(投影テーブルからの削除)'),
(11,'revert'   ,'復元', 0, 0, '過去リビジョンを最新として復元'),
(31,'baseline' ,'締切', 0, 0, '履歴アーカイブのための監査用チェックポイント');

2.マスタデータのライフサイクル・シナリオ

本記事では、以下のシナリオに沿って、処理と実行結果を解説します。

冒頭のシンプルなデータ構造と、本記事の末尾に掲載したロジックが、どのようにデータを書き換えていくかを追体験いただけます。

フェーズ タイトル 主な使用動詞 見どころ
1 データ登録と変更 initrevise expected_revision による排他制御。
2 削除とUndo terminaterevert 削除したマスタを「過去の版」から復旧する。
3 履歴の肥大化 baseline 過去の履歴をアーカイブへ送り出し、新たな起点から再出発する。

※ 具体的な処理手順は末尾に記載しています。
 実行スクリプトはストアドプロシージャの形式です。
 ストアドの実行サンプルは、お使いの言語のインターフェース相当と捉えてください。

本記事では、複雑さを排除するため同期的に投影を更新します。イベントソーシング的な振る舞いが必要な場合など、要件に合わせて読み替えてください。


フェーズ 1:データ登録と変更

新規追加および更新処理は、以下の要領で実行します。

実行スクリプト

-- @expected_revision = 0 は新規追加
exec [dbo].[up_master_room_upsert]
    @room_id = 'RM335', 
    @room_name = 'Room 335', 
    @updater = 'alice', 
    @expected_revision = 0; 

-- @expected_revision > 0 は変更
exec [dbo].[up_master_room_upsert]
    @room_id = 'RM335', 
    @room_name = 'Larry''s Studio', 
    @updater = 'bob', 
    @expected_revision = 1;

【データ実例:フェーズ 1 終了時】

履歴テーブル(仕訳帳):master_room_history
room_id revision room_name parent_rev merge_parent event_verb updater
RM335 1 Room 335 0 0 init alice
RM335 2 Larry's Studio 1 0 revise bob

処理を実行した結果、履歴テーブルには以下が記録されます。

  • @expected_revision = 0 を条件に、最初の記録 revision 1 が生成されます
  • @expected_revision = 1 を指定することで parent_rev = 1 を親に持つ revision 2 が積みあがります
投影テーブル(元帳):master_room

アプリケーションはこちらのテーブルを参照します。
論理削除などでありがちな、検索条件などは不要です。「テーブルに存在する=有効なデータ」です

room_id room_name revision updater
RM335 Larry's Studio 2 bob

フェーズ 2:削除とUndo

マスタを削除する場合は、以下のように実行します。

実行スクリプト

exec [dbo].[up_master_room_terminate]
    @room_id = 'RM335', 
    @updater = 'bob', 
    @expected_revision = 2;
【データ実例:フェーズ 2 削除後】

削除後の履歴テーブルには、revision 3 が削除の動詞(event_verb = terminate)で記録されます。

履歴テーブル(仕訳帳):master_room_history
room_id revision room_name parent_rev merge_parent event_verb updater
RM335 1 Room 335 0 0 init alice
RM335 2 Larry's Studio 1 0 revise bob
RM335 3 Larry's Studio 2 0 terminate bob
投影テーブル(元帳):master_room

(このタイミングで行は存在しません)

削除後のユースケース

その後、誤操作に気づいた担当者がリビジョン 2 の状態へ復旧させたいと考えます。
このような復旧(Undo)操作は、以下の要領で実行します。

実行スクリプト

exec [dbo].[up_master_room_revert]
    @room_id = 'RM335', 
    @target_revision = 2, 
    @expected_revision = 3, 
    @updater = 'admin'; 

(※実際は履歴検索UIによる履歴の選択が必要です。しかしここでは簡略化のため UI 関連は省き、操作の解説に集中します)

  • @expected_revision = 3(現在の削除状態)に対して、
  • 復旧元となる @target_revision = 2 を指定して実行します

【データ実例:フェーズ 2 終了時】

実行の結果、履歴テーブルには revision 4 が記録されます。

  • parent_revに 3 を記録することで、データの系譜を維持します
  • merge_parentに 2 を記録することで、コピー元の情報を残します
履歴テーブル(仕訳帳):master_room_history
room_id revision room_name parent_rev merge_parent event_verb updater
RM335 1 Room 335 0 0 init alice
RM335 2 Larry's Studio 1 0 revise bob
RM335 3 Larry's Studio 2 0 terminate bob
RM335 4 Larry's Studio 3 2 revert admin
投影テーブル(元帳):master_room

アプリケーションはこちらのテーブルを参照します。
(論理削除の実装でありがちな特殊な検索条件などは不要です)

room_id room_name revision updater
RM335 Larry's Studio 4 admin

以上で、追加・更新・削除+復元に対応できました。

次は、履歴が大量になった場合の解説です。


フェーズ 4: 履歴の肥大化対策

例えば年度末や、データ保存期間を迎えたタイミングで、履歴を整理するユースケースです。
履歴の整理を宣言(baseline)してから、退避テーブルへ移動(archive)します。

実行スクリプト

exec [dbo].[up_master_room_baseline]
    @room_id = 'RM335',
    @expected_revision = 4,
    @updater = 'auditor';

【データ実例:フェーズ 4 baseline後】

履歴テーブル(仕訳帳):master_room_history
room_id revision room_name parent_rev merge_parent event_verb updater
... ... ... ... ... ... ...
RM335 4 Larry's Studio 3 2 revert admin
RM335 5 Larry's Studio 4 0 baseline auditor
投影テーブル(元帳):master_room

内容は変わりませんが、版番号(revision)が「締め後の番号」に更新されます。
これ以前の履歴をアーカイブへ逃がすための「目印」になります。

room_id room_name revision updater
RM335 Larry's Studi 4 auditor

実行スクリプト

baseline のリビジョンを指定してアーカイブを実行します。

exec [dbo].[up_master_room_history_archive]
    @room_id = 'RM335',
    @keep_baseline_rev = 5;

【データ実例:フェーズ 4 終了時】

履歴テーブル(仕訳帳):master_room_history
room_id revision room_name parent_rev merge_parent event_verb updater
RM335 5 Larry's Studio 4 0 baseline auditor

履歴テーブルは リビジョン5のみ残ります。
そして master_room_archive に 5未満の履歴が移動します。

(実務では一括処理できると運用が容易になりますが、説明のため room_id ごとの処理としています。)


3.全フェーズ完走:お疲れ様でした

これでマスタデータのライフサイクルが完結しました。

  1. 発生 (init)
  2. 適応 (revise)
  3. 充足 (terminate)
  4. 回帰 (revert)
  5. 凝縮 (baseline)

これらの系譜を積み上げたことで、roomマスタは **『過去の任意の時点における状態を再構築し、その変更意図を第三者に証明する』**ことができるようになります。

これにより、ユーザー視点でも、データの変更の系譜が確認できるようになります。
また、保守運用フェーズにおける保守担当(開発者)の工数削減に寄与します。

おわりに ── 誠実な履歴がシステムを長寿にする

マスタデータのライフサイクルを「動詞」で定義し直すことで、マスタデータ自身が今の状態にいたる経緯を語ることができます。

とはいえ、この設計を導入することは、開発初期に「手間」を持ち込みます。
しかし、その対価として得られるのは、データ自身が系譜を語ることによる調査負荷の削減、障害発生時の復旧力です。

あなたのシステムが、単に「動く」だけでなく、数年後の自分や後任者に対して「誠実」であり続けるために。この系譜型マスタ設計が、その一助となれば幸いです。


X.実装例

サンプルはSQLServer向けストアドプロシージャです。
適宜、特定のDB向けSQL、またはコードに変換してご利用ください。

※各ストアドの @expected_revision により楽観ロックを実現しています。


1. init/revise : [up_master_room_upsert]

create procedure up_master_room_upsert (
    @room_id varchar(16),
    @room_name varchar(100),
    @updater varchar(15),
    @expected_revision int
)
as
begin
    set nocount on;

    -- 入力値の有無を点検する
    if nullif(@room_id, '') is null raiserror('[51001] missing room_id', 16, 1);
    if nullif(@room_name, '') is null raiserror('[51001] missing room_name', 16, 1);
    if nullif(@updater, '') is null raiserror('[51001] missing updater', 16, 1);
    if @expected_revision is null raiserror('[51001] missing expected_revision', 16, 1);
    if @@error <> 0 return;

    -- 現在の最新リビジョンを読み取る
    -- updlock, holdlock により、この行への他者の書き込みを完了まで待機させる
    declare @cur_rev int;
    select @cur_rev = isnull(max(revision), 0)
    from master_room_history with (updlock, holdlock)
    where room_id = @room_id;

    -- 現在の論理状態(終端か否か)を特定する
    declare @is_term bit = isnull((
        select s.is_terminal from master_room_history h 
        join system_event_type s on h.event_verb_type = s.event_type_id 
        where h.room_id = @room_id and h.revision = @cur_rev
    ), 1);

    -- 期待する番号と実際の番号を突き合わせ、不一致なら処理を止める(楽観的ロック)
    if (@expected_revision = 0 and @is_term = 0) or (@expected_revision <> 0 and @cur_rev <> @expected_revision)
    begin
        declare @msg nvarchar(255) = formatmessage('[50001] conflict: room_id=%s, expected=%d, actual=%d', 
            @room_id, @expected_revision, @cur_rev);
        raiserror(@msg, 16, 1); return;
    end

    -- 新しいリビジョン番号とイベント種別を決定する
    declare @v_init tinyint = 1, @v_rev tinyint = 2, @now datetime = getdate();
    declare @nxt_rev int = @cur_rev + 1;
    declare @v_type tinyint = case when @is_term = 1 then @v_init else @v_rev end;

    -- 履歴テーブルへ新しい事実を挿入する
    insert into master_room_history (
        room_id, revision, updater, update_time, event_verb_type, 
        parent_rev, merge_parent, branch_id, room_name
    )
    values (
        @room_id, @nxt_rev, @updater, @now, @v_type, 
        @cur_rev, 0, 0, @room_name
    );

    -- 投影テーブル(現在の状態)を最新化する
    update master_room set 
        revision = @nxt_rev, updater = @updater, update_time = @now, room_name = @room_name 
        where room_id = @room_id;

    if @@rowcount = 0 
        insert into master_room (room_id, revision, updater, update_time, room_name) 
        values (@room_id, @nxt_rev, @updater, @now, @room_name);
end

2. terminate : [dbo].[up_master_room_terminate]

create procedure up_master_room_terminate (
    @room_id varchar(16),
    @updater varchar(15),
    @expected_revision int
)
as
begin
    set nocount on;

    -- 入力値を点検する(終了処理のため、期待するリビジョンは1以上が必要)
    if nullif(@room_id, '') is null raiserror('[51001] missing room_id', 16, 1);
    if nullif(@updater, '') is null raiserror('[51001] missing updater', 16, 1);
    if isnull(@expected_revision, 0) = 0 raiserror('[51001] expected_revision must be > 0 for terminate', 16, 1);
    if @@error <> 0 return;

    -- 現在の最新リビジョンを読み取る
    declare @cur_rev int;
    select @cur_rev = isnull(max(revision), 0)
    from master_room_history with (updlock, holdlock)
    where room_id = @room_id;

    -- 競合を検知する(既に他者が更新している、または既に削除されている場合)
    if @cur_rev <> @expected_revision
    begin
        declare @msg nvarchar(255) = formatmessage('[50001] conflict: room_id=%s, expected=%d, actual=%d', 
            @room_id, @expected_revision, @cur_rev);
        raiserror(@msg, 16, 1); return;
    end

    -- 投影テーブル(現在の状態)からレコードを抹消する
    delete from master_room where room_id = @room_id;

    -- 履歴テーブルへ「終了」の事実を書き込む
    -- 直前のリビジョンの内容をコピーし、その断面のまま終了したことを記録する
    declare @v_term tinyint = 9, @now datetime = getdate();
    declare @nxt_rev int = @cur_rev + 1;

    insert into master_room_history (
        room_id, revision, updater, update_time, event_verb_type, 
        parent_rev, merge_parent, branch_id, room_name
    )
    select 
        room_id, @nxt_rev, @updater, @now, @v_term, 
        @cur_rev, 0, 0, room_name
    from master_room_history
    where room_id = @room_id and revision = @cur_rev;
end

3. revert : [up_master_room_revert]

create procedure up_master_room_revert (
    @room_id varchar(16),
    @target_revision int,     -- 復元の出典とする過去のリビジョン
    @expected_revision int,   -- 現在見ているリビジョン(楽観的ロック)
    @updater varchar(15)
)
as
begin
    set nocount on;

    -- 入力値を点検する
    if nullif(@room_id, '') is null raiserror('[51001] missing room_id', 16, 1);
    if isnull(@target_revision, 0) = 0 raiserror('[51001] target_revision required', 16, 1);
    if @expected_revision is null raiserror('[51001] expected_revision required', 16, 1);
    if @expected_revision = 0 raiserror('[51001] revert requires an explicit current revision', 16, 1);
    if nullif(@updater, '') is null raiserror('[51001] missing updater', 16, 1);
    if @@error <> 0 return;

    -- 現在のリビジョンを読み取り、他セッションを待機させる
    declare @cur_rev int;
    select @cur_rev = isnull(max(revision), 0)
    from master_room_history with (updlock, holdlock)
    where room_id = @room_id;

    -- 競合検知(画面を開いた後に誰かが更新・削除していないか)
    if @cur_rev <> @expected_revision
    begin
        declare @msg_conflict nvarchar(255) = formatmessage('[50001] conflict: room_id=%s, expected=%d, actual=%d', 
            @room_id, @expected_revision, @cur_rev);
        raiserror(@msg_conflict, 16, 1); return;
    end

    -- 出典となるリビジョンが存在するか確認する
    if not exists (select 1 from master_room_history where room_id = @room_id and revision = @target_revision)
    begin
        raiserror('[50002] target revision not found', 16, 1); return;
    end

    -- 新しいリビジョン番号を確定する
    declare @v_revert tinyint = 11, @now datetime = getdate();
    declare @nxt_rev int = @cur_rev + 1;

    -- 投影テーブル(現在の姿)を復元データで書き換える
    -- 既に削除(terminate)されて行がない場合は insert で復活させる
    update m set 
        revision = @nxt_rev, updater = @updater, update_time = @now, room_name = h.room_name 
    from master_room m, master_room_history h
    where m.room_id = @room_id and h.room_id = @room_id and h.revision = @target_revision;

    if @@rowcount = 0
        insert into master_room (room_id, revision, updater, update_time, room_name)
        select room_id, @nxt_rev, @updater, @now, room_name
        from master_room_history 
        where room_id = @room_id and revision = @target_revision;

    -- 履歴テーブルへ「復元」の事実を記録する
    -- 出典元(target_revision)を merge_parent に刻む
    insert into master_room_history (
        room_id, revision, updater, update_time, event_verb_type, 
        parent_rev, merge_parent, branch_id, room_name
    )
    select 
        room_id, @nxt_rev, @updater, @now, @v_revert, 
        @cur_rev, @target_revision, 0, room_name
    from master_room_history
    where room_id = @room_id and revision = @target_revision;
end

4. baseline : [up_master_room_baseline]

create procedure up_master_room_baseline (
    @room_id varchar(16),
    @expected_revision int,
    @updater varchar(15)
)
as
begin
    set nocount on;

    -- 入力値の存在を確認する
    if nullif(@room_id, '') is null raiserror('[51001] missing room_id', 16, 1);
    if @expected_revision is null raiserror('[51001] expected_revision required', 16, 1);
    if nullif(@updater, '') is null raiserror('[51001] missing updater', 16, 1);
    if @@error <> 0 return;

    -- 現在のリビジョンを読み取り、他セッションの割り込みを制限する
    declare @cur_rev int;
    select @cur_rev = isnull(max(revision), 0)
    from master_room_history with (updlock, holdlock)
    where room_id = @room_id;

    -- 競合検知(画面上の番号と最新の番号が一致するか)
    if @cur_rev <> @expected_revision
    begin
        declare @msg nvarchar(255) = formatmessage('[50001] conflict: room_id=%s, expected=%d, actual=%d', 
            @room_id, @expected_revision, @cur_rev);
        raiserror(@msg, 16, 1); return;
    end

    -- 新しいリビジョン番号(締切リビジョン)を確定する
    declare @v_base tinyint = 31, @now datetime = getdate();
    declare @nxt_rev int = @cur_rev + 1;

    -- 履歴テーブルへ「締切」の事実を書き込む
    -- 直前の属性(room_name)をそのまま引き継ぎ、イベント種別だけを更新する
    insert into master_room_history (
        room_id, revision, updater, update_time, event_verb_type, 
        parent_rev, merge_parent, branch_id, room_name
    )
    select 
        room_id, @nxt_rev, @updater, @now, @v_base, 
        @cur_rev, 0, 0, room_name
    from master_room_history
    where room_id = @room_id and revision = @cur_rev;

    -- 投影テーブル(現在の姿)のリビジョン情報を最新化する
    -- 部屋名に変更はないため、管理項目のみを更新
    update master_room set 
        revision = @nxt_rev, updater = @updater, update_time = @now 
    where room_id = @room_id;
end

5. archive : [up_master_room_archive]

create procedure up_master_room_archive (
    @room_id varchar(16),
    @keep_baseline_rev int -- このリビジョンを「履歴の起点」として残し、これより古いものを移動する
)
as
begin
    set nocount on;

    -- 入力値の存在を確認する
    if nullif(@room_id, '') is null raiserror('[51001] missing room_id', 16, 1);
    if isnull(@keep_baseline_rev, 0) = 0 raiserror('[51001] keep_baseline_rev required', 16, 1);
    if @@error <> 0 return;

    -- 最新状況と、指定されたリビジョンの種類を確認する
    -- 処理中に他者が更新できないようロックをかける
    declare @max_rev int, @target_event tinyint;
    select 
        @max_rev = isnull(max(revision), 0),
        @target_event = isnull(max(case when revision = @keep_baseline_rev then event_verb_type end), 0)
    from master_room_history with (updlock, holdlock)
    where room_id = @room_id;

    -- 指定されたリビジョンが存在するか点検する
    if @target_event = 0
    begin
        raiserror('[50002] target revision not found', 16, 1); return;
    end

    -- 最新リビジョンはアーカイブできない(最低1行は履歴に残す必要がある)
    if @keep_baseline_rev > @max_rev
    begin
        declare @msg_range nvarchar(255) = formatmessage('[50003] baseline out of range: room_id=%s, max_rev=%d', 
            @room_id, @max_rev);
        raiserror(@msg_range, 16, 1); return;
    end

    -- 指定された地点が「締切(baseline: 31)」であるか確認する
    -- 任意の地点で切断すると系譜が追えなくなるため、明示的なチェックポイントを必須とする
    declare @v_base tinyint = 31;
    if @target_event <> @v_base
    begin
        declare @msg_seal nvarchar(255) = formatmessage('[50101] sealed: revision %d is not a baseline.', @keep_baseline_rev);
        raiserror(@msg_seal, 16, 1); return;
    end

    -- 1. アーカイブテーブルへ古い行をコピーする
    insert into master_room_archive (
        room_id, revision, updater, update_time, 
        event_verb_type, parent_rev, merge_parent, branch_id, room_name
    )
    select 
        room_id, revision, updater, update_time, 
        event_verb_type, parent_rev, merge_parent, branch_id, room_name
    from master_room_history
    where room_id = @room_id and revision < @keep_baseline_rev;

    -- 2. 履歴テーブル(ホットストア)からコピー済みの古い行を消去する
    delete from master_room_history
    where room_id = @room_id and revision < @keep_baseline_rev;
end

6. 動作確認用

begin tran t1

exec [dbo].[up_master_room_upsert]
    @room_id = 'RM335', 
    @room_name = 'Room 335', 
    @updater = 'alice', 
    @expected_revision = 0;

exec [dbo].[up_master_room_upsert]
    @room_id = 'RM335', 
    @room_name = 'Larry''s Studio', 
    @updater = 'bob', 
    @expected_revision = 1;

exec [dbo].[up_master_room_terminate]
    @room_id = 'RM335', 
    @updater = 'bob', 
    @expected_revision = 2;

exec [dbo].[up_master_room_revert]
    @room_id = 'RM335', 
    @target_revision = 2, 
    @expected_revision = 3, 
    @updater = 'admin';

exec [dbo].[up_master_room_baseline]
    @room_id = 'RM335',
    @expected_revision = 4,  
    @updater = 'auditor';

exec [dbo].[up_master_room_archive]
    @room_id = 'RM335',
    @keep_baseline_rev = 5

select * from master_room
select * from master_room_history
select * from master_room_archive

rollback tran t1
--commit tran t1

X.エラー体系

本筋ではないので触れませんでしたが、サンプルにおけるエラー体系は以下の方針になります。

50000番台:系譜型モデル 標準エラー体系

  • [50001] conflict
    • 「あなたが編集を開始してから保存するまでの間に、世界(本流)は一歩先に進みました」という事実を伝えます。upsertmerge において、意図しない上書きによるデータ破壊を防ぎます
  • [50002] source missing
    • branchrevert において、「存在しない過去」を起点にすることを許しません。すべての変化には明確な「親(parent_rev)」が必要であるという、系譜型モデルの根幹を守ります
  • [50003] out of range
    • archive における未来のリビジョン指定や、branch における識別子の重複を検知します。これは、系譜が一本道(または管理された分岐)であることを担保するための制約です
  • [50101] sealed
    • archive において、「baseline(結び目)が打たれていない場所では歴史を切り離せない」という規律を強制します。これは、運用における「不注意なデータ喪失」を防ぐためのガードレールです
  • [51001] invalid format
    • 「型は合っているが、事実として記録するには値しない(更新者が不明、UIDのバイト長不足など)」場合に発動します。不純なデータが系譜に混入するのを防ぎます
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?