🙌

📄 データベース(DB)の基本事項 初学者インターン生がわかりやすくまとめてみた

に公開

📄 データベース(DB)の基本

🎯<テーブルとは?>

テーブルとは、データを行(レコード)と列(カラム)で構成された形式で保存する、データベースの基本単位のこと。Excelのシートみたいな感じ。

  • レコード(行):1行の情報 (例:1件の伝達予算)
  • カラム(列):情報の項目 (例:ステータス、日付、送信元)

🗂 社内のとあるプロジェクトで使われているテーブル一覧

テーブル名 説明
users 管理者などのログインユーザー情報
companies 自社の会社情報・担当者情報など
templetes 送信するメッセージのテンプレート定義
history 実際に送信された履歴(どの宛先にいつ送られたか)
recipients 送信対象の会社やURLなどの情報
schedules 実際の送信スケジュール(いつ・誰に・どのテンプレートを)

📎参考:
https://zenn.dev/arisa1115/articles/da92685dfc4ebd


🔑<主キーと外部キー>

  • 主キー (Primary Key):そのテーブルの中で「誰か」を一意に識別するための番号
  • 外部キー (Foreign Key):他のテーブルにある「誰か」を参照するための番号

📎参考:
https://zenn.dev/sudoukky/articles/598c85b1123bfe


🎯 <主キーとは>

主キー (Primary Key):そのテーブルの中で「一件だけを特定するためのID」

主キーの利点:

  • データベースにあるデータをわかりやすくするため
  • データベースのテーブルにあるデータの「被り」を防ぐため
  • 特定のデータだけを更新・削除・取得できるため

例❌(IDなし)

トレーナー名
サトシ
エモバ
サトシ

→ この状態だと「どのサトシ?」であるのかがわからない

例✅ (IDあり)

ID    トレーナー名
001   サトシ
002   エモバ
003   サトシ

→ 「IDが001のサトシを更新する」と言えるようになる

<primary_key(主キー) の条件>

なぜこの条件が必要なのか:

  • 主キーが null(空)でないこと

    • 値が空欄だと「どのデータか」を判別できないから。
  • 主キーが一意であること(重複しない)

    • 同じIDが2つあると、どちらのデータを使えばいいのか迷ってしまう。

📎参考:
https://zenn.dev/nameless_sn/articles/primary_key_tutorial


🛠 <社内でのプロジェクトにおける主キーの使われ方>

某プロジェクト では、各テーブルに主キーとして id カラムが定義されており、それぞれのデータを一意に識別できるようになっています。

<schedules テーブル>

id: text("id").primaryKey().$defaultFn(uuidv7)
  • スケジュールの登録・編集・削除でこのIDを用いて特定のスケジュールを操作

<recipients テーブル>

id: text("id").primaryKey().$defaultFn(uuidv7)
  • 宛先の企業や送信先URLなどの情報を一意に識別

<templetes テーブル>

id: text("id").primaryKey().$defaultFn(uuidv7)
  • テンプレートの選択・編集・削除でこのIDが使われる

🆔<idカラムって何?>

多くのテーブルには id という名前のカラムがあります。これは通常、主キー(primary key)として使われ、各レコードを一意に識別するための番号や文字列です。

たとえば:

id: text("id").primaryKey().$defaultFn(uuidv7)

このように定義されていれば、

  • 重複しないユニークなID(UUID)が自動で発行される
  • データの更新や削除が確実に行えるようになる

🧪 <社内プロジェクトのコード例>

