転職したらスマレジだった件

スマレジのエンジニアやまてのテックブログです。マジレス大歓迎です。

ER図の作図などに関する自動化について A5M2, dbdiagram.io, DBeaver を使ってみる - ②始め方、使い方、感想

こんにちは!

スマレジ・テックファームのWebエンジニアやまてと申します。

はじめに

qiita.com

前回の記事で、上記のQiita記事へのコメントと、コメントで教えていただいたツールを、ご紹介させていただきました。

ryamate.hatenablog.com

今回は、記事に対してのコメントで教えていただいたツールで、主に「ER図の自動生成」についての機能を試していきたいと思います。


具体的には、ご紹介いただいたツールの中で無料のものから、下記の3つのツールを試しに使ってみます。

  • dbdiagram.io
  • DBeaver
  • A5:SQL Mk-2(A5M2)


それぞれのツールについて、下記の内容を書いていきます。

  • 始め方
  • 使い方
  • 感想


どのツールも多機能で、「ER図の自動生成」についてはどれでもできるのですが、これが一番良くて万能!という感想はなく、どれも便利なツールで今回試してない機能は色々違いがあるんだろうと思ったので、これから用途によって選択していけたらと思っています。


感想については、ツールが多機能であっても一部の機能しか試しておらず、実務で使ったわけでもないため、浅い感想であることはご容赦くださいませ。

環境

  • macOS Big Sur バージョン: 11.6
  • Homebrew バージョン: 3.5.4
  • DBeaver バージョン: 22.1.4
  • A5M2(A5:SQL Mk-2(x64 edition)) バージョン: 2.17.2

以前、ポートフォリオとして作成したWebアプリケーションの MySQL で作成したデータベースをサンプルとして使用します。

qiita.com

目次


1. dbdiagram.io

dbdiagram.io

dbdiagram.io でできることは、

  • SQL ダンプファイル(DDL) から ダイアグラム(ER図) をすばやく生成できる
  • SQL ステートメントDDL) を直接生成して、データベースのテーブルを作成できる

などです。

  • また、データベースを定義するための構文として DBML を使用します。

1-1. 始める

アプリのページにアクセスして、Googleアカウントなどでサインインしたら、ブラウザ上で使用をすぐに開始することができます。

私は Googleアカウント でサインインしました。


1-2. 使う

今回、「ER図の自動生成」が主目的であるため、dbdiagram.io では、

  • SQL ダンプファイル(DDL) から ダイアグラム(ER図) をすばやく生成できる

という使い方を試していきます。

SQLダンプファイル(DDL)の作成

② ER図 の生成

DDLの生成(ER図からDDLを生成)

SQLダンプファイル(DDL)の作成

まずは、SQLダンプファイル(DDL) を用意しました。

qiita.com

上記記事の方法で作成しましたが、事前準備として、#コメントアウトSQLでエラーになるため、 # で始まる全行を削除しました。

また、LOCKUNLOCK は dbdiagram.io への import 時にエラーになるため、削除しました。


dbdiagram.io への import 用に作成した SQLダンプファイル はこちらです。

dbdiagram.io への import 用の SQLダンプファイル

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
SET NAMES utf8mb4;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE='NO_AUTO_VALUE_ON_ZERO', SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

DROP TABLE IF EXISTS `child_read_record`;

CREATE TABLE `child_read_record` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `read_record_id` bigint unsigned NOT NULL,
  `child_id` bigint unsigned NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `child_read_record_read_record_id_foreign` (`read_record_id`),
  KEY `child_read_record_child_id_foreign` (`child_id`),
  CONSTRAINT `child_read_record_child_id_foreign` FOREIGN KEY (`child_id`) REFERENCES `children` (`id`) ON DELETE CASCADE,
  CONSTRAINT `child_read_record_read_record_id_foreign` FOREIGN KEY (`read_record_id`) REFERENCES `read_records` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `children`;

CREATE TABLE `children` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `family_id` bigint unsigned NOT NULL,
  `name` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `gender_code` int DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `children_family_id_foreign` (`family_id`),
  CONSTRAINT `children_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- LOCK TABLES `children` WRITE;
/*!40000 ALTER TABLE `children` DISABLE KEYS */;

INSERT INTO `children` (`id`, `family_id`, `name`, `gender_code`, `birthday`, `created_at`, `updated_at`)
VALUES
    (1,1,'ゆきまさ',1,'2020-04-01','2022-07-15 06:45:00','2022-07-15 06:45:00'),
    (2,1,'みくり',2,'2021-04-01','2022-07-15 06:45:00','2022-07-15 06:45:00'),
    (3,2,'お子さま',0,NULL,'2022-07-15 06:50:06','2022-07-15 06:50:06');

/*!40000 ALTER TABLE `children` ENABLE KEYS */;
-- UNLOCK TABLES;

DROP TABLE IF EXISTS `contacts`;

CREATE TABLE `contacts` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `nickname` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `body` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `failed_jobs`;

CREATE TABLE `failed_jobs` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `connection` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `queue` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `exception` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `families`;

CREATE TABLE `families` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `nickname` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `introduction` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `families_name_unique` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- LOCK TABLES `families` WRITE;
/*!40000 ALTER TABLE `families` DISABLE KEYS */;

INSERT INTO `families` (`id`, `name`, `nickname`, `introduction`, `created_at`, `updated_at`)
VALUES
    (1,'guest','ゲスト','ゲストログインユーザー用です。よろしくお願いします。','2022-07-15 06:45:00','2022-07-15 06:45:00'),
    (2,'y6E2867HyrBuG9fT','よんで','よろしくお願いします。','2022-07-15 06:50:06','2022-07-15 06:50:06');

/*!40000 ALTER TABLE `families` ENABLE KEYS */;
-- UNLOCK TABLES;

DROP TABLE IF EXISTS `follows`;

CREATE TABLE `follows` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint unsigned NOT NULL,
  `family_id` bigint unsigned NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `follows_user_id_foreign` (`user_id`),
  KEY `follows_family_id_foreign` (`family_id`),
  CONSTRAINT `follows_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`) ON DELETE CASCADE,
  CONSTRAINT `follows_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `invites`;

