Upgrade to Pro — share decks privately, control downloads, hide ads and more …

履歴データテーブルとの向き合い方_PHPerKaigi2024

gennei
March 07, 2024

 履歴データテーブルとの向き合い方_PHPerKaigi2024

PHPerKaigi2024 の登壇資料です。

履歴データテーブルとの向き合い方
https://fortee.jp/phperkaigi-2024/proposal/47cf9f17-825a-4021-bf33-86e4a62bc222

gennei

March 07, 2024
Tweet

More Decks by gennei

Other Decks in Technology

Transcript

  1. 自己紹介 • アカウント: @gennei • 所属: カオナビ • 趣味 ◦

    ⚽ サンフレッチェ広島 ◦ 📚 積読 ◦ 📻 Podcast ◦ ☕ コーヒー
  2. テーブル設計 • ログ ◦ 注文履歴、発送履歴、アクセスログ • バージョン ◦ ソースコード、Wikipedia、ドキュメント •

    範囲履歴 ◦ 所属履歴、学歴 この記事を読んでくれ!! 履歴テーブルについて - 一休.com Developers Blog 変更履歴を持つテーブルの設計 #Database - Qiita だいたいみなさんの悩みについては書いてあります!
  3. 所属履歴の参考データ 社員ID 所属名 開始日 終了日 所属期間 A001 製造部 2023-04-01 現在

    11ヶ月 A001 管理部 2021-10-01 2023-03-31 1年6ヶ月 A002 人事部 2023-04-01 現在 11ヶ月
  4. テーブル設計 • メリット ◦ わかりやすい • デメリット ◦ レコードをまたぐバリデーション ◦

    現在所属の終了日の扱い ◦ 更新時に終了日を更新 + INSERT が必要 ◦ 過去のデータを変更したくなった時はどうする? 所属履歴 id 社員ID 所属名 開始日 終了日
  5. レコードをまたぐバリデーション 社員ID 所属名 開始日 終了日 A001 製造部 2023-04-01 現在 A001

    管理部 2021-10-01 2022-03-31 A001 人事部 2021-04-01 2023-03-31 3レコード目の開始終了の範囲内に 2レコード目の値が入ってしまっている
  6. 現在所属の終了日の扱い 社員ID 所属名 開始日 終了日 A001 製造部 2023-04-01 現在 A001

    管理部 2021-10-01 2022-03-31 A001 人事部 2021-04-01 2023-03-31 現在の値どうする?
  7. 現在所属の終了日の扱い 社員ID 所属名 開始日 終了日 A001 製造部 2023-04-01 現在 A001

    管理部 2021-10-01 2022-03-31 A001 人事部 2021-04-01 2023-03-31 null にしよう! nullを使う 複数行存在した場合 どうしますか?
  8. 現在所属の終了日の扱い 社員ID 所属名 開始日 終了日 A001 製造部 2023-04-01 現在 A001

    管理部 2021-10-01 2022-03-31 A001 人事部 2021-04-01 2023-03-31 9999-12-31 にして UK で制御 アプリケーションコードで 漏れなく変換を実装できますか?
  9. 更新時に終了日を更新 + INSERT が必要 社員ID 所属名 開始日 終了日 A001 製造部

    2023-04-01 現在 A001 管理部 2021-10-01 2022-03-31 A001 人事部 2021-04-01 2023-03-31 更新時2ステップ必要になる 1. 現在の値を更新する 2. 新しいレコードを作る
  10. 過去のデータを変更したくなった時はどうする? 社員ID 所属名 開始日 終了日 A001 製造部 2023-04-01 現在 A001

    管理部 2022-04-01 2023-03-31 A001 人事部 2021-04-01 2022-03-31 終了日を変更しようとすると 別の行に影響がでる
  11. 問題点まとめ • 開始日と終了日のバリデーションが難しい • 現在の所属の終了日の扱い ◦ nullにする -> 複数 null

    が入ってしまう ◦ 9999-12-31 + UK -> アプリで工夫が必要。 • 更新時に2レコード更新する必要がある • 過去の開始日や終了日を変更を考えるのが大変
  12. 業務の事実を記録する 社員ID 所属名 異動日 A001 製造部 2023-04-01 A001 管理部 2022-10-01

    A001 人事部 2021-04-01 イベントが発生した日  開始日 = 異動日  終了日 = 次の異動日 -1日
  13. つまりそれってイミュータブルデータモデルでは? • 雑に言うとそうです • 更新(UPDATE)を止める ◦ UPDATE で事実を失わないようにする • INSERT(or

    DELETE) だけでデータを記録していく 詳しくはこちらの 「イミュータブルデータモデルで始める実践データモデリン グ 業務の複雑さをシンプルに表現!」 を読んでくれ!
  14. 期間を計算するSQL (MySQL 8.0.35 で試しました) SELECT 社員ID, 所属名, 異動日 AS 開始日,

    COALESCE( LEAD(異動日) OVER (PARTITION BY 社員ID ORDER BY 異動日) - INTERVAL '1 day', CURRENT_DATE() ) AS 終了日 FROM 異動履歴 ORDER BY 社員ID,異動日;
  15. 期間を計算するSQL (MySQL 8.0.35 で試しました) SELECT 社員ID, 所属名, 異動日 AS 開始日,

    COALESCE( LEAD(異動日) OVER (PARTITION BY 社員ID ORDER BY 異動日) - INTERVAL '1 day', CURRENT_DATE() ) AS 終了日 FROM 異動履歴 ORDER BY 社員ID,異動日; LEAD() OVER () で1行下の値を取得 その後 -1 日する
  16. 期間を計算するSQL (MySQL 8.0.35 で試しました) SELECT 社員ID, 所属名, 異動日 AS 開始日,

    COALESCE( LEAD(異動日) OVER (PARTITION BY 社員ID ORDER BY 異動日) - INTERVAL '1 day', CURRENT_DATE() ) AS 終了日 FROM 異動履歴 ORDER BY 社員ID,異動日; LEAD() OVER () で1行下の値を取得 その後 -1 日する COALESCEで 1行下がないときは現在の日付を使う
  17. 参考記事・スライド • 履歴テーブルについて - 一休.com Developers Blog • 変更履歴を持つテーブルの設計 #Database

    - Qiita • 『失敗から学ぶ RDBの正しい歩き方』 ◦ 「Column非正規化と履歴データの違い」 • 『WEB+DB PRESS Vol.130』 ◦ 「イミュータブルデータモデルで始める実践データモデリング業務 の複雑さをシンプルに表現!」