要件定義から基本設計までは全 9 モジュール分が揃い、詳細設計は受注管理のみ先行して作成した。
記載レベルの型を確定させたうえで他モジュールへ広げる方針のため、その検収と横展開が残っている。
あわせて、DB スクリプトが SQL Server 専用になっている点への対応も残件とする。
現状
規模の実績値:機能 59 / 画面 40 / テーブル 14 / イベント 31(受注管理の 5 画面分)。
1. 受注管理の検収
横展開の前に、受注管理の詳細設計が「実装入力として行間がないか」を人が検収する。
ここで確定した記載レベルが、以降 8 モジュールすべての型になる。
対象:画面定義書(受注管理)、イベント仕様書(受注管理)
検収の観点
最も確実な検収方法
詳細設計をコーディング・エージェントに渡して実装させ、設計の穴を洗い出す。
本リポジトリの目的がここにあるため、実装させたときに質問・推測・手戻りが発生した箇所こそが
「行間が残っている箇所」であり、修正すべき対象になる。
完了条件
- 受注管理の詳細設計だけで受注管理モジュールが実装できること
- 検収で見つかった記載不足を修正し、その修正内容を記載ルールへ反映していること
(個別の直しで終わらせず、横展開時に同じ穴を空けないようにする)
2. 詳細設計の横展開
受注管理で確定した型を、残る 8 モジュール+共通に広げる。
対象
| モジュール |
画面数 |
画面定義書 |
イベント仕様書 |
共通(CMN) |
1 |
未作成 |
未作成 |
顧客管理(CUS) |
5 |
未作成 |
未作成 |
商品管理(PRD) |
4 |
未作成 |
未作成 |
仕入先管理(SUP) |
5 |
未作成 |
未作成 |
担当者管理(EMP) |
5 |
未作成 |
未作成 |
配送管理(SHP) |
5 |
未作成 |
未作成 |
売上分析(SLS) |
4 |
未作成 |
未作成 |
在庫分析(INV) |
3 |
未作成 |
未作成 |
パフォーマンス分析(PRF) |
3 |
未作成 |
未作成 |
| 合計 |
35 |
|
|
受注管理の実績(5 画面 = 31 イベント、約 6 イベント/画面)から、35 画面でおよそ 200 イベントの規模になる見込み。
進め方
- 業務系(
CUS → PRD → SUP → EMP → SHP)を先に進める
受注管理と同じ CRUD 構造のため、型をそのまま適用できる
- 分析系(
SLS / INV / PRF)は最後に回す
画面項目より集計定義が主になり、記載の型が業務系と異なるため
分析系で先に決めること
分析系は受注管理の型がそのままでは当てはまらない。以下を記載ルールとして先に確定する。
完了条件
- 全 40 画面の画面定義書とイベント仕様書が揃っていること
FN-* / SC-* / EV-* の相互参照に未定義参照・未参照定義がないこと
3. クロス DB 対応
Northwind/ 配下に 4 DB 分のディレクトリを用意済み。SQL Server 以外は空のため、中身を作る。
| ディレクトリ |
DB |
状態 |
Northwind/SQLSvr/ |
Microsoft SQL Server |
作成済(01〜03 + README) |
Northwind/Oracle/ |
Oracle Database |
空 |
Northwind/Postgres/ |
PostgreSQL |
空 |
Northwind/MySQL/ |
MySQL |
空 |
現状の SQL Server 依存(実測)
| 依存箇所 |
DDL |
DML |
移植時の論点 |
rowversion 型 |
0 |
0 |
解決済。int の版数列へ変更した(下記の決定事項) |
IDENTITY (1,1) |
6 |
0 |
シーケンス/SERIAL/AUTO_INCREMENT |
money 型 |
4 |
0 |
decimal(19,4) 等へ読み替え |
ntext / image 型 |
6 |
0 |
CLOB / BLOB、text / bytea |
tinyint 型 |
1 |
0 |
SQL Server 固有(0〜255)。smallint へ |
nchar / nvarchar |
52 |
0 |
PostgreSQL に N 系型はない |
SET IDENTITY_INSERT |
0 |
12 |
明示 ID 投入の方法が DB ごとに異なる |
DBCC CHECKIDENT |
0 |
6 |
シーケンスの再設定方法が異なる |
SET DATEFORMAT mdy |
0 |
2 |
日付リテラルの解釈。ISO 8601 へ統一すべき |
GO バッチ区切り |
33 |
50 |
sqlcmd 固有。標準 SQL ではない |
sys.* カタログビュー |
12 |
0 |
検証クエリ。information_schema へ寄せられる |
角括弧識別子 [x] |
381 |
32,693 |
標準は "x"。MySQL はバッククォート |
楽観排他の実現方式 → 決定済み(2026-08-05):版数(整数 +1)方式
RowVersion を int NOT NULL DEFAULT 1 とし、アプリが更新のたびに +1 する方式を採用した。
| 方式 |
採否 |
理由 |
| 整数の版数列 |
○ 採用 |
全 DB で同一に動作する。精度差・時刻同期の問題が原理的に発生しない |
| DB 固有の行バージョン機構 |
× |
SQL Server の rowversion に他 DB の同等物がない。Oracle の ORA_ROWSCN は ROWDEPENDENCIES なしではブロック単位、PostgreSQL の xmin は VACUUM FREEZE で変化、MySQL の TIMESTAMP は既定の秒精度では同一秒内の更新を検知できない |
| GUID |
× |
一意性は得られるが順序を持たず、整数より記憶域・比較コストが大きい |
| UNIX 時間・タイムスタンプ |
× |
DB 間で精度が異なり、時刻同期のリスクも排除できない |
特別の事情がない限り、DB 間での精度差や時刻同期リスクを完全に排除できる版数(整数 +1)方式が最も安全という判断。
制約をアプリで管理する本システムの方針とも一致する。
反映済みの内容
実装時の注意(重要)
RowVersion = RowVersion + 1 の記述漏れは、競合検知を無言で無効化する。
加算を忘れると版数が進まず、後続の更新が古い版数のまま通ってロストアップデートが起きる。
検証で再現済み。トリガーを使わない方針のため
DB 側では救えない。更新系イベントは必ず共通仕様 9.1 の定型文から書き始めること。
型の読み替え
| 現行(SQL Server) |
Oracle |
PostgreSQL |
MySQL |
int |
NUMBER(10) |
integer |
INT |
smallint |
NUMBER(5) |
smallint |
SMALLINT |
tinyint |
NUMBER(3) |
smallint(tinyint なし) |
TINYINT UNSIGNED |
bit |
NUMBER(1)(23c 未満は BOOLEAN なし) |
boolean |
TINYINT(1) |
money |
NUMBER(19,4) |
numeric(19,4)※ |
DECIMAL(19,4) |
real |
BINARY_FLOAT |
real |
FLOAT |
datetime |
DATE |
timestamp |
DATETIME |
nchar(n) / nvarchar(n) |
NCHAR(n) / NVARCHAR2(n) |
char(n) / varchar(n) |
CHAR(n) / VARCHAR(n) |
ntext |
NCLOB |
text |
LONGTEXT |
image |
BLOB |
bytea |
LONGBLOB |
IDENTITY (1,1) |
GENERATED BY DEFAULT AS IDENTITY(12c+)/SEQUENCE |
GENERATED BY DEFAULT AS IDENTITY |
AUTO_INCREMENT |
※ PostgreSQL にも money 型はあるが、ロケール依存で精度も固定のため使わない。
PostgreSQL / MySQL は DB を UTF-8 にすれば N 系の型・リテラルは不要。
DB 固有の落とし穴
移植時にデータが変質するものを優先して挙げる。
注意:制約を DB に持たせない方針との関係
DB に持たせない制約の方針により、
外部キー・CASCADE・CHECK・UNIQUE・トリガーは DB に定義していない。
この方針は移植を容易にする方向に働く(DB ごとの制約構文の差異が問題にならない)一方で、
参照整合性の検証は各 DB の投入スクリプトで必ず実施する必要がある。
完了条件
Northwind/Oracle/ Northwind/Postgres/ Northwind/MySQL/ の各ディレクトリに
SQL Server 版と同じ構成(01_CreateDatabase / 02_CreateTables / 03_InsertData + README)が揃うこと
- 各 DB で
01 → 02 → 03 が通ること
- 4 DB すべてで件数(14 テーブル)・参照整合性(14 系統)・値の妥当性(9 項目)・売上合計 1,265,793.29 が一致すること
進め方の順序
1 → 2 → 3 の順を推奨する。
- 1 を先にやる理由:記載レベルが未確定のまま 35 画面へ広げると、手戻りが 35 画面分になる
- 3 を後に回す理由:楽観排他の方式(方式 A / B)を変えると共通仕様と
全テーブル定義書に波及するため、詳細設計が固まってから着手した方が影響を抑えられる
ただし 3 の「楽観排他の方式」だけは先に決めておくとよい。
仕様の根幹に関わるため、2 の横展開が進むほど変更コストが上がる。
要件定義から基本設計までは全 9 モジュール分が揃い、詳細設計は受注管理のみ先行して作成した。
記載レベルの型を確定させたうえで他モジュールへ広げる方針のため、その検収と横展開が残っている。
あわせて、DB スクリプトが SQL Server 専用になっている点への対応も残件とする。
現状
規模の実績値:機能 59 / 画面 40 / テーブル 14 / イベント 31(受注管理の 5 画面分)。
1. 受注管理の検収
横展開の前に、受注管理の詳細設計が「実装入力として行間がないか」を人が検収する。
ここで確定した記載レベルが、以降 8 モジュールすべての型になる。
対象:画面定義書(受注管理)、イベント仕様書(受注管理)
検収の観点
テーブル.列または算出式で埋まっており、曖昧な記述がない合計 = 小計 + 送料)PRE-*/VAL-*/ERR-*)の参照が正しく、個別分だけが追記されている最も確実な検収方法
詳細設計をコーディング・エージェントに渡して実装させ、設計の穴を洗い出す。
本リポジトリの目的がここにあるため、実装させたときに質問・推測・手戻りが発生した箇所こそが
「行間が残っている箇所」であり、修正すべき対象になる。
完了条件
(個別の直しで終わらせず、横展開時に同じ穴を空けないようにする)
2. 詳細設計の横展開
受注管理で確定した型を、残る 8 モジュール+共通に広げる。
対象
CMN)CUS)PRD)SUP)EMP)SHP)SLS)INV)PRF)受注管理の実績(5 画面 = 31 イベント、約 6 イベント/画面)から、35 画面でおよそ 200 イベントの規模になる見込み。
進め方
CUS→PRD→SUP→EMP→SHP)を先に進める受注管理と同じ CRUD 構造のため、型をそのまま適用できる
SLS/INV/PRF)は最後に回す画面項目より集計定義が主になり、記載の型が業務系と異なるため
分析系で先に決めること
分析系は受注管理の型がそのままでは当てはまらない。以下を記載ルールとして先に確定する。
ST-T2/ST-T4に既出)完了条件
FN-*/SC-*/EV-*の相互参照に未定義参照・未参照定義がないこと3. クロス DB 対応
Northwind/配下に 4 DB 分のディレクトリを用意済み。SQL Server 以外は空のため、中身を作る。Northwind/SQLSvr/01〜03+ README)Northwind/Oracle/Northwind/Postgres/Northwind/MySQL/現状の SQL Server 依存(実測)
rowversion型intの版数列へ変更した(下記の決定事項)IDENTITY (1,1)SERIAL/AUTO_INCREMENTmoney型decimal(19,4)等へ読み替えntext/image型CLOB/BLOB、text/byteatinyint型smallintへnchar/nvarcharN系型はないSET IDENTITY_INSERTDBCC CHECKIDENTSET DATEFORMAT mdyGOバッチ区切りsqlcmd固有。標準 SQL ではないsys.*カタログビューinformation_schemaへ寄せられる[x]"x"。MySQL はバッククォート楽観排他の実現方式 → 決定済み(2026-08-05):版数(整数 +1)方式
RowVersionをint NOT NULL DEFAULT 1とし、アプリが更新のたびに +1 する方式を採用した。rowversionに他 DB の同等物がない。Oracle のORA_ROWSCNはROWDEPENDENCIESなしではブロック単位、PostgreSQL のxminはVACUUM FREEZEで変化、MySQL のTIMESTAMPは既定の秒精度では同一秒内の更新を検知できない特別の事情がない限り、DB 間での精度差や時刻同期リスクを完全に排除できる版数(整数 +1)方式が最も安全という判断。
制約をアプリで管理する本システムの方針とも一致する。
反映済みの内容
rowversion→int(既定値 1)へ変更SET RowVersion = RowVersion + 1を明記[int] NOT NULL DEFAULT (1)へ変更し、実行検証(競合検知の動作確認まで実施)実装時の注意(重要)
RowVersion = RowVersion + 1の記述漏れは、競合検知を無言で無効化する。加算を忘れると版数が進まず、後続の更新が古い版数のまま通ってロストアップデートが起きる。
検証で再現済み。トリガーを使わない方針のため
DB 側では救えない。更新系イベントは必ず共通仕様 9.1 の定型文から書き始めること。
型の読み替え
intNUMBER(10)integerINTsmallintNUMBER(5)smallintSMALLINTtinyintNUMBER(3)smallint(tinyintなし)TINYINT UNSIGNEDbitNUMBER(1)(23c 未満はBOOLEANなし)booleanTINYINT(1)moneyNUMBER(19,4)numeric(19,4)※DECIMAL(19,4)realBINARY_FLOATrealFLOATdatetimeDATEtimestampDATETIMEnchar(n)/nvarchar(n)NCHAR(n)/NVARCHAR2(n)char(n)/varchar(n)CHAR(n)/VARCHAR(n)ntextNCLOBtextLONGTEXTimageBLOBbyteaLONGBLOBIDENTITY (1,1)GENERATED BY DEFAULT AS IDENTITY(12c+)/SEQUENCEGENERATED BY DEFAULT AS IDENTITYAUTO_INCREMENT※ PostgreSQL にも
money型はあるが、ロケール依存で精度も固定のため使わない。PostgreSQL / MySQL は DB を UTF-8 にすれば
N系の型・リテラルは不要。DB 固有の落とし穴
移植時にデータが変質するものを優先して挙げる。
''をNULLとして扱う。原典データに空文字列があると意味が変わる(現データはNULL済みだが要確認)CustomerIDのような混在表記を保つには全 DB で引用符が必須になるOrder Detailsは名前に空白を含む。原典忠実を優先する以上、全 DB で引用符必須。MySQL はバッククォート、または
ANSI_QUOTESモードで"..."GOはsqlcmd固有。Oracle は/、PostgreSQL / MySQL は不要(;区切り)YYYY-MM-DD)に統一する。現行のSET DATEFORMAT mdy+m/d/yyyyは移植できない。Oracle はTO_DATEかNLS_DATE_FORMATの指定が必要SET IDENTITY_INSERT相当)と採番値の再設定(DBCC CHECKIDENT相当)を DB ごとに用意するsys.*カタログビューをinformation_schemaに寄せる(MySQL / PostgreSQL は対応、Oracle はUSER_*/ALL_*)OFFSET ... FETCHは SQL Server 2012+ / Oracle 12c+ / PostgreSQL で使えるが、MySQL はLIMIT ... OFFSETinstnwnd.sql から
機械抽出している(画像バイナリのみ
NULL化)。他 DB でも同じ出典から生成し、同一データを保つ自己検証している。売上合計 1,265,793.29 は DB を跨いだ同一性の確認に使える
注意:制約を DB に持たせない方針との関係
DB に持たせない制約の方針により、
外部キー・CASCADE・CHECK・UNIQUE・トリガーは DB に定義していない。
この方針は移植を容易にする方向に働く(DB ごとの制約構文の差異が問題にならない)一方で、
参照整合性の検証は各 DB の投入スクリプトで必ず実施する必要がある。
完了条件
Northwind/Oracle/Northwind/Postgres/Northwind/MySQL/の各ディレクトリにSQL Server 版と同じ構成(
01_CreateDatabase/02_CreateTables/03_InsertData+ README)が揃うこと01→02→03が通ること進め方の順序
1 → 2 → 3 の順を推奨する。
全テーブル定義書に波及するため、詳細設計が固まってから着手した方が影響を抑えられる
ただし 3 の「楽観排他の方式」だけは先に決めておくとよい。
仕様の根幹に関わるため、2 の横展開が進むほど変更コストが上がる。