CREATE TABLE `invites` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `family_id` bigint unsigned NOT NULL,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `token` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `invites_token_unique` (`token`),
  KEY `invites_family_id_foreign` (`family_id`),
  CONSTRAINT `invites_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- LOCK TABLES `invites` WRITE;
/*!40000 ALTER TABLE `invites` DISABLE KEYS */;

INSERT INTO `invites` (`id`, `family_id`, `email`, `token`, `created_at`, `updated_at`)
VALUES
    (1,2,'test2@test','9UyZzBbWeNL41Dcr','2022-07-15 06:51:23','2022-07-15 06:51:23');

/*!40000 ALTER TABLE `invites` ENABLE KEYS */;
-- UNLOCK TABLES;

DROP TABLE IF EXISTS `likes`;

CREATE TABLE `likes` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint unsigned NOT NULL,
  `picture_book_id` bigint unsigned NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `likes_user_id_foreign` (`user_id`),
  KEY `likes_picture_book_id_foreign` (`picture_book_id`),
  CONSTRAINT `likes_picture_book_id_foreign` FOREIGN KEY (`picture_book_id`) REFERENCES `picture_books` (`id`) ON DELETE CASCADE,
  CONSTRAINT `likes_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `migrations`;

CREATE TABLE `migrations` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `batch` int NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- LOCK TABLES `migrations` WRITE;
/*!40000 ALTER TABLE `migrations` DISABLE KEYS */;

INSERT INTO `migrations` (`id`, `migration`, `batch`)
VALUES
    (1,'2014_10_12_100000_create_password_resets_table',1),
    (2,'2019_08_19_000000_create_failed_jobs_table',1),
    (3,'2021_03_02_171654_create_families_table',1),
    (4,'2021_03_02_171655_create_users_table',1),
    (5,'2021_03_02_235959_create_children_table',1),
    (6,'2021_03_03_000000_create_picture_books_table',1),
    (7,'2021_03_05_000000_create_read_records_table',1),
    (8,'2021_03_06_000000_create_child_read_record_table',1),
    (9,'2021_05_10_155314_create_tags_table',1),
    (10,'2021_05_10_171704_create_read_record_tag_table',1),
    (11,'2021_05_11_132606_create_follows_table',1),
    (12,'2021_05_31_235959_create_likes_table',1),
    (13,'2021_06_09_180935_create_invites_table',1),
    (14,'2021_07_09_205018_create_contacts_table',1),
    (15,'2021_07_18_145514_add_column_soft_deletes_users_table',1);

/*!40000 ALTER TABLE `migrations` ENABLE KEYS */;
-- UNLOCK TABLES;

DROP TABLE IF EXISTS `password_resets`;

