データベースと SQL 基礎
表形式でデータを管理する考え方を学び、SELECT・WHERE・JOIN・集計という SQL の基本操作を実際に読み書きできるようになる。
- リレーショナルモデルにおけるテーブル・行・列・主キーの役割を説明できる
- SELECT / WHERE / ORDER BY / GROUP BY を組み合わせた問い合わせを書ける
- 正規化の目的と、JOIN による複数テーブルの結合を説明できる
リレーショナルモデル——表で世界を表す
リレーショナルデータベース(RDB)は、データを行(レコード)と列(カラム)からなるテーブルで管理します。「学生テーブル」と「受講テーブル」を分け、必要なときに結合するのが基本設計です。行を一意に識別する候補キーから選んだものが主キー(primary key)で、複数列でも構成できます。外部キー(foreign key)は主キーや一意制約のあるキーを参照する列または列の組です。同じテーブルを参照する場合もあります。
| 用語 | 意味 | 例 |
|---|---|---|
| テーブル(関係) | 同じ種類のデータの集合 | students |
| 行(タプル) | 1件分のデータ | 「1番, 田中, 2年」 |
| 列(属性) | データの項目 | id, name, grade |
| 主キー | 行を一意に決める列または列の組(重複・NULL 禁止) | id |
| 外部キー | 主キーや一意制約のあるキーを参照する列または列の組 | student_id |
SQL——データに語りかける言葉
SQL(Structured Query Language)はデータベースへの命令文です。読み取りは SELECT … FROM … WHERE が基本形で、並べ替えは ORDER BY、集計は GROUP BY と COUNT・AVG などの集約関数を使います。宣言型言語であることが特徴で、「どう取得するか」ではなく「何がほしいか」を書くと、実行計画はデータベース側が最適化します。
上は句を書く順序です。基本的な問い合わせの論理的な処理は FROM / JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY と考えます(実際の実行計画とは別)。WHERE は集計前の行、HAVING は集計後のグループを絞ります。GROUP BY がなくても COUNT(*) や AVG(point) で全体を1グループとして集計できます。
students(id, name, grade) と scores(student_id, subject, point) から「2 年生の科目別平均点」を求める SQL を書け。
解答・解説
**SELECT s.subject, AVG(s.point) FROM scores s JOIN students st ON st.id = s.student_id WHERE st.grade = 2 GROUP BY s.subject;**(WHERE で行を絞り、GROUP BY で科目ごとにまとめて平均を取る)
🔍 JOIN の結果の行数——なぜ結合キーで行数が決まるのか
- Step 1: 素朴な組み合わせ(クロス結合)
行と 行のテーブルを無条件に組み合わせると全ペア 行になります。
- Step 2: 条件で絞り込む(内部結合)
内部結合は「キーが一致するペアだけ」を残します。各行ごとの一致数(度数)の総和が結果の行数です。
- Step 3: 主キー結合なら高々 m 行
主キーは重複しないので、A の各行に対する一致は最大 1 個。行数が爆発しないのが主キー設計の効能です。
- Step 4: 実務上の教訓
単純な二重ループ結合では全ペアを比較します。B木索引を使って各行から探す方式は、一致結果 k 行の出力も含めて目安 O(m log n + k)。索引なしでも等値結合ではハッシュ結合を使い、適切な条件下で期待 O(m + n + k) にできるので、索引の有無だけで速度は決まりません。
正規化——重複を排除する設計
1枚の巨大な表にすべてを書き込むと、同じ情報が繰り返され、更新時の矛盾(更新異常)が起きます。正規化は関数従属性(X の値が決まると Y の値も決まる関係 X → Y)などを調べ、冗長性を抑える設計です。単に分割すればよいのではなく、結合で元の情報を正しく復元できることも確認します。主キーだけでなく、行を一意に識別できる最小の列の組である候補キーすべてを考えます。
- 第1正規形(1NF): 1つのセルに1つの値。繰り返し列を禁止
- 第2正規形(2NF): 1NF を満たし、どの候補キーにも含まれない属性が、候補キーの一部分だけに依存しない
- 第3正規形(3NF): 非自明な関数従属性 X → A ごとに、X がスーパーキー(行を一意に決める列の組)であるか、A がいずれかの候補キーに含まれる。典型的には非キー属性への推移的な依存を分離する
| 操作系 SQL | 役割 | 例 |
|---|---|---|
| SELECT | 読み取り | SELECT * FROM t WHERE id = 1 |
| INSERT | 追加 | INSERT INTO t VALUES (...); |
| UPDATE | 更新 | UPDATE t SET name = 'Suzuki' WHERE id = 2 |
| DELETE | 削除 | DELETE FROM t WHERE id = 2 |
scores(subject, point) から point が 80 以上の行だけを取り出す SQL を書け。
ヒント
SELECT … FROM … WHERE。
解答・解説
**SELECT * FROM scores WHERE point >= 80;**
students テーブルの行数を数える SQL を書け。
解答・解説
**SELECT COUNT(*) FROM students;**
「受講履歴」を students に埋め込むと更新異常が起きる理由を述べよ。
ヒント
同じ学生名が何行も繰り返される状況を想像する。
解答・解説
氏名などの属性が受講件数だけ繰り返し保存され、変更時に全行を直さず矛盾が残る(更新異常)。学生情報と受講記録を**テーブル分割(正規化)+ 外部キー**で分離すれば防げる
1000 行 × 1000 行のテーブルを、すべてのペアを調べる単純な二重ループで JOIN する場合、結合条件の評価回数はいくつか。
解答・解説
回。これは指定した方式の回数であり、索引がない JOIN が必ずこの方式になるわけではない。ハッシュ結合など別の実行計画もある。
問1. テーブルの行を一意に特定する列はどれか。
問2. 科目ごとなど、値が同じ行をグループに分けて集計する句はどれか。
問3. 候補キーが学生IDだけの表で、学生ID → 学科ID → 学科名という依存がある。第3正規形にする典型的な対応は?