［DB/SQL］要件をテーブルに落とし込む手法のメモ書き（複式簿記のテーブル設計を例に）

## この記事で書くこと
要件をテーブルに落とし込む手法のメモ書き（複式簿記のテーブル設計を例に）

## 前提条件
・SQLの基本的な文法(SELECT,INSERT等)を知っている

## 開発環境
開発環境は次の通り

|項目||
|---|---|
|PC|MacBook Air|
|OS|MacOS Catalina|
|DB|PostgreSQL|
|DB管理|pgAdmin4|
|Browser|Google Chrome|

## 「複式簿記」に興味を持った理由
・グーグル日本法人の社長を勤めた[村上憲郎さん](https://ja.wikipedia.org/wiki/%E6%9D%91%E4%B8%8A%E6%86%B2%E9%83%8E)が`「エンジニアとしてキャリアを始めた時に簿記を勉強させられたがそれが後に役に立った」`と書籍に書かれていたから。

## そもそも「複式簿記」とは？
・どこからいくらお金を調達して（=**負債**または**収益**）、
・何にいくらお金を支払ったのか（＝**費用**）
・または、調達したお金をどういう形でいくら保管しているか（＝**資産**）を記録する手法。

（目的）
・決算日における資産状況を把握する**貸借対照表（B/S）**を作成
・１年間の損益や**当期純利益**を把握する**損益計算書(P/L)**を作成


## テーブル設計の流れ
①要件の把握 >> ②概念設計 >> ③論理設計 >> ④物理設計

### 要件の把握
```text:要件
・複式簿記で家計簿を入力したい
・仕訳表を表示できるようにしたい
・例えば12000円の服をクレジットカードで10000円および現金で2000円支払って購入したような取引も入力できるようにしたい
・勘定科目はあとから追加できるようにしてほしい
```

（仕訳表のイメージ）

|    日付    |   借方科目   | 借方金額 |        貸方科目        | 貸方金額 |         摘要         
--------+------------+--------------+----------+------------------------+----------+----------------------
| 2020-01-26 | 現金         |    10000 | 開始残高               |    10000 | 現金の開始残高
| 2020-01-26 | 普通預金     |   500000 | 開始残高               |   500000 | 普通預金の開始残高
| 2020-01-26 | Suica        |     5000 | 開始残高               |     5000 | Suicaの開始残高
| 2020-01-27 | 食費         |      129 | 現金                   |      129 | コンビニで緑茶を購入
| 2020-01-27 | 衣服・美容費 |    12000 | クレジットカード未払金 |    10000 | 服を購入
|  |  |  | 現金                   |     2000 | 服を購入
| 2020-01-27 | 交通費       |      230 | Suica                  |      230 | 梅田〜なんばを移動
| 2020-01-27 | 食費         |      110 | 普通預金               |      110 | おにぎりを購入


### 概念設計
どういう情報を管理する必要があるか整理すること

|必要な情報|
|---|
|仕訳表|
|勘定科目の一覧|

### 論理設計
整理した情報の構造を具体化すること

・仕訳表を表示するためには、`仕訳テーブル(journal)`が必要
・勘定科目の一覧を用意するためには、`勘定科目テーブル(accounts_title)`が必要

・下記`要件`を叶えるためには、明細の情報を格納する必要がある。
・明細情報を格納するために、`仕訳明細テーブル(journal_details)`を用意

```text:要件
・例えば12000円の服をクレジットカードで10000円および現金で2000円支払って購入したような取引も入力できるようにしたい
```


（ER図の例）
![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199441/9003a7a2-586e-9c3e-8288-0d154b75372a.png)


### 物理設計
全てのテーブルの列について、データ型・インデックス・制約・デフォルト値を確定すること

**仕訳テーブル（journal）**

|カラム名 | データ型 | 制約 |
|---|---|---|
|id|SERIAL|主キー|
|date|DATE|NULL不可|
|memo|VARCHAR(20)||


**仕訳明細テーブル（journal_details）**

|カラム名 | データ型 | 制約 |
|---|---|---|
|id|SERIAL|主キー|
|journal_id|INTEGER|外部キー(仕訳テーブル id)|
|debit_account_id|INTEGER|外部キー(勘定科目テーブル id)|
|debit_amount|INTEGER|NULL不可|
|credit_account_id|INTEGER|外部キー(勘定科目テーブル id)|
|credit_amount|INTEGER|NULL不可|

**勘定科目テーブル（accounts_title）**

|カラム名 | データ型 | 制約 |
|---|---|---|
|id|SERIAL|主キー|
|name|VARCHAR(10)|NULL不可・重複不可|
|account_type|INTEGER|設定可能な値：0,1,2,3,4のうち1つ※|

※`0:資産 1:負債 2:費用 3:収益 4:純資産`として勘定科目を区別


## CREATE TABLE
```SQL:仕訳テーブル（journal）
CREATE TABLE journal(
id SERIAL PRIMARY KEY,
date DATE NOT NULL,
memo VARCHAR(20)
);
```
```SQL:仕訳IDシーケンス（journal_id_sequence）
CREATE SEQUENCE journal_id_sequence;
```

```SQL:仕訳明細テーブル（journal_details）
CREATE TABLE journal_details(
id SERIAL PRIMARY KEY,
journal_id INTEGER REFERENCES journal(id),
debit_accounts_id INTEGER REFERENCES accounts_title(id),
debit_amount INTEGER NOT NULL,
credit_accounts_id INTEGER REFERENCES accounts_title(id),
credit_amount INTEGER NOT NULL
);
```
```SQL:仕訳明細IDシーケンス（journal_details_id_sequence）
CREATE SEQUENCE journal_details_id_sequence;
```

```SQL:勘定科目テーブル（accounts_title）
CREATE TABLE accounts_title(
id SERIAL PRIMARY KEY,
name VARCHAR(10) NOT NULL UNIQUE,
accounts_type INTEGER CHECH(accounts_type in (0,1,2,3,4))
);
```

```SQL:勘定科目IDシーケンス（accounts_title_id_sequence）
CREATE SEQUENCE accounts_title_id_sequence;
```

## SQLを叩いて仕訳表を表示してみよう
```SQL:勘定科目テーブルにデータを投入
insert into accounts_title(id,name,account_type) values(1,'現金',0);
```

```SQL:仕訳テーブルにデータを投入
insert into journal(id,date,memo) values((select(nextval('journal_id_sequence'))),(SELECT CURRENT_DATE),'おにぎりを購入');
select * from journal;
```

```SQL:仕訳明細テーブルにデータを投入
insert into journal_details(id,journal_id,debit_accounts_id,debit_amount,credit_accounts_id,credit_amount)
values((select(nextval('journal_details_id_sequence'))),3,3,5000,20,5000);
```

```SQL:仕訳表を表示
select journal.id as 仕訳ID,
journal.date as 日付, 
(select accounts_title.name from accounts_title where accounts_title.id = journal_details.debit_accounts_id) as 借方科目,
journal_details.credit_amount as 借方金額,
(select accounts_title.name from accounts_title where accounts_title.id = journal_details.credit_accounts_id) as 貸方科目,
journal_details.credit_amount as 貸方金額,
journal.memo as 摘要 from journal_details
join journal
on journal_details.journal_id = journal.id;
```

```text:勘定科目を一覧表示
 id |          name          | account_type 
----+------------------------+--------------
  1 | 現金                   |            0
  2 | 普通預金               |            0
  3 | Suica                  |            0
  4 | その他（資産）         |            0
  5 | クレジットカード未払金 |            1
  6 | その他（負債）         |            1
  7 | 食費                   |            2
  8 | 日用品費               |            2
  9 | 衣服・美容費           |            2
 10 | 交通費                 |            2
 11 | 光熱費                 |            2
 12 | 教育費                 |            2
 13 | 交際費                 |            2
 14 | 趣味・娯楽             |            2
 15 | 家賃                   |            2
 16 | その他（費用）         |            2
 17 | 給与                   |            3
 18 | 副収入                 |            3
 19 | その他（収益）         |            3
 20 | 開始残高               |            4
 21 | その他（純資産）       |            4
(21 rows)
```

```text:明細を一覧表示
 id |    date    |         memo         
----+------------+----------------------
  1 | 2020-01-26 | 現金の開始残高
  2 | 2020-01-26 | 普通預金の開始残高
  3 | 2020-01-26 | Suicaの開始残高
  6 | 2020-01-27 | コンビニで緑茶を購入
  7 | 2020-01-27 | 服を購入
  8 | 2020-01-27 | 梅田〜なんばを移動
  9 | 2020-01-27 | おにぎりを購入
(7 rows)
```

```text:表示結果(仕訳明細)
 仕訳id |    日付    |   借方科目   | 借方金額 |        貸方科目        | 貸方金額 |         摘要         
--------+------------+--------------+----------+------------------------+----------+----------------------
      1 | 2020-01-26 | 現金         |    10000 | 開始残高               |    10000 | 現金の開始残高
      2 | 2020-01-26 | 普通預金     |   500000 | 開始残高               |   500000 | 普通預金の開始残高
      3 | 2020-01-26 | Suica        |     5000 | 開始残高               |     5000 | Suicaの開始残高
      6 | 2020-01-27 | 食費         |      129 | 現金                   |      129 | コンビニで緑茶を購入
      7 | 2020-01-27 | 衣服・美容費 |    10000 | クレジットカード未払金 |    10000 | 服を購入
      7 | 2020-01-27 | 衣服・美容費 |     2000 | 現金                   |     2000 | 服を購入
      8 | 2020-01-27 | 交通費       |      230 | Suica                  |      230 | 梅田〜なんばを移動
      9 | 2020-01-27 | 食費         |      110 | 普通預金               |      110 | おにぎりを購入
(8 rows)

```

## 今後やりたいこと
① 複式簿記を採用した家計簿アプリ（WEBアプリ）を実装したい

（想定している開発環境）

|項目||
|---|---|
|PC|MacBook Air|
|OS|MacOS Catalina|
|Container|Docker|
|WEB Server|Apache Tomcat|
|Server Side|Java Servlet + JSP|
|Front End|React Pivottable.js|
|DB|PostgreSQL|
|DB管理|pgAdmin4|
|バージョン管理|GitHub|
|Browser|Google Chrome|


② 簿記２級を取得したい
・商業簿記や工業簿記を勉強することで、形のないものをどう現金化（＝**価値創出**）するかのヒントを学習できる（はず）

## 参考資料
**データベースのテーブル設計に関するもの**
[スッキリわかるSQL入門 第２版（株式会社インプレス）](https://www.amazon.co.jp/%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8BSQL%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E3%83%89%E3%83%AA%E3%83%AB222%E5%95%8F%E4%BB%98%E3%81%8D-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1%E6%B8%85%E5%96%AC/dp/4295005096/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8B&qid=1581663075&sr=8-2)

**複式簿記に関するもの**
[初歩から学ぶ簿記・経営分析（税務経理協会 三枝幸文・松井富佐男）](https://www.amazon.co.jp/%E7%B0%BF%E8%A8%98%E3%83%BB%E7%B5%8C%E5%96%B6%E5%88%86%E6%9E%90-%E5%88%9D%E6%AD%A9%E3%81%8B%E3%82%89%E5%AD%A6%E3%81%B6-%E4%B8%89%E6%9E%9D-%E5%B9%B8%E6%96%87/dp/4419063270/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E5%88%9D%E6%AD%A9%E3%81%8B%E3%82%89%E5%AD%A6%E3%81%B6%E7%B0%BF%E8%A8%98%E3%83%BB%E7%B5%8C%E5%96%B6%E5%88%86%E6%9E%90&qid=1581663172&sr=8-1)
[会計の世界史 イタリア、イギリス、アメリカ - 500年の物語（日本経済新聞出版社 田中靖浩）](https://www.amazon.co.jp/%E4%BC%9A%E8%A8%88%E3%81%AE%E4%B8%96%E7%95%8C%E5%8F%B2-%E3%82%A4%E3%82%BF%E3%83%AA%E3%82%A2%E3%80%81%E3%82%A4%E3%82%AE%E3%83%AA%E3%82%B9%E3%80%81%E3%82%A2%E3%83%A1%E3%83%AA%E3%82%AB%E2%80%95%E2%80%95500%E5%B9%B4%E3%81%AE%E7%89%A9%E8%AA%9E-%E7%94%B0%E4%B8%AD-%E9%9D%96%E6%B5%A9/dp/4532322030/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=28ZVU03E6WUN3&keywords=%E4%BC%9A%E8%A8%88%E3%81%AE%E4%B8%96%E7%95%8C%E5%8F%B2&qid=1581663122&sprefix=%E4%BC%9A%E8%A8%88%2Caps%2C242&sr=8-1)

**エンジニアも簿記を勉強することでキャリアが広がることを示す記事**
[村上式シンプル仕事術―厳しい時代を生き抜く14の原理原則（ダイヤモンド社 村上憲郎）](https://www.amazon.co.jp/%E6%9D%91%E4%B8%8A%E5%BC%8F%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E4%BB%95%E4%BA%8B%E8%A1%93%E2%80%95%E5%8E%B3%E3%81%97%E3%81%84%E6%99%82%E4%BB%A3%E3%82%92%E7%94%9F%E3%81%8D%E6%8A%9C%E3%81%8F14%E3%81%AE%E5%8E%9F%E7%90%86%E5%8E%9F%E5%89%87-%E6%9D%91%E4%B8%8A-%E6%86%B2%E9%83%8E/dp/4478008612/ref=tmm_hrd_swatch_0?_encoding=UTF8&qid=&sr=)