CREATE TABLE `password_resets` (
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  KEY `password_resets_email_index` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `picture_books`;

CREATE TABLE `picture_books` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `family_id` bigint unsigned NOT NULL,
  `user_id` bigint unsigned NOT NULL,
  `google_books_id` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `isbn_13` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `authors` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `published_date` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `description` varchar(1000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `thumbnail_url` varchar(1000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `five_star_rating` int NOT NULL,
  `read_status` int NOT NULL,
  `review` varchar(1000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `picture_books_family_id_foreign` (`family_id`),
  KEY `picture_books_user_id_foreign` (`user_id`),
  CONSTRAINT `picture_books_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`),
  CONSTRAINT `picture_books_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `read_record_tag`;

CREATE TABLE `read_record_tag` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `read_record_id` bigint unsigned NOT NULL,
  `tag_id` bigint unsigned NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `read_record_tag_read_record_id_foreign` (`read_record_id`),
  KEY `read_record_tag_tag_id_foreign` (`tag_id`),
  CONSTRAINT `read_record_tag_read_record_id_foreign` FOREIGN KEY (`read_record_id`) REFERENCES `read_records` (`id`) ON DELETE CASCADE,
  CONSTRAINT `read_record_tag_tag_id_foreign` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `read_records`;

CREATE TABLE `read_records` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `picture_book_id` bigint unsigned NOT NULL,
  `family_id` bigint unsigned NOT NULL,
  `user_id` bigint unsigned NOT NULL,
  `memo` varchar(1000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `read_date` date NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `read_records_picture_book_id_foreign` (`picture_book_id`),
  KEY `read_records_family_id_foreign` (`family_id`),
  KEY `read_records_user_id_foreign` (`user_id`),
  CONSTRAINT `read_records_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`) ON DELETE CASCADE,
  CONSTRAINT `read_records_picture_book_id_foreign` FOREIGN KEY (`picture_book_id`) REFERENCES `picture_books` (`id`) ON DELETE CASCADE,
  CONSTRAINT `read_records_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `tags`;

CREATE TABLE `tags` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `tags_name_unique` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

DROP TABLE IF EXISTS `users`;

CREATE TABLE `users` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `family_id` bigint unsigned NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `nickname` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email_verified_at` timestamp NULL DEFAULT NULL,
  `password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `icon_path` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `relation` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  `deleted_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `users_name_unique` (`name`),
  UNIQUE KEY `users_email_unique` (`email`,`deleted_at`),
  KEY `users_family_id_foreign` (`family_id`),
  CONSTRAINT `users_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- LOCK TABLES `users` WRITE;
/*!40000 ALTER TABLE `users` DISABLE KEYS */;

INSERT INTO `users` (`id`, `family_id`, `name`, `nickname`, `email`, `email_verified_at`, `password`, `remember_token`, `icon_path`, `relation`, `created_at`, `updated_at`, `deleted_at`)
VALUES
    (1,1,'guest_user','げん(ゲスト)','guest_user@guest.com','2022-07-15 06:45:01',NULL,NULL,'image/1.jpg','パパ','2022-07-15 06:45:01','2022-07-15 06:45:01',NULL),
    (2,1,'guest_partner','ゆい(パートナー)','guest_partner@guest.com','2022-07-15 06:45:01',NULL,NULL,'image/2.jpg','ママ','2022-07-15 06:45:01','2022-07-15 06:45:01',NULL),
    (3,2,'kWJ1A7fhlzUZXDAb','やまて','test@test','2022-07-15 06:50:41','$2y$10$JCbzpFTNRTTbYfh9jxp.u.0JB6AETjnJitwofj3tv4Mi7Gn/GyCTm',NULL,NULL,NULL,'2022-07-15 06:50:06','2022-07-15 06:50:41',NULL);

/*!40000 ALTER TABLE `users` ENABLE KEYS */;
-- UNLOCK TABLES;

/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;


② ER図 の生成

dbdiagram.io を開きます(サインインします)。

dbdiagram.io

SQLダンプファイル から ER図 を生成するには、

画面上部の「Import」→「Import from MySQL」を押します。

先程の SQLダンプファイル をアップロードします。

アップロードが完了したら、右側に ER図 が表示され、左側にER図の元となっている DBML が表示されます。(DBMLも自動生成されます)

参考:自動生成された DBML 全文

Table "child_read_record" {
  "id" bigint [pk, not null, increment]
  "read_record_id" bigint [not null]
  "child_id" bigint [not null]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  read_record_id [name: "child_read_record_read_record_id_foreign"]
  child_id [name: "child_read_record_child_id_foreign"]
}
}

Table "children" {
  "id" bigint [pk, not null, increment]
  "family_id" bigint [not null]
  "name" varchar(100) [default: NULL]
  "gender_code" int [default: NULL]
  "birthday" date [default: NULL]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  family_id [name: "children_family_id_foreign"]
}
}

Table "contacts" {
  "id" bigint [pk, not null, increment]
  "email" varchar(255) [not null]
  "nickname" varchar(255) [not null]
  "name" varchar(255) [default: NULL]
  "title" varchar(255) [default: NULL]
  "body" varchar(255) [not null]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]
}

Table "failed_jobs" {
  "id" bigint [pk, not null, increment]
  "connection" text [not null]
  "queue" text [not null]
  "payload" longtext [not null]
  "exception" longtext [not null]
  "failed_at" timestamp [not null, default: `CURRENT_TIMESTAMP`]
}

Table "families" {
  "id" bigint [pk, not null, increment]
  "name" varchar(100) [not null]
  "nickname" varchar(255) [default: NULL]
  "introduction" varchar(255) [default: NULL]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  name [unique, name: "families_name_unique"]
}
}

Table "follows" {
  "id" bigint [pk, not null, increment]
  "user_id" bigint [not null]
  "family_id" bigint [not null]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  user_id [name: "follows_user_id_foreign"]
  family_id [name: "follows_family_id_foreign"]
}
}

Table "invites" {
  "id" bigint [pk, not null, increment]
  "family_id" bigint [not null]
  "email" varchar(255) [not null]
  "token" varchar(16) [not null]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  token [unique, name: "invites_token_unique"]
  family_id [name: "invites_family_id_foreign"]
}
}