export const schedules = sqliteTable("schedules", {
  id: text("id").primaryKey().$defaultFn(uuidv7),// ← 主キーの定義👍👍
  recipientId: text("recipient_id")
    .notNull()
    .references(() => recipients.id),
  status: text("status").default("PENDING"),
  templateId: text("template_id")
    .notNull()
    .references(() => templates.id),
  senderId: text("sender_id")
    .notNull()
    .references(() => companies.id),
  scheduledAt: text("scheduled_at")
    .notNull()
    .default(sql`CURRENT_TIMESTAMP`),
  completedAt: text("completed_at").default(sql`CURRENT_TIMESTAMP`),
  createdAt: text("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
  updatedAt: text("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
  isDeleted: integer("is_deleted", { mode: "boolean" })
    .notNull()
    .default(false),
});

このコードの👍👍の部分でid を主キーにしますよーっていうのを決めている。


🔗<外部キー(Foreignキー)とは>

外部キー (Foreign Key):他のテーブルにある「誰か」を参照するための番号。

→ 表と表を関連付ける関係データベースで、他の表の主キーを参照する。参照される主キーを外部キーという。

外部キーの利点:

  • データの正確さ(整合性) が保たれる
  • リレーションシップ(関係性)を明確に定義できる
  • 削除や更新時の動作を制御できる

例:trainers テーブル

ID   トレーナー名
001  サトシ
002  エモバ
003  タダシ

例:pokemon テーブル

ポケモンID  名前        ID
A001         ピカチュウ  001
A002         ポッチャマ  002
A003         フシギダネ  003

→ pokemons テーブルの「ID」は trainers テーブルの「ID(主キー)」を参照している、つまり外部キー。


⚙️ <外部キーの条件>

  • 参照先の主キーが存在していること
  • 参照先のデータ型と一致していること
  • 参照整合性が保たれること(DELETE/UPDATEの動作制御)

📎参考:
https://zenn.dev/sudoukky/articles/598c85b1123bfe


社内プロジェクトにおける外部キーの使われ方

schedules テーブル
カラム名 説明 参照先
senderId スケジュールの送信元の会社ID organization_information.id
tempplatedId 使用するテンプレートのID message_templates.id
recipientId 宛先の送信ターゲットID send_targets.id
history テーブル
カラム名 説明 参照先
recipientId 宛先の会社 send_targets.id
senderId 送信元の会社 organization_information.id
templetedId 使用したテンプレート message_templates.id
scheduleId 実行スケジュールID send_schedules.id (任意)

📝 scheduledDatetime, completedDatetime, createdAt, updatedAt などは外部キーではない。


📌<クエリ(Query)とは?>

  • クエリとは、データベースに対して出す命令や質問のこと。

    • 例:「このIDのデータを取得して」「このデータを更新して」

🧩 <CRUD操作とは?>

CRUDとは、データベース操作の基本4つの動作を表す略語:

  • Create(作成)
  • Read(取得)
  • Update(更新)
  • Delete(削除)

🛠<基本的なCRUD操作>

種類 意味 drizzleの使用例 SQLでの書き方
Create 作成 insert().values() INSERT INTO テーブル名 (...) VALUES (...);
Read 取得 select().from() SELECT * FROM テーブル名;
Update 更新 update().set().where() UPDATE テーブル名 SET カラム=値 WHERE 条件;
Delete 削除 delete().where() DELETE FROM テーブル名 WHERE 条件;

🛠<社内のプロジェクトでの使われ方>

Create (INSERT)

await db.insert(sendSchedules).values({...}).returning();
  • 新しいレコードを追加
  • SQL:
INSERT INTO send_schedules (...) VALUES (...);

Read (SELECT)

await db.select().from(schedules).where(eq(schedules.id, scheduleId)).all();
  • 特定IDのレコードを取得
  • SQL:
SELECT * FROM schedules WHERE id = 'abc123';

Update (UPDATE)

await db.update(schedules)
  .set(updateFields)
  .where(eq(schedules.id, scheduleId));
  • id が一致するレコードを更新
  • SQL:
UPDATE schedules SET ... WHERE id = 'abc123';

Delete (DELETE)

await db.delete(schedules).where(eq(schedules.id, scheduleId));
  • 定期削除(過去日時を判定してから)
  • SQL:
DELETE FROM schedules WHERE id = 'abc123';

🔎<WHERE文(条件指定)>

.where(eq(schedules.id, scheduleId))
  • DBに「このIDのデータだけ対象にして」と伝える
  • SQLの WHERE id = 'abc123' に相当

Emoba Tech Blog

Discussion