📄 データベース(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'
に相当
Discussion