Table "likes" {
  "id" bigint [pk, not null, increment]
  "user_id" bigint [not null]
  "picture_book_id" bigint [not null]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  user_id [name: "likes_user_id_foreign"]
  picture_book_id [name: "likes_picture_book_id_foreign"]
}
}

Table "migrations" {
  "id" int [pk, not null, increment]
  "migration" varchar(255) [not null]
  "batch" int [not null]
}

Table "password_resets" {
  "email" varchar(255) [not null]
  "token" varchar(255) [not null]
  "created_at" timestamp [default: NULL]

Indexes {
  email [name: "password_resets_email_index"]
}
}

Table "picture_books" {
  "id" bigint [pk, not null, increment]
  "family_id" bigint [not null]
  "user_id" bigint [not null]
  "google_books_id" varchar(100) [not null]
  "isbn_13" varchar(100) [default: NULL]
  "title" varchar(255) [not null]
  "authors" varchar(255) [default: NULL]
  "published_date" varchar(100) [default: NULL]
  "description" varchar(1000) [default: NULL]
  "thumbnail_url" varchar(1000) [default: NULL]
  "five_star_rating" int [not null]
  "read_status" int [not null]
  "review" varchar(1000) [default: NULL]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  family_id [name: "picture_books_family_id_foreign"]
  user_id [name: "picture_books_user_id_foreign"]
}
}

Table "read_record_tag" {
  "id" bigint [pk, not null, increment]
  "read_record_id" bigint [not null]
  "tag_id" bigint [not null]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  read_record_id [name: "read_record_tag_read_record_id_foreign"]
  tag_id [name: "read_record_tag_tag_id_foreign"]
}
}

Table "read_records" {
  "id" bigint [pk, not null, increment]
  "picture_book_id" bigint [not null]
  "family_id" bigint [not null]
  "user_id" bigint [not null]
  "memo" varchar(1000) [default: NULL]
  "read_date" date [not null]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  picture_book_id [name: "read_records_picture_book_id_foreign"]
  family_id [name: "read_records_family_id_foreign"]
  user_id [name: "read_records_user_id_foreign"]
}
}

Table "tags" {
  "id" bigint [pk, not null, increment]
  "name" varchar(255) [not null]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]

Indexes {
  name [unique, name: "tags_name_unique"]
}
}

Table "users" {
  "id" bigint [pk, not null, increment]
  "family_id" bigint [not null]
  "name" varchar(255) [not null]
  "nickname" varchar(255) [default: NULL]
  "email" varchar(255) [not null]
  "email_verified_at" timestamp [default: NULL]
  "password" varchar(255) [default: NULL]
  "remember_token" varchar(100) [default: NULL]
  "icon_path" varchar(255) [default: NULL]
  "relation" varchar(100) [default: NULL]
  "created_at" timestamp [default: NULL]
  "updated_at" timestamp [default: NULL]
  "deleted_at" timestamp [default: NULL]

Indexes {
  name [unique, name: "users_name_unique"]
  (email, deleted_at) [unique, name: "users_email_unique"]
  family_id [name: "users_family_id_foreign"]
}
}

Ref "child_read_record_child_id_foreign":"children"."id" < "child_read_record"."child_id" [delete: cascade]

Ref "child_read_record_read_record_id_foreign":"read_records"."id" < "child_read_record"."read_record_id" [delete: cascade]

Ref "children_family_id_foreign":"families"."id" < "children"."family_id"

Ref "follows_family_id_foreign":"families"."id" < "follows"."family_id" [delete: cascade]

Ref "follows_user_id_foreign":"users"."id" < "follows"."user_id" [delete: cascade]

Ref "invites_family_id_foreign":"families"."id" < "invites"."family_id"

Ref "likes_picture_book_id_foreign":"picture_books"."id" < "likes"."picture_book_id" [delete: cascade]

Ref "likes_user_id_foreign":"users"."id" < "likes"."user_id" [delete: cascade]

Ref "picture_books_family_id_foreign":"families"."id" < "picture_books"."family_id"

Ref "picture_books_user_id_foreign":"users"."id" < "picture_books"."user_id"

Ref "read_record_tag_read_record_id_foreign":"read_records"."id" < "read_record_tag"."read_record_id" [delete: cascade]

Ref "read_record_tag_tag_id_foreign":"tags"."id" < "read_record_tag"."tag_id" [delete: cascade]

Ref "read_records_family_id_foreign":"families"."id" < "read_records"."family_id" [delete: cascade]

Ref "read_records_picture_book_id_foreign":"picture_books"."id" < "read_records"."picture_book_id" [delete: cascade]

Ref "read_records_user_id_foreign":"users"."id" < "read_records"."user_id" [delete: cascade]

Ref "users_family_id_foreign":"families"."id" < "users"."family_id"

テーブルの位置は DBML で記述したテーブルの順番が考慮されているようで、画像のER図のテーブル配置は、手作業で配置したいところに動かしました(動かした後の状態で保存されます)。

以下は Export してみた PNGファイル です。

黒もあります。

