TECHS は「受注(製番)を背骨にした台帳」であって、製品ツリーを持たない。この頁は fab-forward-pms の鏡像(1,265製番・11,073製造品目・239,262部品表明細)から逆算した、TECHS の実際のデータ構造と、そこに透けて見えるクライアントのメンタルモデルの読み取りである。開発者(Ryo)本人向けメモ。
一文で: TECHS は「受注(製番)を背骨にした台帳」であって、製品ツリーを持たない。カタログも号機も製品マスタも無い。あるのは「いつ・誰の・何番目の仕事か」を刻んだ台帳と、その仕事にぶら下がる部品表だけである。
この頁の数字はすべて、fab-forward-pms の鏡像DB(TECHSの読み取り専用同期先)を2026-09-05に直接クエリした実測値と、客先の実スキーマレポート(60,543列・1,388オブジェクト、2026-09-03付)から来ている。確認済み は再クエリで確認した事実、推定 は構造的な状況証拠から読んだ解釈であることを明示する。両者を混同しないこと。
受注から品番まで、実際に辿れる経路は一本しかない:MstDeal(得意先/仕入先)→ TrnOrder(受注)→ TrnSeiban(製番)→ TrnProd(製造品目=ユニット)→ TrnBom(受注部品表)→ MstItemNo(品番)。この一本道の外側に、MstPartsCompose(マスタ部品表、品番の自己参照エッジ)がぶら下がり、TrnSOrderD/TrnAcceptD(発注・検収、いずれも品番キーで製番キーではない)と TrnInOutRec(入出庫)が側枝として品番から生えている。
読み取れること: 製番と品番のあいだに直接のリレーションは無い。TrnSeiban.SeibanItemNo は全行 NULL で、製番から品番へ辿る唯一の経路は TrnProd(この製番で作った各ユニットの品番)を経由するものだけである。発注・検収は品番キーで、製番付きの発注は 22,131行中 1行しかない — 原価をジョブ(製番)単位で見たいなら、発注データからは辿れず、受注部品表 (bom_lines) や検収明細を経由するしかない。
下図はネットワーク経由で Mermaid(CDN読み込み)を使って描画する。オフラインや読み込み失敗時は図1が要約として機能する。
erDiagram
MstDeal["MstDeal (customers)"] {
string DealCd PK
string DealNm
string role "得意先/仕入先どちらにもなる"
}
MstSupplier["MstSupplier (suppliers)"] {
string SupplierCd PK "== DealCd, 75/75一致"
}
MstSupplierBuyUp["MstSupplierBuyUp (supplier_price_tiers)"] {
int SupplierBuyUpSeq PK
string SupplierCd FK
string ItemNo FK
}
MstItemNo["MstItemNo (parts)"] {
string ItemNo PK "bare, ItemNoRevは99.97%NULL"
string LargeCategoryCd "Eのみ実値あり"
}
MstPartsCompose["MstPartsCompose (part_compositions)"] {
int PartsComposeSeq PK
string ParentItemNo FK
string ChildItemNo FK
int DataSrt
}
MstPerson["MstPerson (employees)"] {
string PersonCd PK "4桁 or Exxxの2系統"
}
TrnSeiban["TrnSeiban (seiban)"] {
string Seiban PK
string OrderNo FK
string SeibanItemNo "全行NULL"
}
TrnOrder["TrnOrder (orders)"] {
string OrderNo PK
string CustomerCd FK
string ProjectName "自由記述,34機種に正規化可(81.6%)"
}
TrnProd["TrnProd (production_items)"] {
int ProdSeq PK "グローバル surrogate"
string Seiban FK
string ProdNo "Seiban+-NN, 96.6%"
string ProdItemNo FK "28%がparts外"
}
TrnSOrderH["TrnSOrderH (purchase_order_headers)"] {
string SOrderSlipNo PK "10桁ゼロ埋め連番"
}
TrnSOrderD["TrnSOrderD (purchase_order_lines)"] {
int SOrderDNo PK
string SOrderSlipNo FK
string ItemNo FK
string Seiban "1/22,131のみ充填"
}
TrnAcceptH["TrnAcceptH (acceptance_headers)"] {
string AcceptNo PK
}
TrnAcceptD["TrnAcceptD (acceptance_lines)"] {
int AcceptDSeq PK
string AcceptNo FK
string ItemNo FK
}
TrnBom["TrnBom (bom_headers/bom_lines)"] {
int PartsSeq PK "line"
string OrderNo FK "headerキーの一部"
string UnitCode FK "= ProdNo"
string ItemNo FK
string ParentPartsSeq "全行NULL"
}
TrnInOutRec["TrnInOutRec (inventory_movements)"] {
int InOutRecSeq PK
string ItemNo FK
string MovementTypeCd "S0/S1,極性未確認"
}
ViwStock["ViwRptStockConditionListInfo (stock_balances)"] {
string ItemNo FK
string StockBaseCd
string HouseCd
}
MstDeal ||--o{ TrnOrder : "DealCd 305to1265"
MstDeal ||--o{ MstSupplier : "role projection 75/75"
TrnOrder ||--|| TrnSeiban : "OrderNo 100% 1:1"
TrnSeiban ||--o{ TrnProd : "Seiban 1265to11073"
TrnProd ||--o{ TrnBom : "ProdNo=UnitCode headers100%"
MstItemNo ||--o{ TrnBom : "ItemNo 明細参照"
MstItemNo ||--o{ MstPartsCompose : "ParentItemNo 自己参照"
MstItemNo ||--o{ MstPartsCompose : "ChildItemNo 自己参照"
MstItemNo ||--o{ TrnSOrderD : "ItemNo Seibanは0%"
TrnSOrderH ||--o{ TrnSOrderD : "SOrderSlipNo"
MstItemNo ||--o{ TrnAcceptD : "ItemNo"
TrnAcceptH ||--o{ TrnAcceptD : "AcceptNo"
MstItemNo ||--o{ TrnInOutRec : "ItemNo 2026-07のみ"
MstItemNo ||--o{ ViwStock : "ItemNo|StockBaseCd|HouseCd"
MstSupplier ||--o{ MstSupplierBuyUp : "SupplierCd"
MstItemNo ||--o{ MstSupplierBuyUp : "ItemNo"
各識別子を実例で分解する。番号は分類コードではなく時系列の台帳番号(月×連番)であること、リビジョンや加工段階までも番号の中に埋め込む文化であることが読み取れる。
| 識別子 | 実例 | 分解 |
|---|---|---|
| 製番 推定 接頭辞の意味 |
BD2212-07 |
BD 接頭辞(内部分類、DM/SS=自社案件) + 2212 YYMM(採番月。due_date一致61.4%) + -07 月内で全顧客共有の連番(95.1%が密。歯抜けはTrnSeibanDelでの物理削除) |
| 製造No 確認済み |
BD2212-07-03 |
BD2212-07 製番
+ -03 連番(1..k、96.6%が密)。
残り3.4%は手打ち接尾辞 -SOJI/-KIRIKAE/-CR01 等
|
| 品番 推定 文字の意味 |
5131F719-A |
5131 4桁ファミリー(5111/5131/5141/5151のみ存在)
+ F 文字(K/M≈組立、親84-93%/E/F≈個別加工部品、E67%が葉/Bは小規模)
+ 719 3桁
+ -A リビジョン(A→N、頻度が単調減少 確認済み)
同一品番の加工段階違い: IT5141E171-A(素材)/TS5141E172-A(加工中)
|
| 発注伝票 推定 グローバル連番 |
0000023477 |
10桁ゼロ埋め の全期間通し連番(0000000001〜0000023477) |
| 得意先/仕入先 | 00000000 / 30000123 |
8桁。00000000=自社(内部・実証案件用)。仕入先は同じMstDealのロール投影(75/75が得意先側にも実在) |
| 社員 | 1001 / E004 |
4桁数字(28/33=85%)と Exxx英数字(5/33=15%)が併存 確認済み。別々の登録経路の名残 推定 |
ItemNoRev、99.97%がNULL)ではなく番号の中に埋め込む。加工段階すら品番の接頭で表す(IT/TS)。手打ちで接尾を付ける文化がある(_ADVICS、_KIRIKAE、-SUETUKE)。そして「製品」の名前は独立したマスタではなく orders.project_name の自由記述に住んでいる — それでも34機種に正規化でき(1,032/1,265件=81.6%)、そのうち上位10機種で全体の79.4%をカバーする(詳細は fab-forward-pms の lineup-inference-2026-09-05.md)。
見出し/マスタ系のテーブルは業務コードをそのままキーにし、明細/エッジ系のテーブルは全て独自の *Seq 整数サロゲートを持つ。この線引きは16ソース全てで一貫している。
| PMSテーブル(TECHS源) | 実際のキー | 種別 |
|---|---|---|
parts(MstItemNo) | ItemNo | 自然キー |
customers/suppliers(MstDeal) | DealCd/SupplierCd | 自然キー |
supplier_price_tiers(MstSupplierBuyUp) | SupplierBuyUpSeq | 独自サロゲート |
part_compositions(MstPartsCompose) | PartsComposeSeq | 独自サロゲート((Parent,Child)は非一意、207重複) |
employees(MstPerson) | PersonCd | 自然キー |
seiban(TrnSeiban) | Seiban | 自然キー(別途SeibanNoは無い) |
orders(TrnOrder) | OrderNo | 自然キー |
production_items(TrnProd) | ProdSeq | 独自サロゲート(グローバル、製番単位ではない) |
purchase_order_headers(TrnSOrderH) | SOrderSlipNo | 自然キー(10桁ゼロ埋め連番) |
purchase_order_lines(TrnSOrderD) | SOrderDNo | 独自サロゲート |
acceptance_headers(TrnAcceptH) | AcceptNo | 自然キー |
acceptance_lines(TrnAcceptD) | AcceptDSeq | 独自サロゲート |
bom_lines(TrnBom) | PartsSeq | 独自サロゲート |
inventory_movements(TrnInOutRec) | InOutRecSeq | 独自サロゲート |
stock_balances(ViwRptStockConditionListInfo) | なし | 複合導出キー ItemNo|StockBaseCd|HouseCd |
唯一の複合キー実体(stock_balances)は、同時に唯一「確定スキーマ調査の16オブジェクトから外れている」実体でもある — ソースビュー(ViwRptStockConditionListInfo)が別のwave3設計ドキュメントからしか裏付けられていない。
TmStamp ウォッチマークと物理削除の罠
確定スキーマの16基底テーブル全てが TmStamp timestamp(8) NOT NULL(SQL Serverのrowversion)を持ち、stock_balancesを除く全実体はこれで増分同期する(何も変わらなければ0行更新)。だが TmStampは物理削除を検知できない — このTECHS環境はDelFlgを立てるだけでなく行を物理削除するため、TrnOrderDel(52行)・TrnSeibanDel(52行)・TrnProdDel(1,175行)という影テーブルが存在する。ウォッチマーク同期に加えて、この*Delテーブル(またはキー全件突合)による削除検知が必須。
受注部品表(TrnBom)とマスタ部品表(MstPartsCompose)は、似て非なる別物である。
| 受注部品表 TrnBom(bom_lines) | マスタ部品表 MstPartsCompose(part_compositions) | |
|---|---|---|
| 形 | フラット。ParentPartsSeq は297,158行全件でNULL — 列は存在するがこの環境では使われていない | 木構造。ルートからの最大深さちょうど4(確認済み、再帰CTE) |
| 件数 | 239,262明細 / 10,750ヘッダ | 45,521エッジ(45,314種のユニークな親子対、207組が重複) |
| 階層の代替表現 | ProdLevel≥2(13,139行)は同じ部品の加工段階違い(素材→加工中)であって独立部品ではない | ルート1,573種のうち852種(54%)は一度も発注されていない(=製造実績なし) |
| 手打ちの分類 | AssyUnitNo=KONYU(購入,79.3%)/GAITYU(外注,18.2%)+タイプミス群(ZZKONYU, GAICYU, GATIYU…) | parts_noは118種の値しかなく親ごとに非一意(位置バルーン番号の使い回しと推定) |
両者の一致度: 実際に発注実績のある877品番について、受注BOM(実績)とマスタBOM(設計)を比較すると、Jaccard中央値 0.961(200組サンプル、fab-forward-pmsのlineup-inference-2026-09-05.md実測)— 「設計通りに作られている」という点では両者はよく一致する。一方でマスタBOM側の54%は一度も実発注されておらず、「設計されたが売れたことのない構成」がマスタには混じっている。
| 無いもの | 実測 | PMS側の対応 |
|---|---|---|
| 製品/機種マスタ | orders.project_nameの自由記述のみ(949種、874種が一度きり) | /lineup 推定表示。正規化ルールで34機種に集約(81.6%、上位10機種で79.4%カバー) |
| 号機(アセット単位のシリアル) | production_itemsはジョブ内ユニット番号(ProdNo)を持つが、機体としての通し番号は無い | /serials を新設し、推定管理として別枠で持つ方針 |
| 売価 | 受注の売価 orders.amount が非ゼロなのは 1,265件中 11件、製造品目の production_items.unit_price/amount は 11,073行中 11行(0.1%)。原価に対して桁が合わないため利益率の分母に使えない | 売価未登録として画面に明示表示(黙って0円扱いにしない) |
| 実績完了日 | CompleteFinishYmd(complete_finish_date)は0%(全行空欄)。出荷実績日(ship_finish_date)は90.4%充填 | 完成実績日欄は空欄のまま表示し、出荷実績日を実績の代理指標として扱う |
| 製番付きの発注 | purchase_order_lines.seiban充填は 1/22,131行のみ | ジョブ単位の原価突合は発注ではなくbom_lines/acceptance_lines経由で行う |
| 継続的な入出庫 | inventory_movementsは2,264件、期間は2026-07-07〜07-31のみで以降ゼロ | 鏡像側のバグではないと確認済み。客先への未解決質問として保留(§7) |
客先の実スキーマは1,388オブジェクト中1,019がビュー(Viw*接頭)。base tableだけを見ていると、この環境の実際の姿を半分以上見落とす。
VIWRPTMSTDEAL)で保存され、実環境はPascalCase(ViwRptMstDeal)だったため、大文字小文字を区別する比較で8本のビューが誤って「欠落」と報告された。両辺を小文字化して比較し直して解決。ViwTrnBomの除外集合からDelFlg極性を確定した手口: ViwTrnBom(134列, 262,911行)は基底のTrnBom(296,594行)からちょうど33,683行を除外して投影している。これがDelFlg='S1'の行と完全一致することを確認し、フラグの意味を客先に聞かずに実測だけで確定した。「フラグの意味は推測せず、ビューの除外集合という別の実測値と突き合わせる」という、この調査全体で繰り返し使った手口。020101_受注一覧情報、020107_製番一覧情報など、02xxxx_という体系的な番号を持つ日本語名オブジェクトが275本存在し、逆引きカタログには一切載っていなかった。TrnOrderH/TrnOrderDが存在しないこの環境では、受注データの一部はこの帳票ファミリーの中に住んでいる可能性が高いが、まだ掘っていない。TrnOrderH/TrnOrderD/MstItemNoInfo/TrnInvStock/TrnBuyAcceptが見つからなかったことから、一時「受注管理/検収モジュールが未導入」と誤結論し、製造・購買・原価集計の大規模な再設計に踏み出しかけた。実際にはこの環境は別名(単一126列のTrnOrder、TrnProd、TrnAcceptH/TrnAcceptD)でデータを持っており、全て稼働していた。
鏡像データだけでは決着しなかった論点。推測で埋めていない。
class_code/class_nameは全1,265行で空欄、order_kind_codeは全行'S1' — 識別に使える値が無いinventory_movements.movement_type_code(S0/S1)の極性 — 入庫か出庫かS1=2,027行、S0=237行。頻度の偏りはあるが極性そのものは未確認TrnBom.MasterFlgの極性・意味S0=2,615行/S1=294,543行。ProdLevel 0/1集中や空欄ItemNoと相関はあるが、開示されておらず未確認のまま扱うinventory_movementsが2026-07-31で止まっているかデータ入力の中断か、鏡像が見えていない並行プロセスかは未測定IT/BS/DBS/YT/QY/AT…)が具体的に何を指すか確認できたのはIT=素材、TS=加工中の2つのみ