データベースとSQL
RDB、3層スキーマ、E-R図、正規化、SQL、トランザクション、バックアップの基礎を整理する
このページの役割
このページの役割
このページは、企業システムの「データの保管庫」となるデータベースを理解するページです。営業が受注を記録し、在庫を更新し、決算データを集計する─これらすべてがデータベースの上で動いています。表の設計から、データ取り出しの命令、そして障害時の復旧まで、一連の実務を支える考え方をていねいに解説します。
学習のポイント
- まず体験する:「顧客情報が複数の受注に繰り返している」という問題から、表を分割する必要性を感じる
- キーで「誰が誰とつながるか」を追う:主キーと外部キーの対応を見ると、複雑な表の関係も一本の流れとして理解できる
- 正規化は「整理」:データの重複を見つけ、表を分割する思考プロセスを身につける
- SQLは「日本語に訳す」:実行順序(FROM → WHERE → GROUP BY)を常に意識しながら読む
- トランザクションは「複数操作をセット」:銀行振込の例で、途中で止まると困る理由を理解する
- バックアップは「取得と復旧」のセット:取得だけでは意味がないことを押さえる
試験で何が問われるか
- 主キーと外部キー:「行を識別するか」「表をつなぐか」の違いを言えるか。複合キーが現れても対応できるか
- 正規化の段階:非正規形、第1〜第3正規形の境界がどこか、各段階で排除するものが何か
- 更新異常:なぜ「顧客名を複数の受注レコードに持つ」と困るのか。その理由を説明できるか
- SQL の読み取り:SELECT文の記述順序と実行順序の違いを理解し、WHERE と HAVING、GROUP BY と集約関数の関係を見分けられるか
- JOIN の種類:LEFT OUTER JOIN でなぜ「受注がない顧客も表示」されるのか、その仕組みが言えるか
- ACID 特性:トランザクションの4つの特性が実装上どう保証されるか(コミット、ロック、ログなど)
- バックアップとリカバリ:フル、差分、増分の使い分けと、復旧の手順(ロールバック、ロールフォワード)
データベースの基本概念
データベースとは何か
データベースは、企業の経営活動に必要な情報を、体系的に保存・管理・取り出す 仕組みです。
たとえば、商品を売った時を想像してください。「誰に」「何を」「いくらで」「いつ」売ったかが、あちこちに散らばっていると、後で「この顧客の売上合計は?」と聞かれた時に、すべてを手作業で足す羽目になります。データベースがあれば、その質問に秒単位で答えられます。
データベースがもたらす効果は三つです:
- データの保持:記録を失わない。停電やシステム障害があってもデータは残る
- データの整合性:同じ情報が二度と矛盾しない。顧客の住所を変えたら、それが一度だけ変わる
- データの取り出し:必要な情報を必要な形で、高速に引き出せる
これらを実現するために、データベースには 構造 と ルール があります。
データベースの種類
データベースにはいくつかの形式があります。試験では リレーショナルデータベース(RDB) が主役ですが、他の種類も背景として理解すると理解が深まります。
| 種類 | 構造 | 特徴 | 用途 |
|---|---|---|---|
| RDB | 行と列の表 | キーで表をつなぐ、ACID特性対応 | 会計、受発注、顧客管理 |
| キーバリュー型 | キーと値のペア | 高速アクセス、メモリ中心 | キャッシュ、セッション管理 |
| ドキュメント型 | JSON/XML形式 | 柔軟なスキーマ、階層構造 | ログ管理、ユーザー設定 |
| カラムナー型 | 列単位での圧縮保存 | 分析・集計が高速 | ビッグデータ分析 |
| グラフ型 | ノードとエッジのグラフ | 関連性の検索が効率的 | SNS、推奨エンジン |
RDB が「表」という最も単純な形式を使いながら、なぜ 50年以上、ほぼすべての企業システムで使われ続けているのか。それは、ルール(正規化)に従うと、データの矛盾が自動的に防げる からです。試験でも、この RDB の構造と仕組みが重点です。
リレーショナルデータベース(RDB)─なぜ「表」か
RDB は、関係(relation)を 表 で表す仕組みです。「関係」とは聞き慣れないかもしれませんが、これは単に「表」を意味します。「顧客」と「受注」の関係を、別々の表で管理し、キーでつなぐ。これが RDB の核です。
なぜ「1 つの大きな表に全てを詰め込まない」のでしょう?答えは、同じ情報が何度も繰り返される問題 を防ぐためです。
例えば、「顧客」と「受注」を 1 つの表に詰め込むと:
顧客ID | 顧客名 | 受注ID | 商品
101 | A社 | R001, R002 | P001, P002こうなると、A社の住所を変えた時に、A社のすべての受注レコードを探して更新しなければなりません。1 つ忘れると、データが矛盾します(更新異常)。
逆に表を分ければ:
【顧客表】
顧客ID | 顧客名
101 | A社
【受注表】
受注ID | 顧客ID | 商品
R001 | 101 | P001
R002 | 101 | P002A社の情報は 1 ヶ所だけなので、変更は一度で済み、矛盾が生まれません。
RDB の基本
表(テーブル)は、行(レコード)と列(フィールド)の組み合わせです。各行は一意に識別され、列は意味を持つデータ項目です。複数の表を一つのデータベースにまとめ、キー で結び付けることで、データの重複を最小化し、矛盾を防ぎます。
3 層スキーマとデータ独立性
スキーマとは何か
スキーマ(schema)は、「設計図」「構造の約束」という意味です。データベースの設計図は、3 つの階層に分かれています。この 3 層構造により、変更の影響を最小限に抑える「データ独立性」が実現されます。
3 層の構成と意味
| 層 | 役割 | 対象 | 具体例 |
|---|---|---|---|
| 外部スキーマ | 利用者が見えるビュー | アプリケーション、ユーザー | 営業スタッフは顧客名と売上だけ見て、給与情報は見えない |
| 概念スキーマ | 全体の論理構造 | エンティティ、属性、リレーションシップ | 「顧客表」「受注表」「商品表」の定義と、それらの関連 |
| 内部スキーマ | 物理的な保存構造 | インデックス、ファイル、磁盤配置 | 「顧客ID にインデックスを張る」「このファイルを SSD に置く」 |
データ独立性の実務的意味
スキーマが 3 層に分かれていると、何が得られるでしょう。それは、変更の波紋を限定する ことです。
例:営業管理システムを新しく作る
古い時代:営業スタッフが見ていた帳票形式(「顧客No、顧客名、売上」)が、データベース層の表構造そのものだった。営業管理システムを新しく作る時、新しい形式に対応させようとすると、データベースの表そのものまで変えなければならず、既存システムが全部壊れてしまった。
3 層スキーマなら:
- 外部スキーマ(営業管理システムが見る形) → 新しいシステム用に書き直す
- 概念スキーマ → 変わらない(「顧客」と「受注」の関係は変わらないから)
- 内部スキーマ → 変わらない(データを磁盤のどこに置くかは、業務ロジックに影響しない)
つまり、「新しい営業管理システムを追加」するだけで、既存の他のシステムには一切影響がない。これが データ独立性 です。
データ独立性の定義
- 論理的独立性:外部スキーマと概念スキーマが分離。概念スキーマの変更がアプリケーション層(外部スキーマ)に影響しない
- 物理的独立性:概念スキーマと内部スキーマが分離。データベースファイルの配置や圧縮方式の変更が、上位のアプリケーションに影響しない
この 2 つが実現されると、「昨年作ったシステムを新しい要件に対応させる」が、実装コストを最小にできます。
E-R図(エンティティ・リレーションシップ図)
E-R図の役割
データベースの設計は、いきなり表を作ることから始まりません。まず、「どんなもの(エンティティ)があって、どう関連するのか」を図で整理 します。この図が E-R 図です。
プログラマーが実装を始める前に、要件を整理する段階で「顧客」と「受注」の関係は「1人の顧客が複数の受注を出す(1:N)」ことを確認します。この確認をせずに実装を始めると、後で「やはり 1 人の顧客が複数の部門の受注を同時に進められるようにしたい」という要件変更に対応できず、全部修正することになります。
主要な要素
| 要素 | 説明 | 図記号 | 例 |
|---|---|---|---|
| エンティティ | 実体、「ものごと」 | 四角形 | 顧客、商品、受注 |
| 属性 | エンティティが持つ性質、データ項目 | 楕円 | 顧客ID、顧客名、住所 |
| リレーションシップ | エンティティ間の関連、つながり | 菱形 | 「顧客が受注を出す」 |
| カーディナリティ | 関連の強さ(何対何か) | 線の端の記号 | 1 個の顧客が複数の受注 |
カーディナリティ(リレーションシップの種類)
データベース設計で最も大事な判断の一つが「この 2 つのエンティティの関係は何対何か」です。
| 型 | 表記 | 説明 | 実例 | RDB での実装 |
|---|---|---|---|---|
| 1:1 | 一対一 | A は B と最大 1 つ結合 | 従業員 1 人 - 社員証 1 枚 | A の表に B の主キーを外部キーとして持つ |
| 1:N | 一対多 | A は複数の B と結合 | 顧客 1 社 - 受注複数件 | B の表に A の主キーを外部キーとして持つ |
| M:N | 多対多 | A と B が相互に複数結合 | 受注 - 商品(1 受注に複数商品、1 商品が複数受注に) | 中間表を作成 |
M:N リレーションシップの処理
ここが E-R 図から RDB の実装への「ギャップ」です。理解しておきましょう。
問題:「受注」と「商品」の関係は何か?
- 1 つの受注には複数の商品が含まれます(例:受注 R001 に「商品 P001」と「商品 P002」)
- 1 つの商品は複数の受注に含まれます(例:商品 P001 は「受注 R001」と「受注 R003」)
つまり M:N(多対多)です。
RDB での実装の困難:表では、1 つのセルに複数の値を入れられません。だから、「受注」表に「商品 P001, P002」と書くことはできません。
解決方法:中間表(関連表)を作ります。
【受注表】
受注ID | 顧客ID
R001 | C001
R002 | C001
【受注明細表】← 中間表
受注ID | 商品ID | 数量
R001 | P001 | 10
R001 | P002 | 5
R002 | P001 | 3
【商品表】
商品ID | 商品名
P001 | パーツA
P002 | パーツB受注明細表により、「受注 R001」と「商品 P001」の関係は、「受注 R001 行」と「受注明細表で受注ID=R001 の行」と「商品 P001 行」をつなぐことで表現できます。
M:N を中間表で実装する理由
RDB は「単一値」の表を前提にしています。M:N を直接表現することはできません。中間表を作ることで、M:N を 2 つの 1:N に分解します。この分解こそが、RDB が単純で堅牢である理由です。
リレーショナルデータベース基本概念
用語の整理
RDB では、「表」という日常的な言葉で、数学的な「関係」を管理します。用語を正確に押さえておくと、技術的な会話がスムーズになります。
| 日本語 | 英語 | 説明 |
|---|---|---|
| 表 | Table | 1 つのエンティティに対応する行・列の集合。顧客表、受注表など |
| 行 | Tuple(数学)/ Record(実務) | 1 個のエンティティ、データ 1 件。顧客 1 社、受注 1 件 |
| 列 | Attribute(数学)/ Field(実務) | 1 つの性質・項目。顧客ID、顧客名、住所など |
| セル | Cell | 1 行と 1 列の交点。具体的な 1 つの値 |
キーの概念と役割
キー(key)は、RDB で最も重要な概念です。「どの行のことを言っているのか特定する」あるいは「どの表とどの表をつなぐのか指定する」ために使われます。
キーの種類
| キーの種類 | 意味 | 制約 | 例 |
|---|---|---|---|
| 主キー(Primary Key, PK) | この行を一意に識別する属性 | 重複不可、NULL不可、1表に最低1個 | 顧客ID、受注ID |
| 候補キー | 主キーになる資格がある属性 | 一意性あり、複数あり得る | 顧客ID、顧客の社会保険番号 |
| 複合キー | 複数の属性の組み合わせで一意 | 属性それぞれには重複があっても、組み合わせは一意 | 受注明細表の(受注ID, 商品ID) |
| 外部キー(Foreign Key, FK) | 別表の主キーを参照する属性 | 参照先表に存在する値のみ | 受注表の顧客ID(顧客表の主キーを参照) |
主キーと外部キーの関係
主キーと外部キーは、RDB の「双子」です。この関係を理解することが、データベース設計と SQL の読み取りの両方の基礎になります。
例:顧客表と受注表
【顧客表】
顧客ID (PK) | 顧客名 | 住所
101 | A社 | 東京都
102 | B社 | 大阪府
【受注表】
受注ID (PK) | 顧客ID (FK) | 売上
R001 | 101 | 100000
R002 | 101 | 50000
R003 | 102 | 80000- 顧客表の顧客ID:主キー。顧客を一意に識別
- 受注表の顧客ID:外部キー。「この受注は顧客表のどの行か」を指す矢印
この関係により、「顧客101(A社)の全受注を取得する」という操作が可能になります。
キーの役割を同じ例で比較
主キー:「個」を識別する
- 顧客101は A社、顧客102は B社。それぞれ異なるから、顧客IDで区別できる
外部キー:「つながり」を表現する
- 受注R001の顧客IDが101 → この受注は顧客101(A社)のもの
- 受注R002の顧客IDも101 → この受注も同じA社のもの
外部キーがあることで、「同じ顧客の複数受注」という関係が自動的に保証される
関係演算(関係代数)
なぜ「関係演算」を学ぶのか
SQL を読む時、実は関係演算の 8 つの基本操作が組み合わさっています。「SELECT WHERE をしたら行が絞られた」というのは、選択演算 を行っているのです。「SELECT で列を指定したら列が減った」というのは、射影演算 です。
この対応を意識すると、複雑な SQL でも「あ、これは選択と射影の組み合わせなんだ」と理解できるようになります。
8 つの基本演算
| 演算 | 記号 | 説明 | 入力 | 出力 | SQL の対応 |
|---|---|---|---|---|---|
| 選択(制限) | σ | 条件を満たす行を抽出 | 1 表 | 行の部分集合 | WHERE 句 |
| 射影 | π | 指定列だけを抽出 | 1 表 | 列の部分集合 | SELECT 句 |
| 結合 | ⊳⊲ | 共通属性で表をつなぐ | 2 表 | つながった 1 表 | JOIN 句 |
| 直積 | × | 全ての組み合わせ | 2 表 | m × n 行の表 | CROSS JOIN |
| 和 | ∪ | 重複を除いて統合 | 2 表(同一スキーマ) | 統合表 | UNION |
| 差 | − | 一方にあり、他方にない行 | 2 表(同一スキーマ) | 差分表 | EXCEPT |
| 積(交差) | ∩ | 両方に含まれる行 | 2 表(同一スキーマ) | 共通部分 | INTERSECT |
| 除算 | ÷ | 「全てのものに対応する」行を抽出 | 2 表 | 除算結果 | (複雑な WHERE で表現) |
関係演算と SQL の対応
SQL の SELECT 文を読む時、「これは何の演算をしているのか」を意識することで、複雑なクエリが単純に見えます。
例1:基本的な SELECT
SELECT 顧客ID, 顧客名
FROM 顧客表
WHERE 売上 > 100000→ 顧客表から(元の表)→ 売上 > 100000 の行を選択(選択演算)→ 顧客ID と顧客名の列だけを射影(射影演算)
例2:JOIN
SELECT 受注表.受注ID, 顧客表.顧客名
FROM 受注表 JOIN 顧客表 ON 受注表.顧客ID = 顧客表.顧客ID→ 受注表と顧客表を結合(結合演算)→ 受注ID と顧客名の列を射影
関係演算を意識する利点
「WHERE は選択」「SELECT は射影」「JOIN は結合」と意識すると、複雑な SQL でも順序立てて理解できます。また、性能最適化時に「この選択は早くできるか」を判断する根拠にもなります。
正規化
正規化とは何か
正規化(normalization)は、データベース設計のプロセスです。目的は一つ:同じ情報が複数の場所に存在することを減らし、更新時の矛盾を防ぐ こと。
なぜこれが必要でしょう。営業管理システムで顧客 A の住所を変えたとします。その顧客の過去の 100 件の受注レコードにも同じ住所が記録されていたら、100 ヶ所すべてを更新しなければなりません。1 つ忘れると、古い住所と新しい住所が混在する矛盾が生まれます。これが 更新異常 です。
正規化は、このような「同じ情報の繰り返し」を見つけて、表を分割することで防ぎます。
正規化の段階と異常の種類
試験では「第 1 正規形から第 3 正規形」と 3 段階覚える傾向がありますが、まず「何が困るのか」を理解することが重要です。
3 つの異常(更新異常、挿入異常、削除異常)
| 異常 | 発生の原因 | 具体例 |
|---|---|---|
| 更新異常 | 同じ情報が複数の行に繰り返される | 顧客 A の住所を 100 件の受注レコードで変更し、1 件忘れる → 古い住所と新しい住所が混在 |
| 挿入異常 | 主キーの一部だけに従属する情報がある | 「部門に属する従業員」の表で、まだ従業員がいない部門を登録できない(従業員IDが NULL では主キーが成立しない) |
| 削除異常 | 行を削除した時、他の情報も失われる | 唯一の受注者が辞めたので受注レコードを削除 → その顧客情報も消える |
正規化の進行
| 段階 | 排除対象 | 具体的な問題 | ビフォー・アフター |
|---|---|---|---|
| 非正規形 | なし(出発点) | 繰り返し項目(1 行に複数値) | 顧客ID, 受注ID(R001, R002), 売上(100, 50) |
| 第1正規形(1NF) | 繰り返し項目 | 同じ情報の繰り返し | 1 行 = 1 受注 へ分割 |
| 第2正規形(2NF) | 部分関数従属 | 主キーの一部だけで決まる情報 | 商品名が商品IDだけで決まる(受注IDは不要) |
| 第3正規形(3NF) | 推移関数従属 | 主キーでない属性同士の依存 | 部門名が部門IDで決まる(従業員IDは不要) |
正規化の本質
正規化は「表を増やすこと」ではなく、「依存関係をはっきりさせること」です。その副作用として表が増えるだけです。
具体例:正規化のステップ
実務で遭遇する例で、段階を追って説明します。「顧客が受注を何度も出す」シナリオです。
出発地点:非正規形
営業管理システムを始めた時、こんな表から出発しました。
【顧客受注表(非正規形)】
顧客ID | 顧客名 | 顧客住所 | 受注ID | 商品ID | 数量
101 | A社 | 東京都 | R001, R002 | P001, P002 | 10, 5
102 | B社 | 大阪府 | R003 | P001 | 3何が問題か:
- 繰り返し項目:「受注ID」「商品ID」「数量」に複数値が入っている(1 行に複数件の受注)
- 同じ情報の繰り返し:顧客 A の情報が 2 行あれば 2 回繰り返される
- 更新異常の危険:A社の住所を変える時、その行の「東京都」だけを「神奈川県」に変えて、本当は 2 行あるのに 1 行だけ更新する危険
第1段階:第1正規形へ(繰り返し項目を排除)
まず、1 行に複数値が入っている部分をばらします。
【受注明細表(第1正規形)】
受注ID | 顧客ID | 顧客名 | 顧客住所 | 商品ID | 数量
R001 | 101 | A社 | 東京都 | P001 | 10
R002 | 101 | A社 | 東京都 | P002 | 5
R003 | 102 | B社 | 大阪府 | P001 | 3改善:繰り返し項目がなくなり、各セルが単一値 ✓
新しい問題:顧客 A の情報(ID、名前、住所)が 2 行に繰り返されている。
第2段階:第2正規形へ(部分関数従属を排除)
「顧客名と顧客住所は、顧客ID だけで決まる。受注ID は不要」に気づきます(部分関数従属)。
表を分割します:
【顧客表】
顧客ID | 顧客名 | 顧客住所
101 | A社 | 東京都
102 | B社 | 大阪府
【受注明細表(第2正規形)】
受注ID | 顧客ID | 商品ID | 数量
R001 | 101 | P001 | 10
R002 | 101 | P002 | 5
R003 | 102 | P001 | 3改善:
- 顧客 A の住所は「顧客表」に 1 ヶ所だけ。変更は 1 ヶ所で済み、更新異常がない ✓
- 受注明細表は「何の受注に、どの商品が何個」かだけ記録
第3段階:第3正規形へ(推移関数従属を排除)
実は、顧客表に「部門ID」があって、「部門ID」には「部門名」が決まっているとします(推移関数従属)。
【不完全な設計】
顧客ID | 顧客名 | 部門ID | 部門名
101 | A社 | D01 | 営業
102 | A社 | D01 | 営業 ← 同じ部門情報が繰り返される「部門」の概念を独立させます:
【部門表】
部門ID | 部門名
D01 | 営業
D02 | 企画
【顧客表(第3正規形)】
顧客ID | 顧客名 | 部門ID
101 | A社 | D01
102 | B社 | D02
【受注明細表】
受注ID | 顧客ID | 商品ID | 数量
R001 | 101 | P001 | 10
R002 | 101 | P002 | 5
R003 | 102 | P001 | 3最終改善:営業部門の名前を「営業」から「営業・企画統合部」に変えても、「部門表」の 1 行を変えるだけ。複数の場所を更新する心配がない ✓
正規化の段階を判定するコツ
- 非正規形か?:1 つのセルに複数値(例:「R001, R002」)が入っているか
- 第1正規形か?:繰り返し項目はないが、主キーの一部だけで決まる属性があるか(例:顧客ID だけで顧客名が決まるのに、受注テーブルに顧客名がある)
- 第2正規形か?:主キー以外の属性間に依存関係があるか(例:部門ID から部門名が決まる)
- 第3正規形?:矛盾がない「正規形」の完成
SQL(Structured Query Language)
SQL とは何か
SQL(Structured Query Language)は、RDB に対する「統一的な問い合わせ言語」です。Oracle、MySQL、PostgreSQL などどの DBMS を使っていても、基本的な SQL の文法は同じです。
試験で「SQL を読みこなせるか」「簡単な SQL を書けるか」は、情報通信技術の中で最も点数に直結する能力の一つです。なぜなら、実務でシステムが「どのような計算をしているのか」の大半は SQL で記述されているから。
SQL の 3 つの領域
SQL は目的別に 3 つに分かれます。試験では DML(SELECT など)が中心ですが、体系的に押さえておくと理解が深まります。
| 領域 | 分類 | 主要な命令 | 役割 | 試験での頻度 |
|---|---|---|---|---|
| DDL | データ定義言語 | CREATE, ALTER, DROP | テーブルやスキーマを定義・変更・削除 | 低(選択肢に出現) |
| DML | データ操作言語 | SELECT, INSERT, UPDATE, DELETE | データを取得・追加・更新・削除 | 高(計算問題の中心) |
| DCL | データ制御言語 | GRANT, REVOKE | アクセス権限を付与・剥奪 | 低(概念問題) |
このページでは DML の SELECT を中心に解説します。SELECT は、データベースから「誰の、どのデータを、どのように取り出すか」を表現する最も重要な命令です。
SELECT 文の処理順序
SQL 書く順番 ≠ 実行順番
これは多くの初学者が躓く点です。SQL を「記述する順番」と「実行される順番」が異なるのです。
【SQL を書く順番】
SELECT 列名
FROM テーブル名
WHERE 条件
GROUP BY グループ列
HAVING グループ条件
ORDER BY ソート列
【実際に実行される順番】
1. FROM -- どのテーブルから読むか
2. WHERE -- 読んだ全行から、条件に合う行だけを残す
3. GROUP BY -- 残った行をグループ化
4. HAVING -- グループの条件で、さらに絞る
5. SELECT -- 必要な列だけを選ぶ(集約関数を計算)
6. ORDER BY -- ソートなぜこの順番か?
RDB が物理的にデータを処理する流れを想像してください。
- FROM:まずテーブルを読みます。メモリに 100万行のデータが乗っていると想像してください。
- WHERE:全 100万行から「売上 > 100000」など条件に合う行だけを残します。1万行に減ったとします。
- GROUP BY:その 1万行を「顧客ID」でグループ化します。100グループになったとします。
- HAVING:グループの条件で絞ります。「各グループの受注件数が 2 件以上」なら、20グループが残ります。
- SELECT:最後に「表示する列」を決めます。元々は 50列あっても、SELECT で 3列だけ指定されていれば 3列だけになります。
- ORDER BY:その 20グループを売上順に並べます。
この流れをイメージできると、複雑な SELECT 文でも一行ずつ「何をしているのか」が見えます。
WHERE と HAVING の違い
ここが最重要です。
| 句 | タイミング | 条件対象 | 例 |
|---|---|---|---|
| WHERE | グループ化前(個別行) | 各行 1 つずつ | WHERE 売上 > 100000 → 売上 > 100000 の行だけを読み込む段階で残す |
| HAVING | グループ化後(集計後) | グループ全体 | HAVING COUNT(*) >= 2 → グループ化した後、受注件数が 2 件以上のグループだけを残す |
具体例:顧客ごとの受注件数が 2 件以上で、かつ売上合計が 50万以上のグループを求める場合
SELECT
顧客ID,
COUNT(*) AS 受注件数,
SUM(売上) AS 売上合計
FROM 受注表
WHERE 売上 > 0 -- WHERE:個別行。売上がプラスの受注だけを読み込む
GROUP BY 顧客ID
HAVING COUNT(*) >= 2 -- HAVING:グループ。受注件数が 2件以上
AND SUM(売上) >= 500000 -- グループの合計売上が 50万以上
ORDER BY 売上合計 DESC;処理の流れ:
- 売上 > 0 の受注行を読み込む(WHERE)
- 顧客ごとにグループ化
- 各グループが「受注件数 >= 2 かつ売上合計 >= 50万」なら残す(HAVING)
- 顧客ID、受注件数、売上合計を表示(SELECT)
- 売上合計の大きい順(ORDER BY)
| 句 | 役割 | 処理のイメージ | 例 |
|---|---|---|---|
| FROM | 読み込むテーブル | メモリにデータを乗せる | FROM 受注表 |
| WHERE | 行をフィルタ | メモリ上で、条件に合わない行を捨てる | WHERE 売上 > 100000 |
| GROUP BY | グループ化 | 残った行を「顧客ID」ごとにまとめる | GROUP BY 顧客ID |
| HAVING | グループをフィルタ | グループの中から、条件に合わないグループを捨てる | HAVING COUNT(*) >= 2 |
| SELECT | 列を選択 | グループから表示する列を決める | SELECT 顧客ID, 売上合計 |
| ORDER BY | ソート | 結果を売上順などに並べ替える | ORDER BY 売上合計 DESC |
WHERE 句で使う演算子と関数
WHERE 句の条件は、複数組み合わせることもできます。
| 演算子 | 説明 | 例 | 注記 |
|---|---|---|---|
| = | 完全一致 | WHERE 顧客ID = 101 | 数値でもテキストでも使える |
<> or != | 不一致 | WHERE 顧客ID <> 101 | <> が標準的(!= は非標準) |
> / < / >= / <= | 大小比較 | WHERE 売上 >= 50000 | 数値の範囲指定に使う |
| LIKE | 部分一致(ワイルドカード) | WHERE 顧客名 LIKE 'A%' | % = 任意の文字。'A%' = A で始まる |
| IN | 複数値のいずれか | WHERE 顧客ID IN (101, 102, 103) | OR を複数書く代わりに使える |
| BETWEEN | 範囲指定(両端含む) | WHERE 売上 BETWEEN 10000 AND 50000 | >= 10000 AND <= 50000 と同じ |
| AND | かつ | WHERE 売上 > 50000 AND 顧客ID = 101 | 複数条件の全てが満たす |
| OR | または | WHERE 売上 > 100000 OR 売上 < 10000 | 複数条件の一つ以上が満たす |
| NOT | 否定 | WHERE NOT (顧客ID = 101) | 条件を反転 |
| IS NULL | NULL チェック | WHERE 部門ID IS NULL | NULL は = で比較できない(IS NULL を使う) |
| IS NOT NULL | NULL でない | WHERE 部門ID IS NOT NULL | NULL 以外の値 |
集約関数
集約関数は、複数の行(グループ)の値を 1 つにまとめて計算します。試験では「何が対象か」を正確に理解することが重要です。
主要な集約関数
| 関数 | 説明 | 戻り値 | 例 | 注記 |
|---|---|---|---|---|
| COUNT() | 行数をカウント | 整数 | COUNT(*) = すべての行。COUNT(売上) = NULL を除いた行数 | NULL は数えない |
| SUM() | 合計を計算 | 数値 | SUM(売上) | NULL 値は 0 として扱わず、計算から除外 |
| AVG() | 平均を計算 | 数値 | AVG(売上) | NULL は除外して計算 |
| MAX() | 最大値を取得 | 単一値 | MAX(売上) | 数値だけでなくテキストの最大(Z に近い)も可能 |
| MIN() | 最小値を取得 | 単一値 | MIN(売上) | 数値だけでなくテキストの最小(A に近い)も可能 |
GROUP BY と集約関数の組み合わせ
集約関数が本領を発揮するのは、GROUP BY と組み合わせた時です。
例:顧客ごとの売上合計を求める
SELECT
顧客ID,
SUM(売上) AS 売上合計
FROM 受注表
GROUP BY 顧客ID;
【結果イメージ】
顧客ID | 売上合計
101 | 150000
102 | 200000
103 | 80000処理の流れ:
- 受注表のすべての行を読む
- 顧客ID でグループ化(顧客101 の行、102 の行、103 の行に分ける)
- 各グループの売上を合計(SUM)
- 顧客ごとに 1 行(計 3 行)の結果
GROUP BY なしで集約関数を使った場合:
SELECT SUM(売上)
FROM 受注表;
【結果】
SUM(売上)
430000 ← 全行の合計グループ化しないので、結果は 1 行だけになります。
集約関数と NULL の処理
NULL 値は、COUNT(*)には含まれますが、COUNT(列名)、SUM()、AVG() などには含まれません。
例:COUNT(売上) が 8 で、テーブルに 10 行あれば、2 行は売上 = NULL
SQL 計算例:WHERE、GROUP BY、HAVING の全パターン
-- 売上 > 10000 の受注で、顧客ごとに受注件数と売上合計を求める
-- ただし、受注件数が 2件以上の顧客だけを表示
-- 結果は売上合計の大きい順
SELECT
顧客ID,
COUNT(*) AS 受注件数,
SUM(売上) AS 売上合計
FROM 受注表
WHERE 売上 > 10000 -- WHERE:個別行の条件
GROUP BY 顧客ID -- GROUP BY:顧客ごとに集計
HAVING COUNT(*) >= 2 -- HAVING:グループの条件
ORDER BY 売上合計 DESC;処理の流れ(重要):
- FROM で受注表全体を読む(10 件あると仮定)
- WHERE 売上 > 10000 で条件に合う行だけを残す(5 件に減ったと仮定)
- GROUP BY 顧客ID で 5 件を顧客ごとにグループ化(顧客101=2件、102=2件、103=1件)
- HAVING COUNT(*) >= 2 で「受注件数 >= 2」のグループだけ残す(顧客101と102)
- SELECT で顧客ID、受注件数、売上合計の 3 列を表示
- ORDER BY で売上合計の大きい順にソート
データ例で追跡:
【受注表(元データ)】
受注ID | 顧客ID | 売上
R001 | 101 | 20000 ← WHERE で残す
R002 | 101 | 15000 ← WHERE で残す
R003 | 101 | 5000 ← WHERE で削除(売上 <= 10000)
R004 | 102 | 30000 ← WHERE で残す
R005 | 102 | 25000 ← WHERE で残す
R006 | 103 | 40000 ← WHERE で残す
R007 | 103 | 8000 ← WHERE で削除
【WHERE 後】
受注ID | 顧客ID | 売上
R001 | 101 | 20000
R002 | 101 | 15000
R004 | 102 | 30000
R005 | 102 | 25000
R006 | 103 | 40000
【GROUP BY で集計、HAVING で絞った後】
顧客ID | 受注件数 | 売上合計
101 | 2 | 35000 ← HAVING で残す(2件以上)
102 | 2 | 55000 ← HAVING で残す(2件以上)
(103 | 1 | 40000) ← HAVING で削除(1件のみ)
【ORDER BY で結果ソート】
顧客ID | 受注件数 | 売上合計
102 | 2 | 55000 ← 売上合計が大きい
101 | 2 | 35000このクエリで試験されるポイント:
- WHERE は「グループ化前」に「個別行」を絞る
- HAVING は「グループ化後」に「グループ」を絞る
- COUNT(*) と COUNT(列) の違い(NULL の扱い)
- ORDER BY DESC は「大きい順」
JOIN の種類
JOIN は、複数の表を「関連キー」で結合する操作です。正規化された RDB では、表を分割しているため、必ず JOIN が出てきます。試験では INNER JOIN と LEFT OUTER JOIN が中心です。
JOIN の種類と結果行数
| JOIN 種類 | 説明 | 結果行数 | 使用場面 | 出力の特徴 |
|---|---|---|---|---|
| INNER JOIN | 両方の表に存在するペアのみ | 少ない | 確実に関連データがある行だけが必要 | NULL がない |
| LEFT OUTER JOIN | 左表全て + 右表と共通の行 | 左表の行数 | 左表のすべてのデータを残したい | 右表に対応なし → NULL |
| RIGHT OUTER JOIN | 右表全て + 左表と共通の行 | 右表の行数 | 右表のすべてのデータを残したい | 左表に対応なし → NULL |
| FULL OUTER JOIN | 両表全て | 最多 | 全データを漏らさず取得(DBMS 非互換) | 両側で NULL あり得る |
| CROSS JOIN | 全ての組み合わせ | m × n | 直積。通常は不要 | すべての組み合わせ |
JOIN の仕組み
理解しやすいように、図で表現します。
【顧客表】 【受注表】
顧客ID 顧客名 受注ID 顧客ID 売上
101 A社 R001 101 100000
102 B社 R002 101 50000
103 C社 R003 102 80000
R004 104 60000 ← 顧客ID 104 は顧客表にない
【INNER JOIN の結果】← 両方の表に存在する行だけ
顧客ID 顧客名 受注ID 売上
101 A社 R001 100000
101 A社 R002 50000
102 B社 R003 80000
→ R004(顧客104)と顧客103(受注なし)は消える
【LEFT OUTER JOIN の結果】← 左表全て + 右表の共通行
顧客ID 顧客名 受注ID 売上
101 A社 R001 100000
101 A社 R002 50000
102 B社 R003 80000
103 C社 NULL NULL ← 顧客103は受注がないので右側が NULL
→ 顧客103は残る。顧客104(受注側だけ)は消えるLEFT OUTER JOIN で重要なポイント
FROM 顧客表 LEFT JOIN 受注表 とすると、顧客表がベースになります。
結果として「受注がない顧客も含めて全顧客が表示される」ことになります。
反対に FROM 受注表 LEFT JOIN 顧客表 とすると、受注表がベースなので「顧客がない受注」も含まれます(あれば)。
JOIN の具体例:INNER JOIN vs LEFT OUTER JOIN
データセット:
【顧客表】 【受注表】
顧客ID 顧客名 受注ID 顧客ID 売上
101 A社 R001 101 100000
102 B社 R002 101 50000
103 C社 R003 102 80000例1:INNER JOIN(受注がある顧客だけを表示)
SELECT
顧客表.顧客ID,
顧客表.顧客名,
受注表.受注ID,
受注表.売上
FROM 顧客表
INNER JOIN 受注表 ON 顧客表.顧客ID = 受注表.顧客ID
ORDER BY 顧客表.顧客ID;
【結果】
顧客ID | 顧客名 | 受注ID | 売上
101 | A社 | R001 | 100000
101 | A社 | R002 | 50000
102 | B社 | R003 | 80000
← 顧客103(C社)は受注がないので出現しない実務イメージ:「受注があった顧客だけのリスト」が必要な時(請求書作成など)
例2:LEFT OUTER JOIN(全顧客を表示、受注がなければ NULL)
SELECT
顧客表.顧客ID,
顧客表.顧客名,
受注表.受注ID,
受注表.売上
FROM 顧客表
LEFT OUTER JOIN 受注表 ON 顧客表.顧客ID = 受注表.顧客ID
ORDER BY 顧客表.顧客ID;
【結果】
顧客ID | 顧客名 | 受注ID | 売上
101 | A社 | R001 | 100000
101 | A社 | R002 | 50000
102 | B社 | R003 | 80000
103 | C社 | NULL | NULL ← 顧客103も表示(受注なし)実務イメージ:「すべての顧客をリストアップし、受注実績があれば表示、なければ『未受注』と表示」
どちらを使うか:
- 「受注と関連する顧客」→ INNER JOIN
- 「すべての顧客(受注の有無を問わず)」→ LEFT OUTER JOIN
サブクエリと相関サブクエリ
| 種類 | 説明 | 実行パターン | 例 |
|---|---|---|---|
| 非相関サブクエリ | 独立したクエリを内側で実行 | 内側を 1 回実行、その結果を外側で使う | WHERE 顧客ID IN (SELECT 顧客ID FROM ...) |
| 相関サブクエリ | 外側の値を参照しながら実行 | 外側の各行に対し内側を毎回実行 | WHERE 売上 > (SELECT AVG(売上) FROM ... WHERE 同じ顧客) |
トランザクション
トランザクションとは何か
トランザクション(transaction)は、「複数の操作をセットで扱い、『全て成功するか全て失敗するか』のいずれかにする」仕組みです。
最もわかりやすい例が「銀行振込」です:
- あなたの口座から 100万円を出金
- 相手の口座に 100万円を入金
この 2 つの操作を想像してください。もし途中で停電が起きて、「出金は成功したが入金は失敗」という状態になったら、あなたの 100万円が消えます。
トランザクションは、この問題を防ぎます。「出金と入金は 1 つの仕事(トランザクション)。途中で止まったら、両方リセット」という約束になります。
ACID 特性
トランザクション処理が安全であるためには、4 つの特性が必要です。試験ではこれらを「何を保証するのか」を理解することが重要です。
| 特性 | 日本語 | 意味 | 実例 | 違反時の問題 |
|---|---|---|---|---|
| A | 原子性 | 操作は「全て成功」か「全て失敗」か。中途半端はない | 出金と入金の両方が成功するか、両方失敗するか | 出金だけ成功、入金失敗 → 金額消失 |
| C | 一貫性 | トランザクション前後でデータ整合が保たれる | 出金前の総残高 = 出金後の総残高(個人間での移動だから) | 1 回の操作で残高が 2 倍に減る |
| I | 独立性 | 同時に複数のトランザクションが走ってても干渉しない | AさんとBさんが同時に振込しても、結果に矛盾がない | Aさんの未確定値を読んでBさんが計算(ダーティリード) |
| D | 永続性 | コミット(確定)したら、障害があってもデータは残る | 「振込完了」と表示したら、電源が切れてもお金は移動している | コミット直後にクラッシュで反映消失 |
ACID 特性と実装技術の対応
「ACID 特性」は理想。それを実現するのが実装技術です。
| 特性 | 実装方法 | 具体例 |
|---|---|---|
| 原子性 | コミット/ロールバック | トランザクション開始 → 複数操作 → コミット(全て記録)or ロールバック(全て破棄) |
| 一貫性 | 制約チェック | 外部キー制約(親行がないのに子行は作らない)、CHECK 制約(売上が負数でない) |
| 独立性 | 排他制御(ロック) | トランザクションA が口座データを「独占ロック」→ トランザクションB は待機 → A がコミット/ロールバック → B が実行 |
| 永続性 | ログファイル + ディスクフラッシュ | すべてのコミット済み操作をログに記録。定期的にディスクに永続化 |
ACID 特性の本質
ACID は「トランザクション処理が何を約束するか」です。データベースが「複数の操作を確実に扱える」ことを保証します。
排他制御(ロック)
トランザクション間の干渉を防ぐため、ロックを使用します。ロックは「データに対する独占権」のようなものです。
ロックの 2 つの種類
| ロック種類 | 日本語 | 説明 | 複数トランザクションでの共有 | 使用場面 |
|---|---|---|---|---|
| 共有ロック(S ロック) | 読み取りロック | 読み取り専用。複数トランザクションで同時に取得可能 | 複数 OK(全て読み取り) | SELECT 時。複数のトランザクションが同時に読んでも矛盾しない |
| 占有ロック(X ロック) | 書き込みロック | 書き込み・削除用。他のすべての操作を排除 | 1つだけ(排他的) | UPDATE / DELETE 時。この操作の途中で他がデータを読んだり変更したりできない |
ロック競合の実例:
タイムライン:
トランザクション A トランザクション B
1. 顧客ID=101 の残高を読む(S ロック取得)
(読み取り開始。この間、他も読める)
2. 残高 = 100万 を確認
3. 顧客ID=101 の残高を更新したい(X ロック必須)
4. → X ロックを要求
5. → 待機(A が S ロックを持ってるから取得できない)
6. トランザクション A がコミット
(S ロック解放)
7. X ロック取得可能に
8. 残高を 50万に更新
9. コミット
(X ロック解放)この流れにより、A のコミット前の未確定な値を B が使ってしまう問題が防止されます。
ロックの直感的理解
- S ロック:「本を読む」→複数人が同時に読める
- X ロック:「本を編集する」→1人だけ。編集中に他人は読んだり編集したりできない
デッドロック
相互に相手のロック解放を待つ状態が「デッドロック」です。データベースは自動的に検出して解決します。
トランザクション A トランザクション B
1. 顧客テーブル1 を X ロック取得
2. 商品テーブル2 を X ロック取得
3. 商品テーブル2 の X ロックを要求
4. → テーブル2 は B が持ってる(待機)
5. 顧客テーブル1 の X ロックを要求
6. → テーブル1 は A が持ってる(待機)
7. 互いに待機状態 ← デッドロック発生DBMS がタイムアウトで検出 → 一方を強制中止 → ロック解放 → 他方が再開
対策:
- ロック取得順序を統一する(常に「顧客テーブル」→「商品テーブル」)
- トランザクション時間を短くする
- タイムアウト値を設定する
コミットとロールバック
トランザクションは開始から終了まで、以下のいずれかで完結します:
| 命令 | 役割 | 実際の効果 | タイミング |
|---|---|---|---|
| COMMIT | トランザクション確定 | 変更がディスクに永続化。ログに記録。ロック解放。以降の読み取りに反映 | トランザクション成功時 |
| ROLLBACK | トランザクション取消 | すべての変更を破棄して初期状態に戻す。ロック解放。他のトランザクションは待機解除 | エラー発生時や明示的取消 |
実例:
BEGIN TRANSACTION;
UPDATE 顧客表 SET 残高 = 残高 - 100 WHERE 顧客ID = 1;
UPDATE 顧客表 SET 残高 = 残高 + 100 WHERE 顧客ID = 2;
-- ここまでのすべての操作は「未確定」。他のトランザクションには見えない
COMMIT; -- または ROLLBACK;COMMITを実行 → 両方の UPDATE が確定。他のトランザクションから見えるROLLBACKを実行 → 両方の UPDATE が破棄。顧客の残高は変わらない
バックアップとリカバリ
背景:なぜバックアップが必要か
企業システムのデータベースには、毎日膨大な重要データが記録されます。売上、顧客情報、在庫、給与データなど。これらが消えたら企業は機能しません。
障害は必ず起きます。ハードディスク故障、停電、ウイルス感染、誤削除。だから、バックアップ(データのコピー)を定期的に取得し、問題が起きた時に復旧できるようにしておくのです。
しかし、バックアップを取るだけでは不十分。実際に「取得したバックアップから本当に復旧できるか」をテストするまで含めて初めて有効です。
バックアップの 3 つの種類
容量と時間のトレードオフで、3 つを組み合わせます。
| 種類 | 説明 | 対象 | ファイル容量 | リカバリ速度 | 用途 | 頻度 |
|---|---|---|---|---|---|---|
| フルバックアップ | データベース全体をコピー | すべてのデータ | 最大(例:500GB) | 最速(1回復元) | 定期的な確実な保存 | 週1回など |
| 差分バックアップ | 前回フルバックアップ以降の変更分だけコピー | 変更されたデータのみ | 中程度 | 中程度(フル+差分) | 毎日の更新を記録 | 毎日 |
| 増分バックアップ | 前回のバックアップ(フル or 増分)以降の変更分だけコピー | 最小限の変更データ | 最小(例:1GB) | 最遅(フル+増分×N) | 高頻度で更新を記録 | 毎時間 |
バックアップ戦略の典型例
【時系列】
日曜 23:00 フルバックアップ取得(500GB)
月曜 23:00 差分バックアップ(日曜フル以降の累積変更分:50GB)
火曜 23:00 差分バックアップ(日曜フル以降の累積変更分:100GB)
水曜 23:00 差分バックアップ(150GB)
木曜 23:00 差分バックアップ(200GB)
金曜 12:00 増分バックアップ(前回バックアップ以降の変更分、10GB)
金曜 13:00 増分バックアップ(10GB)
...
【金曜 15:00 に障害が発生した場合】
1. 日曜のフルバックアップから復元(500GB 復旧、データは日曜時点)
2. 木曜の差分バックアップを適用(データは木曜 23:00 時点)← 差分は最新の1つだけでよい
3. 金曜の 14:00 の増分バックアップまで時系列に適用(データは金曜 14:00 時点)
→ ほぼ全データが復旧。損失は 14:00〜15:00 の 1 時間分だけ容量と速度のトレードオフ
- 毎回フルを取れば「復旧は速い」が「容量とコストが膨大」
- 増分だけを取れば「容量は小さい」が「復旧に時間がかかる」
- だから「フル + 差分 + 増分」の組み合わせが実務的
リカバリの方法
バックアップから復旧する際の 3 つの操作:
| 方法 | タイミング | 説明 | 具体例 |
|---|---|---|---|
| ロールバック | 障害直後 | トランザクションログを使って、未確定の途中操作を取り消す | システムクラッシュ時に「最後のコミット」まで戻す |
| ロールフォワード | バックアップ復元後 | トランザクションログを再実行して、バックアップ以降の確定済み操作を復元 | フルバックアップ(日曜)から復元した後、月〜金の操作を再実行 |
| チェックポイント | 定期的(計画) | DBMS が定期的に「今この瞬間、整合性が取れた状態」を記録 | 毎時間ごとにチェックポイントを作成。リカバリ開始点を減らす |
リカバリの実際の流れ
【トランザクションログ記録】
コミット済み操作1(売上確定)
コミット済み操作2(在庫更新)
コミット済み操作3(入金記録)
途中の操作4(給与計算中→クラッシュで未確定)
...
【復旧手順】
1. 最後のバックアップから復元
2. ロールバック:途中の操作4を取り消す
3. ロールフォワード:操作1, 2, 3 をもう一度実行
→ データベースが「クラッシュ直前の確定状態」に復元バックアップの落とし穴
「毎週金曜夜にバックアップを取っている」と安心していても、実は取得に失敗していた。あるいは取得されたファイルが破損していた。 → 「バックアップの取得」だけでなく「復旧テスト」を定期的に実施する必要がある。
ビューとインデックス
ビュー(View)
ビューは、「複数の表から必要なデータだけを取り出す『仮想的な表』」です。物理的には存在せず、定義(SELECT 文)だけが保存されます。
ビューの仕組み
【元データ:受注表】
受注ID | 顧客ID | 社員ID | 売上 | 売上日
R001 | C001 | E01 | 100000 | 04-15
R002 | C001 | E02 | 50000 | 04-15
R003 | C002 | E01 | 80000 | 04-16
...(数百万行)
【ビュー定義】
CREATE VIEW 営業成績 AS
SELECT
社員ID,
COUNT(*) AS 受注件数,
SUM(売上) AS 売上合計
FROM 受注表
GROUP BY 社員ID;
【営業成績ビューを SELECT】
SELECT * FROM 営業成績
WHERE 売上合計 > 100000;
【内部的な処理】
→ 定義されたSELECT文を実行
→ 結果が返される
(毎回、もとのテーブルから計算される)ビューの特性
| 特性 | 説明 | 活用例 |
|---|---|---|
| 実体なし | ディスク上にデータを持たない。定義(SQL)だけ保存 | 容量節約 |
| 遅延評価 | ビューを SELECT するたびに、定義のSELECT が実行される | 常に最新データが見える |
| 更新可能性 | 単純なビュー(1 表のみ)は更新可能。複雑なビューは読み取り専用 | 複雑な計算結果は修正できない |
| セキュリティ | 不要な列を隠せる。営業部門には「売上」だけ見せて「原価」は非表示 | データ保護 |
インデックス(Index)
インデックスは、「データベース検索を高速化するための補助構造」です。本の「索引」に似ています。
インデックスの仕組み
「顧客ID で受注を検索」する場合を想像してください。
インデックスなし(線形探索):
受注表:R001, R002, R003, R004, ..., R1000000
顧客ID = C001 を探す
→ 最初から全部見て、C001 を見つけるまで探索
→ 運が悪いと 500万行確認(時間がかかる)インデックスあり(B+ ツリー):
【インデックス】
A | B | C | D | ... ← アルファベット順
↓
顧客C の行の位置へ直接ジャンプ
→ 数十行の確認で発見(高速)インデックスの選択基準
| 指標 | 判定 | 例 |
|---|---|---|
| 検索頻度 | 高い列 | WHERE 句でよく使われる顧客ID |
| 更新頻度 | 低い列 | ほぼ変わらないID。逆に「日次更新」される「残高」にインデックスを張るとムダ |
| カーディナリティ | 高い(重複少ない)列 | 顧客ID(複数) vs 性別(男女だけ) → 前者が効果的 |
インデックスの誤解
「インデックスを多く張れば検索が早くなる」は間違い。
- INSERT / UPDATE / DELETE のたびにインデックスも更新が必要 → コスト増
- インデックス自体もメモリ・ディスク消費 → 「このインデックスは本当に必要か」を問い直す必要あり
現実的な方針:主キー と外部キー は必須。WHERE で頻出の列を厳選。
-- インデックス作成
CREATE INDEX idx_顧客ID ON 受注表(顧客ID);
-- 複合インデックス(複数列)
CREATE INDEX idx_顧客日付 ON 受注表(顧客ID, 売上日);
-- インデックス削除
DROP INDEX idx_顧客ID;過去問で戻りやすい補助論点
マスタデータ、トランザクションデータ、参照整合性
実務の業務システムでは、データを大きく マスタデータ と トランザクションデータ に分けて考えます。この区別ができると、どの表を先に作るか、どの入力欄が自由入力か、どこに外部キーが入るか が見えやすくなります。
| 種類 | 役割 | 代表例 | 特徴 | 典型的な関係 |
|---|---|---|---|---|
| マスタデータ | 基準となる台帳 | 顧客マスタ、商品マスタ、部門マスタ | 比較的安定。コード体系を持つ | 参照される側 |
| トランザクションデータ | 日々発生する事実 | 受注、出荷、入金、仕訳 | 件数が多く、時系列で増える | 参照する側 |
受注システムなら、商品コード や 顧客コード はマスタに登録されており、受注入力画面ではそのコードを参照してトランザクションを記録します。
【商品マスタ】
商品ID | 商品名 | 標準単価
P001 | 部品A | 1200
P002 | 部品B | 800
【受注トランザクション】
受注ID | 商品ID | 数量 | 受注日
R001 | P001 | 10 | 04-01
R002 | P002 | 5 | 04-02このとき 受注トランザクション.商品ID は、商品マスタ.商品ID を参照する外部キーです。参照整合性があるので、存在しない商品コード P999 を誤って入力することを防げます。
ヘッダ、明細、マスタで正規化を読む
正規化問題では、どの列を別表へ追い出すか を感覚で決めるのではなく、受注全体で1回決まるか、行ごとに変わるか、安定した基準データか で切り分けます。特に過去問では、主キー全体への従属 を見落とすと正誤判断を誤りやすいです。
| 置き場所 | 何が入るか | 典型例 | 判断のコツ |
|---|---|---|---|
| ヘッダ | 1 件の取引全体で 1 回決まる情報 | 受注番号、受注日、顧客ID | 明細行が増えても値が変わらない |
| 明細 | 行ごとに変わる情報 | 商品ID、数量、行番号 | 受注番号 + 行番号 のような複合キーになりやすい |
| マスタ | 他表から繰り返し参照される基準情報 | 商品名、標準単価、顧客名、部門名 | コードが決まれば安定して決まる |
たとえば主キーが 受注番号 + 行番号 のとき、数量 は主キー全体に従属しますが、商品名 や 標準単価 は 商品ID だけで決まります。このような列は明細に持たせ続けるより、商品マスタへ置いた方が重複や更新異常を防ぎやすくなります。
条件式の組み立て:AND / OR / NOT、括弧、IF / CASE
試験では、SQL の WHERE 句だけでなく、表計算ソフトの IF 関数や SQL の CASE 式のような条件分岐も、条件をどう束ねるか という同じ考え方で問われます。重要なのは、どの条件が先に評価されるか を明示することです。
| 優先順位 | 演算子 | 意味 |
|---|---|---|
| 1 | NOT | 否定 |
| 2 | AND | すべて満たす |
| 3 | OR | どれかを満たす |
たとえば、A または B かつ C をそのまま書くと、B かつ C が先に評価されます。
-- この式は A OR (B AND C) と同じ
WHERE 色 = '赤'
OR 色 = '青' AND 数量 >= 10(A または B) かつ C にしたいなら、括弧が必要です。
WHERE (色 = '赤' OR 色 = '青')
AND 数量 >= 10条件分岐を文章で読むときは、次の順に整理すると混乱しにくくなります。
まず何を満たせば Yes 側に入るかそれが複数条件の AND か OR か例外条件を NOT で除外しているか
IF 関数や CASE 式での考え方 も同じです。
CASE
WHEN 売上 >= 100000 AND 利益率 >= 0.2 THEN 'A'
WHEN 売上 >= 100000 THEN 'B'
ELSE 'C'
ENDこれは、「上から順に判定し、最初に当てはまった枝で確定する」条件分岐です。表計算ソフトのネストした IF も、実質的には同じ構造だと理解してください。
入力画面とデータベース設計のつながり
入力画面の部品は、何を入力させたいか と その値がどこから来るか で選びます。試験では、マスタデータを選ばせるのか、自由入力させるのかを見抜けるかがポイントです。
| UI 部品 | 使いどころ | 背後のデータ | 例 |
|---|---|---|---|
| テキストボックス | 自由に文字や数値を入力 | トランザクション値や名称 | 顧客名、数量、備考 |
| ドロップダウン | 候補が少なく、1つ選ばせる | マスタデータ参照 | 部門、都道府県、商品分類 |
| リストボックス | 候補が多く、一覧から選ばせる | マスタデータ参照 | 仕入先一覧、担当者一覧 |
| ラジオボタン | 候補が少なく、選択肢を常時見せたい | 固定コード | 性別、支払方法 |
| チェックボックス | Yes / No や複数選択 | 真偽値や複数属性 | 同意、通知設定 |
判断の軸は次の 3 つです。
候補が固定されているか候補数が少ないか多いかマスタから選ぶのか、その場で新規入力するのか
たとえば 商品区分 のように候補が固定されているなら、テキストボックスで自由入力させると表記ゆれが起きやすくなります。マスタを用意し、ドロップダウンやリストボックスから選ばせる方が設計として自然です。
JOIN と GROUP BY は「残す行」と「1行の単位」で考える
SQL の選択肢問題では、どの結合を使うか と どの列でまとめるか が一緒に問われることがあります。このときは、まずどの行を残すか、次に結果1行の単位を何にするか の順で考えると崩れません。
| 論点 | 最初に見ること | 典型的な読み方 |
|---|---|---|
| INNER JOIN | 両方に存在する行だけでよいか | 購入実績がある会員だけを出す |
| LEFT OUTER JOIN | 左側の表をすべて残したいか | 購入がない会員も含める |
| GROUP BY | 結果 1 行を何の単位にするか | 顧客別なら 顧客ID、商品別なら 商品ID |
購入回数を会員ごとに表示 なら、まず 会員を全部残すか / 購入実績がある人だけでよいか を決め、その後で 会員IDごとに集約 します。COUNT(*) や SUM(売上) のような集約結果そのものは GROUP BY に入れません。1 行をどの単位で作るか を表す列だけを置きます。
否定条件と重複除去の読み方
過去問では <> や自己結合を使って、ある条件を満たさない行 や 同じ組合せの重複 を除く問題が出ます。ここは演算子を記号のまま追うより、日本語へ戻す方が安全です。
| 書き方 | 日本語での意味 | よくある誤り |
|---|---|---|
A <> 'g' | A が g ではない | A = g の逆と意識できず読み飛ばす |
NOT (A AND B) | A と B を同時には満たさない | NOT A AND B と同一視する |
A.商品ID < B.商品ID | 同じ組合せを 1 回だけ数える | A-B と B-A を二重計上する |
自己結合で 商品A と商品B の組合せ を求めると、条件がないと A-B と B-A が両方出ます。そこで A.商品ID < B.商品ID のように大小条件を付けて、片方だけ残します。不等号は大小比較 であると同時に、重複除去のためのルール として使われることも押さえてください。
分析用データ基盤:DWH、データマート、データレイク、データクレンジング
日々の受注や会計処理を行う 業務DB(OLTP) と、分析のためにデータをためる基盤は役割が違います。ここを混同すると、DWH とデータレイク の設問で落としやすくなります。
| 用語 | 主目的 | 主なデータ | スキーマの考え方 | 典型用途 |
|---|---|---|---|---|
| 業務DB(OLTP) | 日々の更新処理 | 受注、入金、在庫更新 | 先に厳密に定義 | 受発注、会計、在庫管理 |
| データウェアハウス(DWH) | 分析用に統合・蓄積 | 複数システムの構造化データ | 先に定義してから格納 | 経営分析、BI |
| データマート | DWH の部門別サブセット | 営業用、財務用などの分析データ | DWH を用途別に切り出す | 部門別レポート |
| データレイク | 元データを広くためる | 構造化・半構造化・非構造化 | 後で読み方を決める | IoT、ログ、画像、SNS |
| データクレンジング | 分析前の品質改善 | 重複、欠損、表記ゆれの修正 | データそのものを整える処理 | 顧客名の表記統一 |
覚える軸は、先に形を決めるか と 何のためにためるか です。
DWHは 分析しやすい形に整えてから ためるデータレイクは 元の形式のまま広く集めて、後で読むデータマートは DWH の一部を目的別に切り出したものデータクレンジングは 置き場ではなく、データ品質を整える処理
DWH とデータレイクの切り分け
スキーマを先に決めて、分析しやすい表で持つ なら DWH、まず集めてから必要なときに読み方を決める ならデータレイクです。試験ではこの schema-on-write と schema-on-read の違いが本質です。
SQL の集合演算:UNION、UNION ALL、INTERSECT、EXCEPT
JOIN は 列をつなぐ 操作ですが、集合演算は 行の集合どうしを比べる 操作です。ここを混同しないことが大切です。
| 演算 | 役割 | 重複の扱い | 典型的な使い方 |
|---|---|---|---|
| UNION | 2つの結果を統合 | 重複を除く | 東京店の顧客一覧 ∪ 大阪店の顧客一覧 |
| UNION ALL | 2つの結果をそのまま連結 | 重複を残す | 売上明細を月別に単純連結 |
| INTERSECT | 両方にある行だけ残す | 共通部分だけ | 両キャンペーン対象の顧客 |
| EXCEPT | 前者にだけある行を残す | 差集合 | 会員だが購入実績がない顧客 |
前提として、集合演算では 列数 と 列の意味 がそろっている必要があります。顧客ID, 顧客名 と 商品ID, 商品名 を UNION するのは不適切です。
-- 列をつなぐ JOIN
SELECT c.顧客名, o.売上
FROM 顧客表 c
JOIN 受注表 o ON c.顧客ID = o.顧客ID;
-- 行を統合する UNION
SELECT 顧客ID FROM 東京店会員
UNION
SELECT 顧客ID FROM 大阪店会員;JOIN は 顧客表に売上列を付ける 発想、UNION は 同じ意味の顧客ID集合を縦にまとめる 発想です。
典型的なつまずき
つまずき 1:主キーと外部キーの役割の混同
誤り:「どちらも表をつなぐもの」と思う
正解:
- 主キー:「この行を識別するユニークな属性」。顧客101は A社、顧客102は B社。個を区別
- 外部キー:「別の表の主キーを参照する属性」。受注の顧客ID = 101 という「このレコードは顧客101のもの」という指標
試験対策:表の構造図を見た時、「PK は何か」「FK は何の FK か」を最初に確認
つまずき 2:正規化を「表を増やすこと」と勘違い
誤り:「正規化すると表が増える」→「表を増やせば正規化」
正解:「同じ情報の重複を減らすこと」が目的。副作用として表が増える
実例:
- 正規化前:受注テーブルに顧客名が繰り返される
- 正規化後:顧客テーブルを独立させる → 表は 1 → 2 に増えたが、目的は「顧客名の繰り返し削減」
試験対策:「この異常は何か(更新異常か、削除異常か)」を聞かれたら、「重複による矛盾」を思い出す
つまずき 3:SQL を「記述順に実行」と思う
誤り:
SELECT 列名 ← これが最初に実行
FROM テーブル ← これが 2 番目
WHERE 条件 ← これが 3 番目正解:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
具体的な混同:「SELECT で列を絞ったから、WHERE で NULL は参照できない」と思うが、WHERE は SELECT より前に実行されるので、SELECT されてない列でも WHERE では参照可能
試験対策:「処理順序を書け」という問題では、FROM から始めることを刻み込む
つまずき 4:JOIN の方向が逆
誤り:FROM 受注表 LEFT OUTER JOIN 顧客表 で「受注がない顧客を見たい」
正解:FROM 顧客表 LEFT OUTER JOIN 受注表 で「全顧客 + 受注がない顧客も含める」
理由:LEFT は左側(FROM)の表をすべて残す
試験対策:「何をすべて残したいのか」を決めてから、その表を LEFT 側に置く
つまずき 5:WHERE と HAVING の使い分け
誤り:「どちらも条件を絞る句だから同じ」
正解:
- WHERE:グループ化「前」の個別行を絞る
- HAVING:グループ化「後」のグループを絞る
具体例:「受注件数が 2 件以上で、かつ最近の受注は 1 月以降」
SELECT 顧客ID
FROM 受注表
WHERE 受注日 >= '04-01' ← WHERE:行レベル
GROUP BY 顧客ID
HAVING COUNT(*) >= 2 ← HAVING:グループレベルつまずき 6:トランザクションを「1 行の UPDATE」と混同
誤り:「UPDATE 1 行 = トランザクション 1 件」
正解:「複数の操作をセットで扱う」仕組み
具体例:振込は「出金 + 入金」の 2 操作で 1 トランザクション
つまずき 7:バックアップを取得しただけで安心
誤り:「毎週木曜に自動バックアップを取っているから大丈夫」
正解:「本当に復旧できるか」のテストを含めて初めて有効
現実的な問題:
- バックアップファイルが破損していた
- 取得に失敗していた
- 取得ファイルが別の場所に保存されて、災害で失った
試験対策:「バックアップとリカバリテストはセット」と覚える
つまずき 8:マスタとトランザクションを逆に考える
誤り:「受注データがマスタで、商品一覧がトランザクション」
正解:
- マスタ は基準となる台帳
- トランザクション は日々発生する事実
見分け方:更新頻度が低く、他の表から参照されるか を見る
つまずき 9:AND と OR の優先順位を読み違える
誤り:A OR B AND C を (A OR B) AND C だと思う
正解:括弧がなければ AND が先。つまり A OR (B AND C) と読む
試験対策:条件が 3 つ以上あるときは、必ず括弧付きの論理式に書き直す
つまずき 10:JOIN と UNION を同じ「表をまとめる操作」だと思う
誤り:「顧客表と受注表を UNION でまとめる」
正解:
- JOIN:キーで結び、列を横に増やす
- UNION:同じ意味の列集合を縦に積む
試験対策:横に広げるか、縦に積むか を最初に決める
つまずき 11:DWH とデータレイクを同じ「大きい保存場所」だと思う
誤り:「どちらも大量データをためる場所だから同じ」
正解:DWH は分析しやすい形に整えてから蓄積、データレイクは元データを広く蓄積して後で読む
試験対策:スキーマを先に決めるか後に決めるか を判断軸にする
つまずき 12:複合キーを見落として、主キー全体への従属を判定できない
誤り:「受注番号があるから、この表は受注単位で決まる」と見てしまう
正解:受注番号 + 行番号 のような複合キーなら、数量 は主キー全体に従属し、受注日 は受注番号だけに従属し、商品名 は商品IDだけに従属します。まず主キーを確定させ、その次に ヘッダ / 明細 / マスタ で列の置き場所を判定します。
つまずき 13:JOIN で残す行の範囲と GROUP BY の粒度を混同する
誤り:「会員ごとに購入回数を出す」問題で、COUNT(*) を GROUP BY に入れる、あるいは LEFT OUTER JOIN と INNER JOIN を気分で選ぶ
正解:JOIN は どの行を残すか、GROUP BY は 1 行を何の単位にするか を決めるものです。購入がない会員も含める なら LEFT OUTER JOIN、購入した会員だけ なら INNER JOIN、会員ごとの件数 なら GROUP BY 会員ID です。
つまずき 14:<> や自己結合の大小条件を読み飛ばす
誤り:A <> 'g' を軽く流したり、A.商品ID < B.商品ID の意味を理解しないまま選ぶ
正解:<> は否定条件、大小条件は重複除去のために使われることがあります。条件式は日本語へ戻し、何を除外したいのか を先に言い換えると読み違えにくくなります。
問題を解くときの観点
試験問題には「パターン」があります。問題の種類を見分けることが、迷わない解法の第一歩です。
問題のパターン判定
見た瞬間、以下のいずれかを確認:
| パターン | 見分け方 | 解法の第一歩 |
|---|---|---|
| 表の構造問題 | テーブル定義が示されている。「何正規形か」「異常は何か」が問われる | 重複している属性を探す。何がなぜ繰り返されるか |
| SQL 読み取り | SQL 文が示されて、結果を推測させられる | FROM → WHERE → GROUP BY の実行順を追う |
| 条件式・UI 設計 | IF / CASE、入力部品、マスタ参照が問われる | 候補が固定か、自由入力か、条件の優先順位は何かを見る |
| トランザクション | 複数操作が並行に起きている。「矛盾は何か」「ロックは何か」が問われる | 途中で止まったら困ることは何か |
| データ基盤比較 | DWH、データマート、データレイク、クレンジングが並ぶ | 目的、スキーマ時点、扱うデータの種類を比べる |
| バックアップ | 障害状況が説明される。「何を取得」「どう復旧」が問われる | バックアップの時点と復旧のポイントを時間軸で整理 |
SQL 読み取り問題のステップ
【問題:このクエリの結果は?】
SELECT 顧客ID, COUNT(*) AS 件数
FROM 受注表
WHERE 売上 > 50000
GROUP BY 顧客ID
HAVING COUNT(*) >= 2
ORDER BY 件数 DESC;
【解法ステップ】
1. 「処理順序は FROM → WHERE → ... ORDER BY」を思い出す
2. FROM:受注表全体を読む(例:10万行)
3. WHERE 売上 > 50000:絞る(例:5万行に減る)
4. GROUP BY 顧客ID:顧客ごとにグループ化(100グループ)
5. HAVING COUNT(*) >= 2:受注件数が 2件以上のグループだけ(50グループ)
6. SELECT:顧客IDと件数を表示
7. ORDER BY:件数の大きい順
→ 答え:受注が 2件以上で売上 > 50000 のグループ正規化問題のステップ
【問題:この表は何正規形か。何が問題か】
社員ID | 社員名 | 部門ID | 部門名 | スキルID
E001 | 田中 | D01 | 営業 | S001, S002
E002 | 佐藤 | D01 | 営業 | S001
【解法ステップ】
1. 繰り返し項目があるか? → スキルID が複数値 → 非正規形
2. 主キーは何か? → `社員ID` だけか、`社員ID + スキルID` の複合キーかを先に確定
3. 主キー全体に依存しない属性があるか? → 部門名は部門ID だけで決まる(社員ID は不要) → 第2正規形未満
4. `ヘッダ / 明細 / マスタ` のどこへ置くべきか → 部門名は部門マスタ側
5. 起きる異常は? → 「営業部門の名前を変えると、全社員レコードを更新が必要」 → 更新異常
→ 答え:非正規形。繰り返し項目を削除して第1正規形へ。次に部門名を分割して第2正規形へトランザクション問題のステップ
【問題:A と B が同時に同じ口座に入金する場合、何が起きるか】
【解法ステップ】
1. 「ACID の何に関係するか」を問う → 独立性(Isolation)
2. 「具体的に何が困るか」を説明 → 両方が最新残高を読んで計算すると、片方の入金が反映されない
3. 「対策は」 → 排他制御。1 人が書き込みロック(X)を取得 → 他方は待機 → ロック解放
→ 答え:独立性違反。更新競合やロストアップデートの危険がある。ロックで対策条件式・集合演算問題のステップ
【問題:この条件式はどのデータを返すか】
【解法ステップ】
1. AND / OR / NOT を、括弧つきの論理式へ書き直す
2. `<>` や `NOT` があれば、日本語で「何を除外する条件か」を先に言い換える
3. 条件が「個別行の判定」か「表どうしの統合」かを判定する
4. 横に広げるなら JOIN、縦に積むなら UNION 系を選ぶ
5. 自己結合なら、`A-B` と `B-A` の重複をどう防ぐかを見る
6. UNION なら、列数と列の意味がそろっているかを確認する
→ 答え:条件の優先順位と、JOIN / UNION の役割差から決めるデータ基盤・入力設計問題のステップ
【問題:DWH、データレイク、データマート、入力部品のどれが適切か】
【解法ステップ】
1. 目的が「日々の更新」か「分析」かを判定する
2. スキーマを先に決めるか、後で決めるかを見る
3. 入力欄なら、候補が固定か自由入力かを確認する
4. マスタを参照するならドロップダウン / リスト、自由入力ならテキストを基本に考える
→ 答え:役割とデータ源の違いで切り分ける確実な得点の心がけ
- 「表の構造」を見た時:キーの位置を確認。FK が指す先を追跡
- 「SQL 文」を見た時:実行順序(FROM 最初!)を書く
- 「条件式」を見た時:AND と OR を括弧付きに書き直す
- 「分析基盤」を見た時:業務処理か分析か、スキーマをいつ決めるかを見る
- 「複数操作」を見た時:「途中で止まると困るか」を判定
- 「日付」が出た時:バックアップはいつ。復旧はどの時点か
確認問題
確認問題 1:正規化の段階判定
下の表は何正規形ですか。また、どの異常が起きやすいか答えよ。
表:社員表
社員ID | 社員名 | 部門ID | 部門名 | プロジェクトID
E001 | 田中 | D01 | 営業 | P001, P002
E002 | 佐藤 | D01 | 営業 | P001解答:
- 非正規形。プロジェクトIDに繰り返し項目がある。
- 正規化すると:まず繰り返し項目を排除して第1正規形(社員-プロジェクト関連を独立表へ)。
- 次に部門名が部門ID に従属していることに気づき、部門表を独立させて第3正規形へ。
- この例では「営業部門の名前を変更する時、複数の社員レコードを更新しなければならない(更新異常)」が起きやすい。
確認問題 2:SQL 結果の読み取り
以下のクエリを実行した結果を示せ。(WHERE と HAVING の違いを理解しているか確認)
SELECT
顧客ID,
COUNT(*) AS 受注件数,
SUM(売上) AS 売上合計
FROM 受注表
WHERE 売上 >= 50000
GROUP BY 顧客ID
HAVING COUNT(*) >= 2
ORDER BY 売上合計 DESC;受注表のデータ:
受注ID | 顧客ID | 売上
R001 | C001 | 100000
R002 | C001 | 40000
R003 | C001 | 30000
R004 | C002 | 60000
R005 | C002 | 50000
R006 | C003 | 55000解答:
顧客ID | 受注件数 | 売上合計
C002 | 2 | 110000理由:
- WHERE 売上 >= 50000 で絞る:R001, R004, R005, R006
- GROUP BY 顧客ID でグループ化:C001(1件), C002(2件), C003(1件)
- HAVING COUNT(*) >= 2 で絞る:C002 だけ(2件以上)
重要な確認ポイント:
- WHERE(行レベルの条件)でまず絞った後に GROUP BY
- HAVING(グループレベル)で再度絞った
- 最終結果は C002 の 1 グループだけ
確認問題 3:ACID 特性と排他制御
以下の状況を説明しなさい。
状況:顧客A の口座残高 100万円から 50万円を出金し、顧客B の口座に入金するトランザクション。
- 原子性(Atomicity) が違反したらどうなるか。その対策は
- 独立性(Isolation) が違反したらどうなるか。その対策は
- この処理中、どのロックが必要で、どう機能するか
解答:
-
原子性違反の例
- 「出金だけ成功、入金が失敗」→ A さんの 50万が消える
- 「入金だけ成功、出金が失敗」→ お金が増える(不整合)
- 対策:
COMMIT(全て記録)かROLLBACK(全て破棄)で、中途半端を防止
-
独立性違反の例
- トランザクションA が「出金 → 入金」の途中で、トランザクションB がA の残高を読む
- B が読んだ値が確定値か未確定値か不明
- 例:A が出金を記録したが入金失敗 → B が古い残高を読む → 矛盾
- 対策:A が X ロック(占有ロック)を取得。B は A が完了するまで待機 → 確定値だけを読む
-
ロック
- A 口座:X ロック(書き込み)。出金操作を独占
- B 口座:X ロック(書き込み)。入金操作を独占
- 処理完了(コミット/ロールバック)→ ロック解放
- 他のトランザクションはロック解放まで待機
確認問題 4:バックアップとリカバリ
金曜 15:00 にシステム障害が発生。以下のバックアップがある。復旧方法は。
【バックアップ履歴】
日曜 23:00 フルバックアップ取得
月曜 23:00 差分バックアップ取得
...
木曜 23:00 差分バックアップ取得
金曜 12:00 増分バックアップ取得
金曜 13:00 増分バックアップ取得
金曜 14:00 増分バックアップ取得
(14:00 以降のトランザクションログ記録あり)【質問】
- 復旧の手順は
- 復旧できるデータはいつ時点か
- 失われるデータはいつ〜いつか
解答:
-
復旧手順
- ステップ1:日曜のフルバックアップからデータベース全体を復元
- ステップ2:月曜〜木曜の差分バックアップをすべて適用(木曜 23:00 時点)
- ステップ3:金曜の増分バックアップ(12:00, 13:00, 14:00)をすべて適用(金曜 14:00 時点)
- ステップ4:14:00 以降のトランザクションログを確認(確定済み操作だけ再実行)
-
復旧できるデータ
- コミット済みのトランザクション:金曜 14:00 までのすべて
- 金曜 14:00 〜 15:00 のコミット済み操作も復旧可能(ログから)
- 結果:ほぼ障害直前まで復旧可能
-
失われるデータ
- 「トランザクション開始後、14:00 以降に変更したが、15:00 までにコミットされなかった」操作
- 例:15:00 に「取引開始」した顧客操作で、15:00 内に完了しなかったもの
- 一般的には数分単位の最小限の損失
確認問題 5:マスタ、トランザクション、入力部品
商品マスタ、受注入力画面、受注トランザクション表がある。次の対応として最も適切なものを答えよ。
- 商品コードはどの表で管理するか
- 商品コード入力欄はテキストボックスとドロップダウンのどちらが基本か
- 数量入力欄は何が基本か
解答:
- 商品コードは 商品マスタ
- 商品コードはマスタ参照なので ドロップダウン が基本
- 数量は取引ごとに入力するので テキストボックス
理由:
- 商品コードは基準データで、受注のたびに自由入力させると表記ゆれや誤入力が起きやすい
- 数量は取引ごとに変わる値なので、トランザクション入力として扱う
確認問題 6:DWH とデータレイクの判定
次の説明に最も近い用語を答えよ。
- 複数の基幹システムから抽出した構造化データを、分析しやすい形で統合して蓄積する
- IoT センサログ、画像、SNS 投稿などを元の形式のまま広くためておき、後で分析方法を決める
- DWH から営業部門向けだけを切り出した分析用データ集合
- 重複顧客や住所表記ゆれを修正する処理
解答:
- データウェアハウス
- データレイク
- データマート
- データクレンジング
確認問題 7:条件式と集合演算
次の 2 問に答えよ。
A OR B AND Cは、括弧を補うとどうなるか東京店会員と大阪店会員の顧客ID一覧を、重複を除いて 1 つにまとめたい。JOIN と UNION のどちらを使うべきか
解答:
A OR (B AND C)。ANDが先に評価される- UNION。同じ意味の列集合を縦に統合する問題だから
確認問題 8:ヘッダ・明細・マスタの切り分け
次の属性を、受注ヘッダ、受注明細、商品マスタ のどこへ置くのが基本か答えよ。
- 受注日
- 顧客ID
- 商品ID
- 数量
- 商品名
- 標準単価
解答:
- 受注ヘッダ
- 受注ヘッダ
- 受注明細
- 受注明細
- 商品マスタ
- 商品マスタ
ポイント:1件の受注で1回だけ決まるか、行ごとに変わるか、基準データとして安定しているか で置き場所を決めます。
確認問題 9:JOIN と GROUP BY の粒度を選ぶ
会員ごとの購入回数 を表示したい。購入が 1 回もない会員も結果に含めたい場合、JOIN と GROUP BY はどう考えるべきか答えよ。
解答:
- JOIN は LEFT OUTER JOIN
- GROUP BY は 会員ID(必要なら会員名も)
ポイント:まず 会員を全員残したい ので会員表を左側に置いた LEFT OUTER JOIN を選びます。そのうえで、結果 1 行を 会員ごと にしたいので GROUP BY 会員ID にします。JOIN は残す行、GROUP BY は 1 行の単位です。
関連ページ
このページは役に立ちましたか?
評価とひとことを残してもらえると、内容と導線の改善に使えます。
Last updated on