DDL の生成

また、ER図から、DDLを自動生成することもできました。

Export から Export to MySQL を選択する。

以下が ダウンロードされた SQL ファイルです。

ダウンロードされた SQL ファイル

CREATE TABLE `child_read_record` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `read_record_id` bigint NOT NULL,
  `child_id` bigint NOT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `children` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `family_id` bigint NOT NULL,
  `name` varchar(100) DEFAULT NULL,
  `gender_code` int DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `contacts` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `email` varchar(255) NOT NULL,
  `nickname` varchar(255) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `title` varchar(255) DEFAULT NULL,
  `body` varchar(255) NOT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `failed_jobs` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `connection` text NOT NULL,
  `queue` text NOT NULL,
  `payload` longtext NOT NULL,
  `exception` longtext NOT NULL,
  `failed_at` timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);

CREATE TABLE `families` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `nickname` varchar(255) DEFAULT NULL,
  `introduction` varchar(255) DEFAULT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `follows` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `user_id` bigint NOT NULL,
  `family_id` bigint NOT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `invites` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `family_id` bigint NOT NULL,
  `email` varchar(255) NOT NULL,
  `token` varchar(16) NOT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `likes` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `user_id` bigint NOT NULL,
  `picture_book_id` bigint NOT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `migrations` (
  `id` int PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `migration` varchar(255) NOT NULL,
  `batch` int NOT NULL
);

CREATE TABLE `password_resets` (
  `email` varchar(255) NOT NULL,
  `token` varchar(255) NOT NULL,
  `created_at` timestamp DEFAULT NULL
);

CREATE TABLE `picture_books` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `family_id` bigint NOT NULL,
  `user_id` bigint NOT NULL,
  `google_books_id` varchar(100) NOT NULL,
  `isbn_13` varchar(100) DEFAULT NULL,
  `title` varchar(255) NOT NULL,
  `authors` varchar(255) DEFAULT NULL,
  `published_date` varchar(100) DEFAULT NULL,
  `description` varchar(1000) DEFAULT NULL,
  `thumbnail_url` varchar(1000) DEFAULT NULL,
  `five_star_rating` int NOT NULL,
  `read_status` int NOT NULL,
  `review` varchar(1000) DEFAULT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `read_record_tag` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `read_record_id` bigint NOT NULL,
  `tag_id` bigint NOT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `read_records` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `picture_book_id` bigint NOT NULL,
  `family_id` bigint NOT NULL,
  `user_id` bigint NOT NULL,
  `memo` varchar(1000) DEFAULT NULL,
  `read_date` date NOT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `tags` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL
);

CREATE TABLE `users` (
  `id` bigint PRIMARY KEY NOT NULL AUTO_INCREMENT,
  `family_id` bigint NOT NULL,
  `name` varchar(255) NOT NULL,
  `nickname` varchar(255) DEFAULT NULL,
  `email` varchar(255) NOT NULL,
  `email_verified_at` timestamp DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `remember_token` varchar(100) DEFAULT NULL,
  `icon_path` varchar(255) DEFAULT NULL,
  `relation` varchar(100) DEFAULT NULL,
  `created_at` timestamp DEFAULT NULL,
  `updated_at` timestamp DEFAULT NULL,
  `deleted_at` timestamp DEFAULT NULL
);

CREATE INDEX `child_read_record_read_record_id_foreign` ON `child_read_record` (`read_record_id`);

CREATE INDEX `child_read_record_child_id_foreign` ON `child_read_record` (`child_id`);

CREATE INDEX `children_family_id_foreign` ON `children` (`family_id`);

CREATE UNIQUE INDEX `families_name_unique` ON `families` (`name`);

CREATE INDEX `follows_user_id_foreign` ON `follows` (`user_id`);

CREATE INDEX `follows_family_id_foreign` ON `follows` (`family_id`);

CREATE UNIQUE INDEX `invites_token_unique` ON `invites` (`token`);

CREATE INDEX `invites_family_id_foreign` ON `invites` (`family_id`);

CREATE INDEX `likes_user_id_foreign` ON `likes` (`user_id`);

CREATE INDEX `likes_picture_book_id_foreign` ON `likes` (`picture_book_id`);

CREATE INDEX `password_resets_email_index` ON `password_resets` (`email`);

CREATE INDEX `picture_books_family_id_foreign` ON `picture_books` (`family_id`);

CREATE INDEX `picture_books_user_id_foreign` ON `picture_books` (`user_id`);

CREATE INDEX `read_record_tag_read_record_id_foreign` ON `read_record_tag` (`read_record_id`);

CREATE INDEX `read_record_tag_tag_id_foreign` ON `read_record_tag` (`tag_id`);

CREATE INDEX `read_records_picture_book_id_foreign` ON `read_records` (`picture_book_id`);

CREATE INDEX `read_records_family_id_foreign` ON `read_records` (`family_id`);

CREATE INDEX `read_records_user_id_foreign` ON `read_records` (`user_id`);

CREATE UNIQUE INDEX `tags_name_unique` ON `tags` (`name`);

CREATE UNIQUE INDEX `users_name_unique` ON `users` (`name`);

CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`, `deleted_at`);

CREATE INDEX `users_family_id_foreign` ON `users` (`family_id`);

ALTER TABLE `child_read_record` ADD CONSTRAINT `child_read_record_child_id_foreign` FOREIGN KEY (`child_id`) REFERENCES `children` (`id`) ON DELETE CASCADE;

ALTER TABLE `child_read_record` ADD CONSTRAINT `child_read_record_read_record_id_foreign` FOREIGN KEY (`read_record_id`) REFERENCES `read_records` (`id`) ON DELETE CASCADE;

ALTER TABLE `children` ADD CONSTRAINT `children_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`);

ALTER TABLE `follows` ADD CONSTRAINT `follows_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`) ON DELETE CASCADE;

ALTER TABLE `follows` ADD CONSTRAINT `follows_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;

ALTER TABLE `invites` ADD CONSTRAINT `invites_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`);

ALTER TABLE `likes` ADD CONSTRAINT `likes_picture_book_id_foreign` FOREIGN KEY (`picture_book_id`) REFERENCES `picture_books` (`id`) ON DELETE CASCADE;

ALTER TABLE `likes` ADD CONSTRAINT `likes_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;

ALTER TABLE `picture_books` ADD CONSTRAINT `picture_books_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`);

ALTER TABLE `picture_books` ADD CONSTRAINT `picture_books_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`);

ALTER TABLE `read_record_tag` ADD CONSTRAINT `read_record_tag_read_record_id_foreign` FOREIGN KEY (`read_record_id`) REFERENCES `read_records` (`id`) ON DELETE CASCADE;

ALTER TABLE `read_record_tag` ADD CONSTRAINT `read_record_tag_tag_id_foreign` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE;

ALTER TABLE `read_records` ADD CONSTRAINT `read_records_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`) ON DELETE CASCADE;

ALTER TABLE `read_records` ADD CONSTRAINT `read_records_picture_book_id_foreign` FOREIGN KEY (`picture_book_id`) REFERENCES `picture_books` (`id`) ON DELETE CASCADE;

ALTER TABLE `read_records` ADD CONSTRAINT `read_records_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;

ALTER TABLE `users` ADD CONSTRAINT `users_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`);


1-3. 感想

  • ER図のデザインは、シンプルでかっこよくとても見やすいと思いました。
  • 図の作りやすさは SQLダンプファイル を用意して、export するだけなのでとても楽です。
  • ER図 から DDL が生成できることも便利だと思います。
  • DBML(dbdiagram.io の記法)で記述する場合は、記法を把握する学習コストはありますが、難しくはなさそうな印象です。
  • VSCode拡張機能にはなかったのと、GitHubにサポートされていない記法のようですので、 dbdiagram.io の画面上で基本的に作業することになります。
  • チームでの利用(共同での編集)は有料なので、無料では export したファイルを共有する使い方かなと思います。



2. DBeaver

DBeaver はデータベース管理ツールです。

dbeaver.com

github.com

さまざまなデータベースに対応していて、かなり多機能なようです。

有料版と無料版があり、無料版でも「ER図の自動生成」は使えました。

今回は試してないのですが、ER図からDDLを生成することもできるようです。

2-1. 始める

DBeaver をダウンロードします。

dbeaver.io

2-2. 使う

DBeaver アプリを開いて、データベースに接続すれば、ER図を表示することができます。

① データベースの追加(MySQL接続)

DBeaver アプリを開いて、データベースと接続します。

データベースを選択して、

必要なドライバをダウンロードして、

接続します。

② ER図 の表示

あとは左サイドバーでデータベースを選択して、「ER図」タブを開くだけです。

2-3. 感想

  • ER図のデザインはとても見やすいと思います。エンティティ(テーブル)の位置とリレーションシップ(線)の重なりの少なさが絶妙で、手作業での調整がいらないと感じました。主キーが右側で、外部キーが左側に統一されて表示されていることで見やすいのかなと思います。
  • 今回試したいのはER図を自動生成したいという一点でしたが、データベース管理ツールとしては、いろんなデータベースに対応していて、多機能ということなので、使いこなせたらとても便利なんだと思います。



3. A5:SQL Mk-2(A5M2)

Qiita記事とはてなブックマークでのコメントでは、 A5M2 を推す声が多かったと思います。

A5:SQL Mk-2は複雑化するデータベース開発を支援するために開発されたフリーのSQLクライアントです。

高機能かつ軽量で、使い方が分かりやすいことを目標に開発されています。

SQLを実行したり、テーブルを編集するほかに、SQLの実行計画を取得したり、ER図を作成したりすることが出来ます。

a5m2.mmatsubara.com

3-1. 始める

少し長くなるため、A5M2A5:SQL Mk-2)を macOS で起動させるまでの手順をこちらの記事にまとめました。

qiita.com


3-2. 使う

① データベースの追加(MySQL接続)

② リバースER図生成

DDLの生成(ER図からDDLを生成)

① データベースの追加(MySQL接続)

A5M2 を起動します。

レジストリ」を押すと、データベースの接続に進みます。

Webアプリ(ポートフォリオ)のデータベースと接続してみます。

② ER図 の生成

データベースに作成されている テーブル から、 ER図 をリバース生成してみます。

ツールバー「データベース」→「ER図」→「ER図のリバース生成」を押します。

テーブルを選択して、

「リバースER図生成」を押します。

エンティティ(テーブル)の位置関係は手作業で位置を変更したものがこちらのER図です。

DDLの生成(ER図からDDLを生成)

続いて、 ER図 から DDL を生成してみます。

ツールバー「ER図」→「DDLを作成する」を押します。

RDBMS種類などを選択し、「DDL生成」を押します。

DDLが生成されました。

生成された DDL

-- Project Name : noname
-- Date/Time    : 2022/08/08 23:24:19
-- Author       : crossover
-- RDBMS Type   : MySQL
-- Application  : A5:SQL Mk-2

/*
  << 注意!! >>
  BackupToTempTable, RestoreFromTempTable疑似命令が付加されています。
  これにより、drop table, create table 後もデータが残ります。
  この機能は一時的に $$TableName のような一時テーブルを作成します。
  この機能は A5:SQL Mk-2でのみ有効であることに注意してください。
*/

-- child_read_record
--* RestoreFromTempTable
create table child_read_record (
  id bigint unsigned auto_increment not null comment 'id'
  , read_record_id bigint unsigned not null comment 'read_record_id'
  , child_id bigint unsigned not null comment 'child_id'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint child_read_record_PKC primary key (id)
) comment 'child_read_record' ;

create index child_read_record_read_record_id_foreign
  on child_read_record(read_record_id);

create index child_read_record_child_id_foreign
  on child_read_record(child_id);

-- children
--* RestoreFromTempTable
create table children (
  id bigint unsigned auto_increment not null comment 'id'
  , family_id bigint unsigned not null comment 'family_id'
  , name varchar(100) comment 'name'
  , gender_code int comment 'gender_code'
  , birthday date comment 'birthday'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint children_PKC primary key (id)
) comment 'children' ;

create index children_family_id_foreign
  on children(family_id);

-- contacts
--* RestoreFromTempTable
create table contacts (
  id bigint unsigned auto_increment not null comment 'id'
  , email varchar(255) not null comment 'email'
  , nickname varchar(255) not null comment 'nickname'
  , name varchar(255) comment 'name'
  , title varchar(255) comment 'title'
  , body varchar(255) not null comment 'body'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint contacts_PKC primary key (id)
) comment 'contacts' ;

-- failed_jobs
--* RestoreFromTempTable
create table failed_jobs (
  id bigint unsigned auto_increment not null comment 'id'
  , connection text not null comment 'connection'
  , queue text not null comment 'queue'
  , payload longtext not null comment 'payload'
  , exception longtext not null comment 'exception'
  , failed_at timestamp default CURRENT_TIMESTAMP not null comment 'failed_at'
  , constraint failed_jobs_PKC primary key (id)
) comment 'failed_jobs' ;

-- families
--* RestoreFromTempTable
create table families (
  id bigint unsigned auto_increment not null comment 'id'
  , name varchar(100) not null comment 'name'
  , nickname varchar(255) comment 'nickname'
  , introduction varchar(255) comment 'introduction'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint families_PKC primary key (id)
) comment 'families' ;

alter table families add unique families_name_unique (name) ;

-- follows
--* RestoreFromTempTable
create table follows (
  id bigint unsigned auto_increment not null comment 'id'
  , user_id bigint unsigned not null comment 'user_id'
  , family_id bigint unsigned not null comment 'family_id'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint follows_PKC primary key (id)
) comment 'follows' ;

create index follows_user_id_foreign
  on follows(user_id);

create index follows_family_id_foreign
  on follows(family_id);

-- invites
--* RestoreFromTempTable
create table invites (
  id bigint unsigned auto_increment not null comment 'id'
  , family_id bigint unsigned not null comment 'family_id'
  , email varchar(255) not null comment 'email'
  , token varchar(16) not null comment 'token'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint invites_PKC primary key (id)
) comment 'invites' ;

alter table invites add unique invites_token_unique (token) ;

create index invites_family_id_foreign
  on invites(family_id);

-- likes
--* RestoreFromTempTable
create table likes (
  id bigint unsigned auto_increment not null comment 'id'
  , user_id bigint unsigned not null comment 'user_id'
  , picture_book_id bigint unsigned not null comment 'picture_book_id'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint likes_PKC primary key (id)
) comment 'likes' ;

create index likes_user_id_foreign
  on likes(user_id);

create index likes_picture_book_id_foreign
  on likes(picture_book_id);

-- migrations
--* RestoreFromTempTable
create table migrations (
  id int unsigned auto_increment not null comment 'id'
  , migration varchar(255) not null comment 'migration'
  , batch int not null comment 'batch'
  , constraint migrations_PKC primary key (id)
) comment 'migrations' ;

-- password_resets
--* RestoreFromTempTable
create table password_resets (
  email varchar(255) not null comment 'email'
  , token varchar(255) not null comment 'token'
  , created_at timestamp default null comment 'created_at'
) comment 'password_resets' ;

create index password_resets_email_index
  on password_resets(email);

-- picture_books
--* RestoreFromTempTable
create table picture_books (
  id bigint unsigned auto_increment not null comment 'id'
  , family_id bigint unsigned not null comment 'family_id'
  , user_id bigint unsigned not null comment 'user_id'
  , google_books_id varchar(100) not null comment 'google_books_id'
  , isbn_13 varchar(100) comment 'isbn_13'
  , title varchar(255) not null comment 'title'
  , authors varchar(255) comment 'authors'
  , published_date varchar(100) comment 'published_date'
  , description varchar(1000) comment 'description'
  , thumbnail_url varchar(1000) comment 'thumbnail_url'
  , five_star_rating int not null comment 'five_star_rating'
  , read_status int not null comment 'read_status'
  , review varchar(1000) comment 'review'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint picture_books_PKC primary key (id)
) comment 'picture_books' ;

create index picture_books_family_id_foreign
  on picture_books(family_id);

create index picture_books_user_id_foreign
  on picture_books(user_id);

-- read_record_tag
--* RestoreFromTempTable
create table read_record_tag (
  id bigint unsigned auto_increment not null comment 'id'
  , read_record_id bigint unsigned not null comment 'read_record_id'
  , tag_id bigint unsigned not null comment 'tag_id'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint read_record_tag_PKC primary key (id)
) comment 'read_record_tag' ;

create index read_record_tag_read_record_id_foreign
  on read_record_tag(read_record_id);

create index read_record_tag_tag_id_foreign
  on read_record_tag(tag_id);

-- read_records
--* RestoreFromTempTable
create table read_records (
  id bigint unsigned auto_increment not null comment 'id'
  , picture_book_id bigint unsigned not null comment 'picture_book_id'
  , family_id bigint unsigned not null comment 'family_id'
  , user_id bigint unsigned not null comment 'user_id'
  , memo varchar(1000) comment 'memo'
  , read_date date not null comment 'read_date'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint read_records_PKC primary key (id)
) comment 'read_records' ;

create index read_records_picture_book_id_foreign
  on read_records(picture_book_id);

create index read_records_family_id_foreign
  on read_records(family_id);

create index read_records_user_id_foreign
  on read_records(user_id);

-- tags
--* RestoreFromTempTable
create table tags (
  id bigint unsigned auto_increment not null comment 'id'
  , name varchar(255) not null comment 'name'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , constraint tags_PKC primary key (id)
) comment 'tags' ;

alter table tags add unique tags_name_unique (name) ;

-- users
--* RestoreFromTempTable
create table users (
  id bigint unsigned auto_increment not null comment 'id'
  , family_id bigint unsigned not null comment 'family_id'
  , name varchar(255) not null comment 'name'
  , nickname varchar(255) comment 'nickname'
  , email varchar(255) not null comment 'email'
  , email_verified_at timestamp default null comment 'email_verified_at'
  , password varchar(255) comment 'password'
  , remember_token varchar(100) comment 'remember_token'
  , icon_path varchar(255) comment 'icon_path'
  , relation varchar(100) comment 'relation'
  , created_at timestamp default null comment 'created_at'
  , updated_at timestamp default null comment 'updated_at'
  , deleted_at timestamp default null comment 'deleted_at'
  , constraint users_PKC primary key (id)
) comment 'users' ;

alter table users add unique users_name_unique (name) ;

alter table users add unique users_email_unique (email,deleted_at) ;

create index users_family_id_foreign
  on users(family_id);

3-3. 感想

  • A5M2 の GUI や ER図 の見た目は他の2つのツールに比べて質素ではありますが軽量で、テーブルからER図は自動生成できました。
  • また、ER図からそのとおりにテーブルを作成するためのDDLを生成することもでき、とても便利です。
  • 開発を開始してから25年経過するらしいですが(すごい…)、メンテナンスもされていて現役のご様子です。

おわりに

今回、Qiitaに投稿した記事を多くの方に見ていただき、ツールをご教示いただくなどして、とてもありがたい気持ちでした。

いただいた有用な情報をしっかりとインプットしたいという思いで、今回の各ツールを触ってみましたが、ER図の作成はこんなに簡単にできるのか…知ってたらあのとき楽できたな…と思ったりしました。

経験不足で知らないことは仕方がないので、今後も、(信用できそうな)人からアドバイスいただいたことは積極的に試していきたいと思います。

今回の記事は以上です!ありがとうございました。



モチベーションは勝手に湧いてくる、というようなツイートをしたものの、ツイートやブログ投稿での発信などは、反応もらってモチベーション保たれる要素にもなってるはずなので、工夫の一つかもしれません。

SES派遣中でも、社内のメンターがついてくれるスマレジ・テックファームの応募はこちらです。

corp.smaregi.jp