データベーススペシャリスト試験の合格を目指す皆様へ。 本書は、データベーススペシャリスト試験の広範な出題範囲を網羅し、初心者の方から経験者の方まで、誰もが理解できるように丁寧かつ詳細に解説することを目的としています。複雑な概念も、平易な言葉と豊富な図表(Mermaid形式含む)を用いて視覚的に分かりやすく説明しています。
本書が、皆様のデータベーススペシャリスト試験合格への強力な一助となることを願っています。
データベーススペシャリスト試験(DB)は、情報処理推進機構(IPA)が実施する情報処理技術者試験の一つであり、高度情報処理技術者試験に分類されます。この試験は、企業活動における大量のデータを効率的かつ安全に管理・活用するための、データベースに関する専門知識とスキルを問うものです。
この試験は、データベースに関する深い知識と実践的な能力を持つ人材を育成し、評価することを目的としています。具体的には、以下のような役割を担う方を主な対象としています。
現代のビジネスにおいて、データは「石油に代わる21世紀の資源」とも言われるほど重要性が増しています。データベーススペシャリストは、この重要なデータを適切に扱い、企業の競争力向上に貢献する、まさになくてはならない存在です。
情報処理技術者試験の中では、最高レベルのスキルを認定する「高度試験」の一つに位置づけられています。基本情報技術者試験や応用情報技術者試験で問われる基礎的な知識に加え、より専門的で実践的な知識、そして問題解決能力が求められます。
具体的には、リレーショナルデータベース(RDB)の概念から、SQL、トランザクション処理、正規化、データモデリング、パフォーマンスチューニング、障害回復、セキュリティ、最新のデータベース技術(NoSQL、分散データベースなど)に至るまで、幅広い分野からの出題があります。
この資格を取得することで、データベースに関する深い専門知識と、それを実務に適用できる高度なスキルを持っていることを客観的に証明できます。これにより、IT業界でのキャリアアップや専門家としての信頼性向上に大きく寄与するでしょう。
データベーススペシャリスト試験は、年に1回、通常は秋期(10月の第3日曜日)に実施されます。試験は4つの区分に分かれており、1日で全ての試験を受験します。
graph TD
subgraph "試験全体"
A["午前Ⅰ"] --> B["午前Ⅱ"] --> C["午後Ⅰ"] --> D["午後Ⅱ"]
end
style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#ccf,stroke:#333,stroke-width:2px
style D fill:#ccf,stroke:#333,stroke-width:2px
| 試験区分 | 試験時間 | 出題形式 | 出題数 | 解答数 | 基準点 |
|---|---|---|---|---|---|
| 午前Ⅰ | 50分 | 多肢選択式(4択) | 30問 | 30問 | 60点/100点 |
| 午前Ⅱ | 40分 | 多肢選択式(4択) | 25問 | 25問 | 60点/100点 |
| 午後Ⅰ | 90分 | 記述式 | 3問 | 2問 | 60点/100点 |
| 午後Ⅱ | 120分 | 記述式 | 2問 | 1問 | 60点/100点 |
この試験の最大の特徴は「ノックダウン方式」が採用されている点です。これは、いずれかの試験区分で基準点(60点)に満たない場合、その時点で不合格となる厳しい採点方式です。
例えば、午前Ⅰで58点を取ってしまった場合、その後の午前Ⅱ、午後Ⅰ、午後Ⅱがたとえ満点であっても採点されることなく不合格となります。全ての試験区分で、安定して6割以上の得点を取る実力が求められます。
graph LR
Start("受験開始") --> AM1{"午前Ⅰ"};
AM1 -- "基準点以上" --> AM2{"午前Ⅱ"};
AM1 -- "基準点未満" --> Fail("不合格");
AM2 -- "基準点以上" --> PM1{"午後Ⅰ"};
AM2 -- "基準点未満" --> Fail;
PM1 -- "基準点以上" --> PM2{"午後Ⅱ"};
PM1 -- "基準点未満" --> Fail;
PM2 -- "基準点以上" --> Pass("最終合格");
PM2 -- "基準点未満" --> Fail;
style Fail fill:#fdd,stroke:#f00
style Pass fill:#ddf,stroke:#00f
以下のいずれかの条件を満たすことで、その後2年間、午前Ⅰ試験が免除されます。
多くの受験者はこの免除制度を活用し、専門分野である午前Ⅱと午後試験の対策に集中します。
データベーススペシャリスト試験の合格を勝ち取るためには、戦略的な学習計画が不可欠です。特に、各試験区分で基準点を超える必要がある「ノックダウン方式」を意識し、バランスの取れた学習を心がける必要があります。
学習期間は、個人の経験や知識レベルによって異なりますが、一般的には3ヶ月〜6ヶ月が目安とされています。
本セクションでは、各試験区分に応じた具体的な学習計画を提案します。
対象者: 午前Ⅰ試験の免除資格がない、または免除期間が切れてしまった方。
学習の要点: 「広く浅く」、そして**「過去問至上主義」**で乗り切ること。
午前Ⅰ試験は、全ての高度試験で共通して出題されるIT全般の知識を問う試験です。テクノロジ系、マネジメント系、ストラテジ系と範囲が非常に広く、全ての分野を完璧に理解しようとすると時間がいくらあっても足りません。
幸いなことに、午前Ⅰ試験は過去に出題された問題が形を変えて繰り返し出題される傾向が非常に強いです。そのため、最も効率的な対策は過去問演習に尽きます。
具体的な学習ステップ:
午前Ⅰ試験は、あくまで午前Ⅱ以降の専門試験に進むための「通行手形」です。完璧を目指さず、効率的に60点の壁を突破することだけを考えて学習を進めましょう。
学習の要点: 「狭く深く」、そして**「理屈を自分の言葉で説明できるレベル」**を目指すこと。
午前Ⅱ試験は、データベーススペシャリストとしての専門知識が問われる、この試験の核となる部分です。出題範囲はデータベース技術に特化しており、ここでの知識が午後試験の土台となります。午前Ⅰとは対照的に、単なる暗記ではなく、各技術や概念の本質的な理解が求められます。
重点学習分野:
SELECT文の高度な使い方、GROUP BY, HAVING, 副問合せ、結合、ウィンドウ関数など。GRANT/REVOKE、SQLインジェクション対策。具体的な学習ステップ:
体系的な知識のインプット:
過去問演習と徹底的な復習:
苦手分野の特定と克服:
午前Ⅱで高得点(目標は8割以上)を安定して取れるようになれば、午後試験を解くための強固な基礎知識が身についた証拠です。焦らずじっくりと、一つ一つの概念を自分のものにしていきましょう。
学習の要点: 「国語力と論理的思考力」 を駆使し、**「問題文に隠されたヒントを読み解く」**訓練を積むこと。
午後試験は、データベーススペシャリスト試験の天王山です。膨大な問題文の中から、要件、制約、課題を正確に読み取り、午前Ⅱで培った知識を応用して、記述式で解答する総合力が問われます。知識があるだけでは合格できません。
午後試験の出題傾向:
具体的な学習ステップ(5段階演習法):
【第1段階】時間を計って解く(シミュレーション)
【第2段階】時間無制限で解き直す(熟考)
【第3段階】解答例との比較・分析(ギャップ分析)
【第4段階】知識の再インプット(知識補強)
【第5段階】要約と再説明(定着)
この5段階のプロセスを最低でも5年分の過去問に対して行えば、合格は目前です。時間はかかりますが、最も着実に実力がつく方法です。
知識を蓄え、過去問演習を積んでも、試験本番で実力を100%発揮できなければ意味がありません。ここでは、限られた時間の中で1点でも多く得点するための、実践的な解答テクニックを紹介します。
午前Ⅰ・午前Ⅱは、1問あたり約1分半で解答する必要があるスピード勝負です。迷いを断ち切り、効率的に解答を進めるテクニックを身につけましょう。
時間配分を厳守する
消去法を徹底活用する
問題文のキーワードに注目する
常識で判断する
迷ったら最初の直感を信じる
午後試験の鉄則はただ一つ、**「答えは全て問題文の中にある」**です。自分の経験や知識だけで暴走せず、問題文という地図を正確に読み解くテクニックを身につけましょう。
最初の10分で問題を選び、戦略を立てる
問題文は「多色ボールペンで書き込みながら」読む
設問を先に読み、解答の「型」を意識する
WHERE句の条件、JOINのキー、GROUP BYの列などを特定する。解答は「聞かれたことに」「過不足なく」答える
部分点を確実に取りにいく
長期間にわたる試験勉強は、知識だけでなく、モチベーションの維持や学習の習慣化が同じくらい重要になります。最後に、合格まで走り抜くための心構えをいくつか紹介します。
学習を「習慣」にする
仕事や実務と結びつけて考える
モチベーションを管理する
体調管理も重要な試験対策
さあ、準備は整いました。次の章から、データベーススペシャリストになるための本格的な知識を学んでいきましょう!
データベースにおけるテーブル作成は、データを格納するための「箱」の設計図を作る作業に例えられます。どのような種類のデータを、どのように整理して格納するかを定義する、データベース設計の基礎となる重要なステップです。
SQL(Structured Query Language)におけるテーブル作成は、DDL(Data Definition Language: データ定義言語)の一つであるCREATE TABLE文を用いて行います。
テーブルを作成する際には、以下の要素を定義します。
データ型は、テーブルのカラムに格納できるデータの種類を定義するものです。適切なデータ型を選択することは、データの整合性を保ち、記憶領域を効率的に使用し、クエリのパフォーマンスを向上させる上で非常に重要です。
以下に代表的なデータ型とその特徴を説明します。データベースシステム(DBMS)によって、利用できるデータ型やその名称、詳細な挙動には違いがありますが、基本的な考え方は共通しています。
CHAR(n): 固定長文字列。nバイト(または文字)の固定長でデータを格納します。指定した長さより短い文字列を格納しても、残りの領域は空白で埋められます。例:CHAR(10)VARCHAR(n) / VARCHAR2(n): 可変長文字列。nバイト(または文字)までの可変長でデータを格納します。指定した長さより短い文字列を格納した場合、実際に格納されたデータ長に応じた領域のみを使用します。一般的にこちらが推奨されます。例:VARCHAR(255)TEXT / CLOB: 大容量のテキストデータを格納する場合に利用します。記事の本文やコメントなど、長さが不定で非常に長い文字列に適しています。INT / INTEGER: 整数値を格納します。多くのDBMSで符号付き32ビット整数を指しますが、範囲はDBMSに依存します。例:INTSMALLINT: INTよりも小さい範囲の整数値を格納します。BIGINT: INTよりも大きい範囲の整数値を格納します。DECIMAL(p, s) / NUMERIC(p, s): 固定小数点数を格納します。pは桁数(精度)、sは小数点以下の桁数を指定し、正確な計算が求められる通貨や金銭データなどに使用されます。例:DECIMAL(10, 2)(全体で10桁、小数点以下2桁)FLOAT / REAL / DOUBLE PRECISION: 浮動小数点数を格納します。概数として扱われるため、厳密な精度が不要な科学技術計算などに使用されます。DATE: 日付(年、月、日)のみを格納します。例:'2026-02-23'TIME: 時間(時、分、秒)のみを格納します。例:'10:30:00'DATETIME: 日付と時間(年、月、日、時、分、秒)を格納します。TIMESTAMP: DATETIMEと同様に日付と時間を格納しますが、多くのDBMSではタイムゾーン情報や更新日時自動記録などの機能を持つ場合があります。BOOLEAN: 真(TRUE)または偽(FALSE)のいずれかの値を格納します。DBMSによっては、TRUEを1、FALSEを0としてTINYINTなどで代用する場合もあります。以下は、様々なデータ型を用いた簡単なテーブル作成の例です。
CREATE TABLE Products (
product_id INT PRIMARY KEY, -- 製品ID (整数、主キー)
product_name VARCHAR(100) NOT NULL, -- 製品名 (可変長文字列、NULL不許可)
price DECIMAL(10, 2), -- 価格 (固定小数点数)
stock_quantity INT DEFAULT 0, -- 在庫数 (整数、デフォルト値0)
release_date DATE, -- 発売日 (日付)
is_available BOOLEAN -- 販売中かどうか (真偽値)
);
データベースにおけるNULLは、**「値が存在しない」「不明である」「適用できない」**といった状態を表す特殊な値です。数値の0や空文字''、または真偽値のFALSEとは明確に異なります。NULLは「未定義」の状態を示すものであり、データが存在しないことそのものを意味します。
NULLが絡む演算や比較は、一般的な値とは異なる振る舞いをします。この特性を理解していないと、意図しないクエリ結果を招く可能性があるため、注意が必要です。
算術演算: NULLを含む算術演算(+, -, *, /など)の結果は、常にNULLとなります。
-- 例: 5 + NULL は NULL となる
SELECT 5 + NULL;
これは、「不明な値に何かを加えても、結果はやはり不明である」という考え方に基づきます。
比較演算: NULLと他の値を=や!=(または<>)、<、>などの比較演算子で比較した場合、結果は真(TRUE)でも偽(FALSE)でもなく、UNKNOWN(不明)となります。
-- 例: 1 = NULL や 'A' = NULL は UNKNOWN となる
SELECT product_name FROM Products WHERE price = NULL; -- 意図した結果にならない
WHERE句でUNKNOWNと評価された行は、結果セットに含まれません。このため、WHERE price = NULLという条件では、priceがNULLの行は取得できません。
IS NULL, IS NOT NULL)NULLを正しく検索するためには、専用の演算子IS NULLまたはIS NOT NULLを使用します。
IS NULL: そのカラムの値がNULLである行を検索します。IS NOT NULL: そのカラムの値がNULLではない行を検索します。-- priceがNULLの製品を検索
SELECT product_name, price FROM Products WHERE price IS NULL;
-- priceがNULLではない製品を検索
SELECT product_name, price FROM Products WHERE price IS NOT NULL;
テーブルのカラム定義において、そのカラムにNULL値の格納を許可しないように設定できるのが**NOT NULL制約**です。これはデータの整合性を保つ上で非常に重要な制約となります。
NOT NULL制約が設定されたカラムには、必ず何らかの値を挿入する必要があります。NULLを挿入しようとするとエラーが発生します。
-- 製品テーブルの定義例(再掲、product_nameにNOT NULL制約)
CREATE TABLE Products (
product_id INT PRIMARY KEY,
product_name VARCHAR(100) NOT NULL, -- ここにNOT NULL制約
price DECIMAL(10, 2),
stock_quantity INT DEFAULT 0,
release_date DATE,
is_available BOOLEAN
);
-- product_nameに値を指定しないINSERTはエラーになる
-- INSERT INTO Products (product_id, product_name) VALUES (1, NULL); -- これはエラー!
INSERT INTO Products (product_id, product_name) VALUES (1, '新しい製品A'); -- OK
NOT NULL制約とDEFAULT句を組み合わせることで、カラムに値が明示的に指定されなかった場合に、自動的にデフォルト値が挿入されるようにできます。これにより、常に値が存在することを保証しつつ、挿入時の手間を省くことが可能です。
-- stock_quantityにDEFAULT 0とNOT NULL制約を追加する例
CREATE TABLE Products (
product_id INT PRIMARY KEY,
product_name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2),
stock_quantity INT NOT NULL DEFAULT 0, -- NOT NULL と DEFAULT の組み合わせ
release_date DATE,
is_available BOOLEAN
);
-- stock_quantityを省略してINSERTしても、自動的に0が挿入される
INSERT INTO Products (product_id, product_name, price, release_date, is_available)
VALUES (2, '新しい製品B', 19.99, '2026-03-01', TRUE);
-- この場合、stock_quantityは0となる
データベースに格納されたデータは、必要に応じて取り出し、加工して利用されます。この「データの取り出しと加工」を行うのが**問合せ(クエリ)**です。SQLでは、主にDML(Data Manipulation Language: データ操作言語)のSELECT文を使ってデータ問合せを行います。
SELECT文は、データベースから特定の条件に合致するデータを抽出し、指定した形式で結果を返すための最も基本的な、しかし最も強力なコマンドです。
ここでは、SELECT文の基本的な使い方から、データの絞り込み、並べ替え、集計といった応用的な問合せ方法について学習していきます。
SELECT文は、テーブルからデータを検索し、その結果を取得するために使用します。基本的な構文は以下の通りです。
SELECT
カラム名1, カラム名2, ...
FROM
テーブル名;
より具体的な例を見るために、以下のProductsテーブルにデータを挿入しておきます。
-- Productsテーブルの定義 (再掲)
-- CREATE TABLE Products (
-- product_id INT PRIMARY KEY,
-- product_name VARCHAR(100) NOT NULL,
-- price DECIMAL(10, 2),
-- stock_quantity INT NOT NULL DEFAULT 0,
-- release_date DATE,
-- is_available BOOLEAN
-- );
-- テストデータ挿入
INSERT INTO Products (product_id, product_name, price, stock_quantity, release_date, is_available) VALUES
(1, 'ラップトップPC', 1200.00, 50, '2025-01-15', TRUE),
(2, 'ワイヤレスマウス', 25.50, 200, '2025-02-01', TRUE),
(3, 'メカニカルキーボード', 75.00, 100, '2025-01-20', TRUE),
(4, 'USBハブ', 12.00, 300, '2025-03-10', TRUE),
(5, '外付けSSD 1TB', 90.00, 70, '2025-02-28', TRUE),
(6, 'Webカメラ', 49.99, 80, '2025-01-05', FALSE),
(7, 'ゲーミングヘッドセット', 60.00, 40, '2025-03-15', TRUE),
(8, 'モニター 27インチ', 250.00, 30, '2025-02-10', FALSE),
(9, 'タブレットスタンド', 15.00, 150, '2025-03-20', TRUE),
(10, 'ポータブル充電器', 35.00, 120, '2025-01-25', TRUE);
SELECT *)テーブル内の全てのカラム、全ての行を取得するには、SELECTの後にアスタリスク(*)を指定します。
SELECT * FROM Products;
実務では、必要なカラムだけを指定するのが良いとされています。SELECT *は手軽ですが、不要なデータを取得することでネットワーク負荷やDBの処理負荷が増える可能性があるため、注意が必要です。
必要なカラム名をカンマ(,)で区切って指定します。
SELECT product_name, price FROM Products;
DISTINCT)特定カラムの値の重複を除いて、一意な値だけを取得したい場合はDISTINCTキーワードを使用します。
SELECT DISTINCT price FROM Products;
DISTINCTは、指定したカラムの組み合わせに対して適用されます。
AS句)取得したカラム名が長く読みにくい場合や、複数のテーブルを結合する際にカラム名が重複する場合などに、一時的に別名(エイリアス)をつけることができます。ASキーワードは省略可能です。
SELECT product_name AS "商品名", price AS 価格 FROM Products;
SELECT句には、カラム名だけでなく、定数や演算式を指定することもできます。
-- 価格に消費税10%を加算した「税込価格」を表示
SELECT product_name, price, price * 1.10 AS "税込価格" FROM Products;
WHERE句は、取得するデータの行を絞り込むための条件を指定します。SELECT文で最も重要な句の一つです。
SELECT カラム名 FROM テーブル名 WHERE 条件式;
| 演算子 | 意味 |
|---|---|
= |
等しい |
<> or != |
等しくない |
> |
より大きい |
< |
より小さい |
>= |
以上 |
<= |
以下 |
-- 価格が100ドル以上の製品を検索
SELECT product_name, price FROM Products WHERE price >= 100.00;
複数の条件を組み合わせるためにAND、OR、NOTを使用します。
AND: 両方の条件が真の場合に真OR: いずれかの条件が真の場合に真NOT: 条件が偽の場合に真ANDはORよりも優先順位が高いため、意図しない結果を避けるために括弧()を使うことが推奨されます。
-- 価格が50ドル以上かつ在庫が100個未満の製品
SELECT product_name, price, stock_quantity FROM Products
WHERE price >= 50.00 AND stock_quantity < 100;
-- 価格が20ドル未満、または在庫が200個以上の製品
SELECT product_name, price, stock_quantity FROM Products
WHERE price < 20.00 OR stock_quantity >= 200;
BETWEEN A AND B: AからBの範囲内(AとBを含む)IN (A, B, C): A、B、Cのいずれかと一致LIKE: 文字列の部分一致検索(%: 0文字以上の任意の文字列, _: 任意の1文字)IS NULL / IS NOT NULL: 値がNULLかどうか-- 価格が50ドルから100ドルの範囲にある製品
SELECT product_name, price FROM Products WHERE price BETWEEN 50.00 AND 100.00;
-- 製品IDが1, 3, 5の製品
SELECT product_id, product_name FROM Products WHERE product_id IN (1, 3, 5);
-- 製品名に「PC」が含まれる製品
SELECT product_name FROM Products WHERE product_name LIKE '%PC%';
ORDER BY句は、取得した結果を特定のカラムの値に基づいて並べ替えるために使用します。
ASC: 昇順(小さい順、A→Z)。デフォルト。DESC: 降順(大きい順、Z→A)。-- 価格が高い順に製品を並べ替え
SELECT product_name, price FROM Products ORDER BY price DESC;
-- 発売日の新しい順、同じ発売日の場合は価格の安い順に並べ替え
SELECT product_name, release_date, price FROM Products ORDER BY release_date DESC, price ASC;
**副問合せ(サブクエリ)**とは、SQL文の中に入れ子で記述されるSELECT文のことです。WHERE句やFROM句、SELECT句など、様々な場所で使用でき、より複雑な問合せを実現します。
副問合せが返す行数や列数によって、いくつかの種類に分けられます。
スカラ副問合せ: 1行1列の単一の値を返す副問合せ。WHERE句で単一の値と比較する場合などに使います。
-- 平均価格より高い価格の製品を検索
SELECT product_name, price FROM Products
WHERE price > (SELECT AVG(price) FROM Products);
複数行副問合せ: 複数行1列の値を返す副問合せ。IN, ANY, ALL演算子と共に使います。
-- 後述するCategoriesテーブルに属する製品IDを検索
SELECT product_name FROM Products
WHERE product_id IN (SELECT product_id FROM OrderDetails WHERE quantity >= 10);
インラインビュー: FROM句の中に記述される副問合せ。結果が一時的なテーブルのように扱われます。
-- 各カテゴリの平均価格を計算し、それを基に製品情報を結合する
SELECT p.product_name, p.price, avg_cat.avg_price
FROM Products p
JOIN (SELECT category_id, AVG(price) as avg_price FROM Products GROUP BY category_id) AS avg_cat
ON p.category_id = avg_cat.category_id;
相関副問合せは、内側の副問合せが外側の主問合せのカラムを参照するタイプの副問合せです。主問合せの行が1行処理されるたびに、その行の値を参照して副問合せが実行されます。
普通の副問合せ: 内側の問合せが単独で実行可能。 相関副問合せ: 内側の問合せが外側の値に依存するため、単独では実行不可。
-- 各製品カテゴリ内で、そのカテゴリの平均価格よりも高い製品を検索
-- (Productsテーブルにcategory_idカラムが存在すると仮定)
SELECT product_name, price, category_id
FROM Products AS p1
WHERE price > (
SELECT AVG(p2.price)
FROM Products AS p2
WHERE p2.category_id = p1.category_id -- 外側のp1を参照
);
この例では、外側のp1テーブルのcategory_idを、内側のp2テーブルの絞り込み条件に使っています。これにより、「自分と同じカテゴリの平均価格」を計算し、比較することが可能になります。
集約関数は、複数の行をまとめて一つの結果を返す関数です。GROUP BY句と組み合わせて使うことが多いですが、単独でも使用できます。
| 関数 | 説明 |
|---|---|
COUNT() |
行数を数える。COUNT(*)は全行、COUNT(カラム名)はNULL以外の行を数える。 |
SUM() |
数値の合計を計算する。 |
AVG() |
数値の平均を計算する。 |
MAX() |
最大値を求める。 |
MIN() |
最小値を求める。 |
-- 製品の総数、価格の合計、平均価格を計算
SELECT COUNT(*), SUM(price), AVG(price) FROM Products;
GROUP BY, HAVING)GROUP BY句は、特定カラムの値が同じ行をグループにまとめ、各グループに対して集約関数を適用します。
HAVING句は、GROUP BYで作成されたグループに対して条件を指定し、結果を絞り込むために使います。WHERE句が行を絞り込むのに対し、HAVING句はグループを絞り込むという違いがあります。
-- 各カテゴリIDごとの製品数と平均価格を計算
-- (Productsテーブルにcategory_idカラムが存在すると仮定)
SELECT category_id, COUNT(product_id), AVG(price)
FROM Products
GROUP BY category_id;
-- 上記の結果から、製品数が3つ以上あるカテゴリのみを抽出
SELECT category_id, COUNT(product_id) AS product_count, AVG(price)
FROM Products
GROUP BY category_id
HAVING COUNT(product_id) >= 3; -- HAVINGでグループを絞り込み
重要: WHERE句はグループ化の前に評価され、HAVING句はグループ化の後に評価されます。
関係代数は、リレーショナルデータベースの操作を数学的に体系化したもので、SQLの理論的な基盤となっています。集合論に基づいており、和 差 積 直積 商などの演算があります。
2つのSELECT文の結果を結合し、重複行を除外して表示します。重複行を含めたい場合はUNION ALLを使用します。
SELECT product_id, product_name FROM Products WHERE price > 100
UNION
SELECT product_id, product_name FROM Products WHERE stock_quantity < 50;
最初のSELECT文の結果から、2番目のSELECT文の結果に含まれる行を除外します。
SELECT product_id, product_name FROM Products WHERE price > 50
EXCEPT
SELECT product_id, product_name FROM Products WHERE stock_quantity < 100;
両方のSELECT文の結果に共通して存在する行のみを返します。
SELECT product_id, product_name FROM Products WHERE price > 50
INTERSECT
SELECT product_id, product_name FROM Products WHERE stock_quantity < 100;
2つのテーブルの全ての行の組み合わせを返します。CROSS JOINキーワードまたはFROM句でテーブルをカンマ区切りにすることで実現できます。
SELECT p.product_name, c.category_name
FROM Products p CROSS JOIN Categories c;
「テーブルAの特定の属性値に紐づく全ての値が、テーブルBに存在する」ような行をテーブルAから見つけ出す演算です。SQLには直接の演算子はありませんが、NOT EXISTSなどを駆使して実現します。これは非常に高度な概念であり、試験でも難問として出題されることがあります。
複数のテーブルを、関連するカラムをキーにして連結し、一つの結果として取得する操作です。結合を理解するために、Categoriesテーブルを新しく定義し、Productsテーブルを更新します。
-- Categoriesテーブル作成
CREATE TABLE Categories (
category_id INT PRIMARY KEY,
category_name VARCHAR(50) NOT NULL
);
INSERT INTO Categories VALUES (1, 'PC本体'), (2, 'PC周辺機器'), (3, 'その他');
-- Productsテーブルにcategory_idカラムを追加
ALTER TABLE Products ADD COLUMN category_id INT;
UPDATE Products SET category_id = 1 WHERE product_id IN (1, 8);
UPDATE Products SET category_id = 2 WHERE product_id IN (2, 3, 4, 5, 6, 7, 9);
UPDATE Products SET category_id = 3 WHERE product_id = 10;
graph TD
Categories -- "1対多" --> Products;
両方のテーブルに存在する、結合キーの値が一致する行だけを返します。
SELECT
p.product_name,
c.category_name
FROM
Products AS p
INNER JOIN
Categories AS c ON p.category_id = c.category_id;
LEFT JOINは左側のテーブルの行を全て返し、右側のテーブルに一致する行がない場合はNULLを返します。RIGHT JOINはその逆です。OUTERは省略可能です。
-- 全ての製品とそのカテゴリ名を表示(カテゴリ未設定の製品も表示)
SELECT p.product_name, c.category_name
FROM Products AS p
LEFT JOIN Categories AS c ON p.category_id = c.category_id;
両方のテーブルの全ての行を返し、一致する行がない場合は互いにNULLを返します。
SELECT p.product_name, c.category_name
FROM Products AS p
FULL OUTER JOIN Categories AS c ON p.category_id = c.category_id;
テーブルに新しい行を追加します。
INSERT INTO Categories (category_id, category_name) VALUES (4, 'ソフトウェア');
既存の行のデータを更新します。WHERE句を忘れると全ての行が更新されるため、絶対に忘れないでください。
UPDATE Products SET price = price * 0.9 WHERE release_date < '2025-02-01';
既存の行を削除します。WHERE句を忘れると全ての行が削除されるため、絶対に忘れないでください。
DELETE FROM Products WHERE is_available = FALSE;
データの矛盾や不正を防ぎ、整合性を保つためのルールです。テーブル作成時や変更時に定義します。
price DECIMAL(10, 2) CHECK (price >= 0)UNIQUEとNOT NULLを組み合わせたもの。行を一意に識別するためのキー。CREATE TABLE Products (
product_id INT PRIMARY KEY,
category_id INT,
...
FOREIGN KEY (category_id) REFERENCES Categories(category_id) -- 参照制約
ON DELETE SET NULL -- 親が消えたらNULLにする
ON UPDATE CASCADE -- 親が更新されたら子も追随する
);
ビューは、一つ以上のテーブルから作られる仮想的なテーブルです。SELECT文をデータベースに保存し、名前を付けたものと考えることができます。
利点:
SELECT文を簡単なビュー名で呼び出せる。CREATE VIEW V_AvailableProducts AS
SELECT product_name, price, category_name
FROM Products p
JOIN Categories c ON p.category_id = c.category_id
WHERE p.is_available = TRUE;
-- ビューを通常のテーブルのように使用
SELECT * FROM V_AvailableProducts WHERE price > 50;
特定の条件を満たすビューは、INSERT, UPDATE, DELETEが可能です。
主な条件:
COUNTなど)、DISTINCT、GROUP BYなどを含まないデータベースにアクセスする主体。CREATE USERで作成します。
CREATE USER 'gemini_user'@'localhost' IDENTIFIED BY 'password';
ユーザがデータベースやそのオブジェクトに対して何ができるかを定義します。GRANTで権限を付与し、REVOKEで剥奪します。
-- gemini_userにProductsテーブルのSELECT権限を付与
GRANT SELECT ON database_name.Products TO 'gemini_user'@'localhost';
-- 全ての権限を付与
GRANT ALL PRIVILEGES ON database_name.* TO 'gemini_user'@'localhost';
-- SELECT権限を剥奪
REVOKE SELECT ON database_name.Products FROM 'gemini_user'@'localhost';
一連のSQL処理をまとめてデータベースに保存し、名前を付けて呼び出せるようにしたものです。
利点:
-- 特定の価格以上の製品を検索するプロシージャ
DELIMITER //
CREATE PROCEDURE GetProductsByPrice(IN min_price DECIMAL(10,2))
BEGIN
SELECT product_name, price FROM Products WHERE price >= min_price;
END //
DELIMITER ;
-- プロシージャの呼び出し
CALL GetProductsByPrice(100.00);
ある製品の価格を「9999.99」のように、小数点以下2桁まで正確に格納する必要があります。この場合、価格を格納するカラムに最も適したデータ型は次のうちどれか。
ア. FLOAT
イ. INT
ウ. VARCHAR(10)
エ. DECIMAL(6, 2)
解答: エ
解説:
DECIMAL(p, s)またはNUMERIC(p, s)は、p(精度)で指定された総桁数を持ち、そのうちs(スケール)で指定された桁数が小数点以下となる、正確な数値を格納するためのデータ型です。通貨のような誤差が許されない値の格納に最適です。
FLOATは浮動小数点数であり、近似値のため誤差が生じる可能性があります。INTは整数しか格納できません。VARCHARは文字列型であり、数値計算には不向きです。SQL文 SELECT 100 * NULL; を実行した結果として正しいものはどれか。
ア. 0
イ. 100
ウ. NULL
エ. エラーが発生する
解答: ウ
解説:
NULLは「不明」を表す特殊な値です。NULLを含む算術演算(+, -, *, /など)の結果は、常にNULLになります。「不明な値」に何を掛けても、結果は「不明」であるという考え方に基づきます。
Productsテーブルから、priceが100以上で、かつis_availableがTRUEである製品を抽出するSQL文のWHERE句として正しいものを完成させなさい。
SELECT product_name, price FROM Products WHERE [ ______ ];
解答: price >= 100 AND is_available = TRUE
解説:
「AかつB」という条件は、AND演算子を用いて表現します。それぞれの条件式をANDで結合することで、両方の条件を満たす行のみを絞り込むことができます。
Productsテーブルの製品を、stock_quantity(在庫数)の多い順に並べ、在庫数が同じ場合はproduct_name(製品名)のアルファベット昇順(A→Z)に並べ替えるORDER BY句を完成させなさい。
SELECT product_name, stock_quantity FROM Products ORDER BY [ ______ ];
解答: stock_quantity DESC, product_name ASC
解説:
ORDER BY句では、複数のカラムをカンマで区切って指定することで、複数のキーで並べ替えが可能です。最初のキー(stock_quantity)で並べ替え、値が同じ行グループ内で次のキー(product_name)で並べ替えます。DESCは降順(多い順)、ASCは昇順(A→Z)を指定します。ASCはデフォルトなので省略可能です。
Productsテーブルの全製品の平均価格をavg_priceという別名で取得するSQL文として正しいものはどれか。
ア. SELECT AVG(price) FROM Products AS avg_price;
イ. SELECT AVG(price) AS avg_price FROM Products;
ウ. SELECT price AS avg_price FROM Products GROUP BY price;
エ. SELECT TOTAL(price) AS avg_price FROM Products;
解答: イ
解説:
平均値を求めるには集約関数AVG()を使用します。カラムの別名はAS句を用いて指定します。
TOTAL()は標準SQLの集約関数ではありません。Productsテーブルをcategory_idでグループ化し、グループ内の製品数が2つ以上あるカテゴリIDとその製品数を取得するSQL文を完成させなさい。
SELECT category_id, COUNT(product_id)
FROM Products
GROUP BY category_id
HAVING [ ______ ];
解答: COUNT(product_id) >= 2
解説:
GROUP BY句で作成したグループに対して条件を指定するにはHAVING句を使用します。WHERE句はグループ化の前に個々の行をフィルタリングするのに対し、HAVING句はグループ化の後に集約関数の結果などを用いてグループをフィルタリングします。
Productsテーブルにおいて、製品ID 4 (USBハブ) の価格と同じ価格の、USBハブ以外の製品名を取得するSQL文を完成させなさい。
SELECT product_name FROM Products
WHERE price = (SELECT price FROM Products WHERE product_id = 4)
AND [ ______ ];
解答: product_id <> 4
解説:
副問合せ (SELECT price FROM Products WHERE product_id = 4) を使って、USBハブの価格(12.00)を取得します。主問合せでは、その価格と一致し、かつ製品IDが4ではない(USBハブ自身を除く)という条件を指定します。
INNER JOINとLEFT JOINの主な違いは何か。簡潔に説明しなさい。
解答:
INNER JOINは両方のテーブルに結合キーが一致する行だけを返すのに対し、LEFT JOINは左側のテーブルの行をすべて返し、右側のテーブルに一致する行がない場合はNULLとして返す。
解説:
INNER JOINは両方のテーブルに共通のデータのみ、LEFT JOIN(外部結合)は片方のテーブルのデータを全て残す、という点が根本的な違いです。
2つのSELECT文の結果セットの共通部分(両方に存在する行)のみを返すSQLの集合演算子は何か。
ア. UNION
イ. EXCEPT (または MINUS)
ウ. INTERSECT
エ. CROSS JOIN
解答: ウ
解説:
UNION: 和集合(重複除く)EXCEPT / MINUS: 差集合INTERSECT: 積集合(共通部分)CROSS JOIN: 直積Productsテーブルからproduct_idが6の行を削除するSQL文として正しいものはどれか。
ア. DROP FROM Products WHERE product_id = 6;
イ. DELETE FROM Products WHERE product_id = 6;
ウ. UPDATE Products WHERE product_id = 6;
エ. REMOVE FROM Products WHERE product_id = 6;
解答: イ
解説:
テーブルから行を削除するにはDELETE文を使用します。DROPはテーブルそのものを削除するDDL文です。REMOVEは標準SQLにはありません。
Productsテーブルのpriceカラムに「価格は0以上でなければならない」というルールを追加したい。テーブル作成時にこのルールを定義する制約は何か。
ア. UNIQUE
イ. PRIMARY KEY
ウ. FOREIGN KEY
エ. CHECK
解答: エ
解説:
CHECK制約は、カラムが満たすべき条件式を定義するためのものです。CHECK (price >= 0)と記述することで、0未満の価格が挿入・更新されるのを防ぐことができます。
ビュー(VIEW)を使用する利点として、適切でないものはどれか。
ア. 複雑な問合せを単純化できる。
イ. ユーザーごとに見せるデータを制限し、セキュリティを向上できる。
ウ. 元のテーブルへのデータ更新速度を大幅に向上させる。
エ. 元のテーブル構造の変更が、ビューを利用するアプリケーションに影響を与えにくくする。
解答: ウ
解説:
ビューは保存されたSELECT文であり、それ自体がデータ更新を高速化するわけではありません。むしろ、複雑なビューに対する問合せは、パフォーマンスが低下することさえあります。ア、イ、エはビューの代表的な利点です。
sales_userというユーザーに、Productsテーブルのデータを更新する権限のみを与えたい。正しいSQL文はどれか。
ア. GRANT UPDATE ON Products TO sales_user;
イ. PERMIT UPDATE ON Products TO sales_user;
ウ. ALLOW UPDATE ON Products TO sales_user;
エ. UPDATE Products FOR sales_user;
解答: ア
解説:
データベースオブジェクトに対する権限をユーザーに付与するにはGRANT文を使用します。構文は GRANT 権限 ON オブジェクト TO ユーザー; となります。
ストアドプロシージャに関する記述として、最も適切なものはどれか。
ア. クライアント側で実行される一連のSQL手続きである。 イ. 複数のSQL文を1回のネットワーク通信で実行できるため、ネットワーク負荷を軽減できる。 ウ. 主にテーブル構造の定義(DDL)を目的として使用される。 エ. 実行のたびにSQLがコンパイルされるため、パフォーマンスは低下する。
解答: イ
解説:
ストアドプロシージャはデータベースサーバ側に保存され、実行されます。事前にコンパイルされるためパフォーマンスが向上し、複数の処理を1回の呼び出し(CALL)で実行できるため、クライアントとサーバ間の通信回数が減り、ネットワーク負荷を軽減します。
Productsテーブルから、product_nameが「キーボード」で終わる製品を検索するWHERE句の条件式として正しいものはどれか。
ア. product_name LIKE 'キーボード_'
イ. product_name LIKE '%キーボード'
ウ. product_name LIKE '_キーボード'
エ. product_name LIKE 'キーボード%'
解答: イ
解説:
LIKE演算子で使われるワイルドカードのうち、%は「0文字以上の任意の文字列」を表します。'%キーボード'とすることで、「キーボード」という文字列で終わる全ての製品名を検索できます。
相関副問合せに関する記述として、最も適切なものはどれか。
ア. 主問合せとは独立して単独で実行できる。
イ. 主問合せの行ごとに繰り返し実行されるため、一般的にパフォーマンスは良くない。
ウ. 主にFROM句でインラインビューとして使用される。
エ. 必ずIN演算子と共に使用する必要がある。
解答: イ
解説:
相関副問合せは、主問合せ(外側)の行の値を参照して副問合せ(内側)が実行されます。そのため、主問合せの行数分だけ副問合せが繰り返し実行されることになり、処理対象の行数が多い場合にはパフォーマンスの低下を招くことがあります。
テーブルの全行を削除する際にDELETE文とTRUNCATE TABLE文では挙動が異なる。その違いについて簡潔に説明しなさい。
解答:
DELETEは行を1行ずつ削除し、その操作はトランザクションログに記録されるため、ロールバックが可能。一方、TRUNCATEはテーブルを再作成するのに近い内部動作で、高速だが操作はロールバックできないことが多い。また、DELETEではWHERE句が使えるが、TRUNCATEは全行削除しかできない。
PRIMARY KEY制約とUNIQUE制約の共通点と相違点を簡潔に説明しなさい。
解答:
PRIMARY KEY制約は暗黙的にNOT NULL制約を含むためNULL値を許可しないが、UNIQUE制約は(多くのDBMSで)NULL値を許可する。また、1つのテーブルにPRIMARY KEYは1つしか設定できないが、UNIQUE制約は複数設定できる。SELECT文において、WHERE句とHAVING句は、論理的にどちらが先に評価されるか。
解答: WHERE句
解説:
SQLの論理的な実行順序では、FROM句で対象テーブルが決定された後、WHERE句で個々の行がフィルタリングされます。その後、GROUP BY句でグループ化が行われ、最後にHAVING句でそのグループがフィルタリングされます。
Productsテーブルには存在するが、Categoriesテーブルにはまだ登録されていないcategory_idを持つ製品(例えば、category_idがNULLの製品)を見つけ出すSQL文を完成させなさい。
SELECT p.product_name, p.category_id
FROM Products p
LEFT JOIN Categories c ON p.category_id = c.category_id
WHERE [ ______ ];
解答: c.category_id IS NULL
解説:
LEFT JOINは左側(Products)のテーブルの行を全て返します。右側(Categories)にcategory_idが一致する行がない場合、右側のテーブルのカラム(c.category_idなど)はNULLになります。したがって、WHERE c.category_id IS NULLという条件を指定することで、カテゴリが存在しない製品を特定できます。
データベースにおける**索引(インデックス)**は、書籍の「索引」や電話帳の「見出し」のようなものです。目的のデータを探し出す時間を劇的に短縮するために使用されます。
テーブルに索引が設定されていない場合、データベースはデータを検索する際に、テーブルの全行を最初から最後まで順に読み込む必要があります(これをフルテーブルスキャンと呼びます)。データ量が少なければ問題ありませんが、数百万、数千万といった膨大なデータの中から特定の行を探し出す場合、フルテーブルスキャンでは非常に時間がかかってしまいます。
索引は、特定のカラムの値と、その値が格納されているデータ行の物理的な位置(ROWIDやポインタなど)を関連付けて管理します。これにより、目的の値を持つ行を直接見つけ出すことができるため、検索(SELECT文)のパフォーマンスが向上します。
| メリット | デメリット |
|---|---|
SELECT文によるデータ検索が高速化される |
INSERT, UPDATE, DELETEが遅くなる(索引の更新) |
ORDER BY句によるソートが高速化される |
ディスク容量を消費する(索引自体のデータ) |
JOIN操作のパフォーマンスが向上する |
DBMSのメモリを消費する |
WHERE句での条件指定が高速化される |
WHERE句の条件として頻繁に使用されるカラムJOINの結合条件として使用されるカラムORDER BY句で並べ替えのキーとして頻繁に使用されるカラムPRIMARY KEYやUNIQUE制約が設定されたカラム(DBMSが自動的に索引を作成することが多い)メリットがあるからといって、無闇に多くの索引を作成するのは避けるべきです。索引の数が増えるほど、データの更新時に索引自体も更新する必要が生じるため、INSERT, UPDATE, DELETEのパフォーマンスが低下します。また、ディスク容量も消費します。
適切な索引設計は、データベースのパフォーマンスチューニングにおいて非常に重要な要素となります。
データベースで最も一般的に使用される索引の構造は**B-Tree(B+Tree)**です。B-Treeはバランスの取れた木構造をしており、どのようなキー値を探す場合でも、ほぼ同じ深さのノードをたどることで高速に目的のデータに到達できます。
B-Treeは以下の要素で構成されます。
graph TD
A["ルートノード"] --> B("ブランチノード");
A --> C("ブランチノード");
B --> D("リーフノード");
B --> E("リーフノード");
C --> F("リーフノード");
C --> G("リーフノード");
D -- "次へ" --> E;
E -- "次へ" --> F;
F -- "次へ" --> G;
subgraph "リーフノード層"
D;
E;
F;
G;
end
B-Treeでの索引探索は、以下のような手順で行われます。
この仕組みにより、大量のデータの中からでも、わずか数回のディスクI/O(ディスクアクセス)で目的のデータにたどり着くことが可能になります。
索引が実際にどのように利用されるかには、いくつかのパターンがあります。
索引一意スキャン (Index Unique Scan)
PRIMARY KEYやUNIQUE制約が設定されたカラムに対して、WHERE句で等価条件(=)が指定された場合に発生します。WHERE product_id = 123索引レンジスキャン (Index Range Scan)
WHERE句で範囲条件(BETWEEN, >, <, >=など)や、LIKE演算子による前方一致検索(LIKE 'Apple%')が指定された場合に発生します。WHERE price BETWEEN 100 AND 200索引フルスキャン (Index Full Scan)
ORDER BY句で索引のカラムが指定されており、かつWHERE句で索引が使えない場合などに、ソート処理を避けるために利用されることがあります。SELECT MIN(product_id) FROM Products;スキップスキャン (Index Skip Scan)
WHERE句で指定されていない場合でも、DBMSが賢く索引の一部をスキップしながら利用する探索方法です。全てのDBMSが対応しているわけではありません。(category_id, product_name)の場合にWHERE product_name = 'PC'索引の論理構造はB-Treeが一般的ですが、物理的なデータの格納方法によって、さらにいくつかの種類があります。
クラスタ化インデックス (Clustered Index)
PRIMARY KEY制約を設定すると、多くのDBMSでは自動的にクラスタ化インデックスが作成されます。非クラスタ化インデックス (Non-Clustered Index)
複合索引 (Composite Index)
CREATE INDEX idx_product_cat_name ON Products (category_id, product_name);
WHERE category_id = 1WHERE category_id = 1 AND product_name = 'PC'WHERE category_id = 1 AND product_name LIKE 'P%'
これらは索引が利用されますが、WHERE product_name = 'PC'では索引が利用されにくい、あるいは利用されない場合があります。カバリングインデックス (Covering Index / 包含インデックス)
SELECT product_id, product_name FROM Products WHERE product_id > 100; (もし(product_id, product_name)で複合索引がある場合)トランザクションとは、データベースにおいて一連の処理を一つの論理的な単位として扱うことを指します。これは「全て実行されるか、全く実行されないか」のどちらかであり、途中で失敗した場合は全ての変更が取り消されます。
例として、銀行口座Aから口座Bへ10,000円を送金する処理を考えます。この処理は以下のステップからなります。
もし1の処理は成功したが、2の処理が失敗した場合、口座Aからはお金が減ったのに口座Bには増えないという矛盾した状態が発生します。このようなデータの不整合を防ぐためにトランザクションが利用されます。
COMMIT: トランザクション内の全ての処理が正常に完了し、変更を確定(データベースに永続的に反映)させる。ROLLBACK: トランザクション内の途中でエラーが発生したり、何らかの理由で処理を中止したりする場合に、トランザクション開始時点の状態に戻す(変更を全て取り消す)。graph LR
A["トランザクション開始"] --> B{"処理1"};
B --> C{"処理2"};
C --> D{"全ての処理成功?"};
D -- "はい" --> E["COMMIT 変更確定"];
D -- "いいえ" --> F["ROLLBACK 変更破棄"];
E --> G["トランザクション終了"];
F --> G;
トランザクションには、その信頼性を保証するための4つの重要な特性があります。これらは頭文字を取ってACID特性と呼ばれます。
Atomicity (原子性)
Consistency (一貫性)
PRIMARY KEY, FOREIGN KEYなど)が破られないなど。Isolation (独立性)
Durability (永続性)
COMMITされたトランザクションによる変更は、システム障害や電源障害などが発生しても失われることなく、データベースに永続的に保存されます。MVCCは「Multi-Version Concurrency Control」の略で、日本語では「多版型同時実行制御」などと訳されます。複数のトランザクションが同時にデータにアクセスする際の競合を減らし、データベースの同時実行性能を高めるための技術です。
従来の排他制御(ロック)では、あるトランザクションがデータを更新している間は、他のトランザクションはそのデータを読み取ることができません(書き込み中に読み取ると不整合が発生するため)。これにより、読み取り中心のシステムでも、書き込みが頻繁に発生すると読み取り処理がブロックされ、性能が低下するという課題がありました。
MVCCでは、データが更新される際に、元のデータを上書きするのではなく、新しいバージョンのデータを作成します。これにより、複数のバージョンのデータがデータベース内に共存することになります。
graph LR
A["データX バージョン1"] --> B{"T1が読み取り開始"};
A --> C{"T2が書き込み開始"};
C --> D["データX バージョン2を生成"];
D --> E["T2 COMMIT"];
B -- "バージョン1を読み取り中" --> F["T1完了"];
PostgreSQLやOracleなどの多くのリレーショナルデータベースでMVCCが採用されています。
排他制御は、複数のトランザクションが同時にデータベースにアクセスした際に、データの整合性を保つための仕組みです。主に**ロック(Lock)**という方法が使われます。
共有ロック (Shared Lock / Sロック)
専有ロック (Exclusive Lock / Xロック)
graph TD
Data["データA"] --> S1{"T1: Sロック要求 _読み取り"};
S1 -- "Sロック取得" --> S2{"T2: Sロック要求 _読み取り"};
S2 -- "Sロック取得" --> X1{"T3: Xロック要求 _書き込み"};
X1 -- "ブロックされる" --> Wait["待機"];
S2 -- "Sロック解除" --> S1解除{"T1, T2: Sロック解除"};
S1解除 --> X1取得{"T3: Xロック取得"};
ロックは、対象となるデータの範囲(粒度)によって、以下のようになります。
一般的に、粒度が細かいほど同時実行性は高まりますが、ロック管理のオーバーヘッドが増加します。DBMSは、問合せの内容やデータ量に応じて、適切な粒度のロックを自動的に選択します。
直列化可能性(Serializable)とは、複数のトランザクションが並行して実行された場合でも、その結果が、あたかもそれらのトランザクションが何らかの順序で一つずつ(直列に)実行された場合と同じになるという保証のことです。これはトランザクションの独立性(Isolation)の最高レベルであり、最も厳格な整合性を保証します。
並行実行時に直列化可能性が保証されていれば、プログラマはあたかもトランザクションが直列に実行されるかのようにアプリケーションを設計・実装できるため、並行処理による複雑な問題を考慮する必要がなくなります。これにより、アプリケーション開発の難易度が下がり、バグの発生を抑えることができます。
直列化可能性は、主に以下の技術によって実現されます。
デッドロックとは、複数のトランザクションが互いに相手がロックしている資源の解放を待ち合い、結果としてどのトランザクションも処理を先に進められなくなる状態のことです。
トランザクションT1とT2が、データAとデータBのロックを要求する例で考えます。
graph TD
T1["トランザクションT1"] -- "データAをロック" --> A("データA");
T2["トランザクションT2"] -- "データBをロック" --> B("データB");
A -- "データBを待機" --> T1;
B -- "データAを待機" --> T2;
結果として、T1はT2がBを解放するのを待ち、T2はT1がAを解放するのを待つという無限ループに陥り、どちらのトランザクションも進行できなくなります。
ほとんどのDBMSはデッドロックを自動的に検出する機能を持っています。デッドロックを検出すると、DBMSは一方のトランザクション(これを**犠牲者(Victim)**と呼びます)を強制的に中断させ、ROLLBACKします。これにより、犠牲者トランザクションがロックしていた資源が解放され、もう一方のトランザクションは処理を続行できるようになります。犠牲者となったトランザクションは、後で再実行されることになります。
デッドロックの発生を完全に防ぐことは難しいですが、以下の対策を講じることで発生頻度を減らすことができます。
トランザクションの独立性(Isolation)は、複数のトランザクションが同時に実行される際に、互いの処理がどの程度影響し合うかを定義するものです。SQL標準では、以下の4つの分離レベル(Isolation Level)が定義されており、それぞれ発生しうる現象(Anomaly)を防ぐ度合いが異なります。
graph TD
SERIALIZABLE --> REPEATABLE_READ;
REPEATABLE_READ --> READ_COMMITTED;
READ_COMMITTED --> READ_UNCOMMITTED;
subgraph "独立性レベル Isolation Levels"
SERIALIZABLE;
REPEATABLE_READ;
READ_COMMITTED;
READ_UNCOMMITTED;
end
subgraph "発生しうる現象 Anomalies"
DIRTY_READ["ダーティリード"];
NON_REPEATABLE_READ["ノンリピータブルリード"];
PHANTOM_READ["ファントムリード"];
end
READ_UNCOMMITTED -- "許容" --> DIRTY_READ;
READ_COMMITTED -- "許容" --> NON_REPEATABLE_READ;
READ_COMMITTED -- "許容" --> PHANTOM_READ;
REPEATABLE_READ -- "許容" --> PHANTOM_READ;
ダーティリード (Dirty Read):
COMMITされていない(ROLLBACKされる可能性がある)他のトランザクション(T2)の変更を読み取ってしまう現象です。ノンリピータブルリード (Non-Repeatable Read):
ファントムリード (Phantom Read):
READ UNCOMMITTED (未コミット読み取り)
READ COMMITTED (コミット済み読み取り)
REPEATABLE READ (反復可能読み取り)
SERIALIZABLE (直列化可能)
適切な分離レベルの選択は、アプリケーションの要件(整合性の厳密さ、パフォーマンス、同時実行性など)に基づいて慎重に行う必要があります。
データベースシステムは、様々な障害(ハードウェア故障、ソフトウェアエラー、電力供給停止など)が発生しても、データを保護し、可能な限り早く正常な状態に復旧できる仕組みを持っています。これが**障害管理(リカバリ)**です。
データベースは、ディスク上のデータファイルとメモリ上のバッファキャッシュ(変更されたデータが一時的に保持される領域)を持っています。更新処理はまずバッファキャッシュ上で行われ、その後非同期的にディスクに書き込まれます。
チェックポイントとは、データベースのバッファキャッシュ内の変更されたデータを強制的にディスク上のデータファイルに書き出す処理のことです。
DBMSは、一定時間ごとや、特定のイベント(例えば、ログファイルのサイズが閾値を超えた時)が発生した際に、自動的にチェックポイント処理を実行します。
データベースシステムは、以下の要素を組み合わせて障害から回復します。
ログファイル(ジャーナル):
データファイル:
バックアップ:
データベース障害発生時、DBMSはログファイルを利用して、データベースを整合性の取れた状態に復旧します。
ロールフォワード (Roll-Forward / REDO):
ロールバック (Roll-Back / UNDO):
これらの仕組みによって、データベースは高い信頼性と可用性を提供しています。
近年、Webサービスやビッグデータの登場により、従来のリレーショナルデータベース(RDBMS)だけでは対応しきれない課題(大量のデータ、高いスケーラビリティ、柔軟なスキーマなど)が浮上しました。これに対応するために登場したのが、**NoSQL(Not only SQL)**と呼ばれる、RDBMS以外の様々なデータストア技術です。
NoSQLは、そのデータモデルによっていくつかの主要なカテゴリに分類されます。
graph TD
NoSQL["NoSQL"] --> KV["Key-Value Store"];
NoSQL --> Doc["Document Store"];
NoSQL --> CF["Column-Family Store"];
NoSQL --> Graph["Graph Database"];
KV -- "例" --> Redis;
KV -- "例" --> DynamoDB;
Doc -- "例" --> MongoDB;
Doc -- "例" --> Couchbase;
CF -- "例" --> Cassandra;
CF -- "例" --> HBase;
Graph -- "例" --> Neo4j;
Key-Value Store (KVS)
Document Store
Column-Family Store
Graph Database
分散データベースとは、一つの論理的なデータベースが、物理的にはネットワークで接続された複数のコンピュータ(ノード)に分散して格納・管理されているシステムのことです。ユーザーからは単一のデータベースのように見えますが、内部ではデータが複数の場所に分割して保持されています。
分散システムにおける重要な概念にCAP定理があります。これは、以下の3つの特性のうち、同時に2つしか完全に満たすことはできない、というものです。
多くの分散データベースやNoSQLシステムは、このCAP定理のトレードオフを考慮し、特定の特性を優先するように設計されています。例えば、可用性と分断耐性を優先し、一貫性を「最終的な一貫性」とするシステムが多く存在します。
データベースにおいて索引(インデックス)を使用する主な目的として、最も適切なものはどれか。
ア. データの重複を自動的に排除するため。
イ. INSERT、UPDATE、DELETEの処理速度を向上させるため。
ウ. SELECT文によるデータ検索の処理速度を向上させるため。
エ. データベースの物理的な容量を削減するため。
解答: ウ
解説:
索引は、特定のカラムの値をキーとしてデータ行へのポインタを管理することで、SELECT文による検索やソート処理を高速化します。データの重複排除は主にPRIMARY KEYやUNIQUE制約の役割であり、INSERT等のDML操作は索引のメンテナンスコストがかかるため遅くなります。索引自体もデータであるため、物理容量は増加します。
B-Tree(B+Tree)索引の構造において、実際のデータ行へのポインタ(ROWIDなど)を格納しているのは主にどのノードか。
ア. ルートノード
イ. ブランチノード
ウ. リーフノード
エ. メタデータノード
解答: ウ
解説:
B-Tree索引では、ルートノードとブランチノードは探索のためのキー値と下位ノードへのポインタを保持し、リーフノードが実際のキー値とデータ行へのポインタを格納しています。リーフノードは通常、範囲検索を効率化するために相互に連結されています。
索引のデメリットとして、適切でないものはどれか。
ア. 索引の作成や再構築に時間がかかる。
イ. SELECT文によるデータ検索が遅くなる。
ウ. INSERT、UPDATE、DELETEなどのデータ変更時に索引の更新が必要となる。
エ. ディスクストレージを消費する。
解答: イ
解説:
索引はSELECT文によるデータ検索を高速化するためのものです。データ検索が遅くなるのは索引のデメリットではありません。索引の作成、更新コスト、ストレージ消費はデメリットです。
クラスタ化インデックス(Clustered Index)に関する説明として、最も適切なものはどれか。
ア. 1つのテーブルに複数作成できる。
イ. 索引のキー順にテーブルのデータ行が物理的に並べ替えられて格納される。
ウ. 常に非クラスタ化インデックスよりも検索性能が優れている。
エ. VARCHAR型のカラムにのみ作成できる。
解答: イ
解説:
クラスタ化インデックスは、索引のキー順にデータ行が物理的に格納されるため、1つのテーブルに1つしか作成できません(アは誤り)。物理的な並び順と索引が一致するため、多くの場合高速ですが、常に非クラスタ化インデックスより優れているとは限りません(ウは誤り)。データ型の制限もありません(エは誤り)。
データベースにおけるトランザクションの最も基本的な性質は何か。
ア. 一連の処理は必ず複数のSQL文で構成される。
イ. 処理の途中でも他のユーザーから変更結果が見える。
ウ. 一連の処理は全て成功するか、全て失敗して元の状態に戻るかのどちらかである。
エ. SELECT文だけがトランザクションの対象となる。
解答: ウ
解説:
トランザクションの原子性(Atomicity)とは、一連の処理が不可分な一つの単位として扱われ、全て実行されるか、全て実行されないかのどちらかであることを意味します。
トランザクションのACID特性のうち、一度コミットされた変更は、システム障害が発生しても失われることなく永続的に保存されることを保証する特性は何か。
ア. 原子性 (Atomicity)
イ. 一貫性 (Consistency)
ウ. 独立性 (Isolation)
エ. 永続性 (Durability)
解答: エ
解説:
永続性(Durability)は、トランザクションが一度コミットされると、その結果は恒久的なものとなり、システム障害が発生しても失われることはない、という特性です。通常、これはログファイルへの書き込みによって保証されます。
MVCC (Multi-Version Concurrency Control) が主に解決しようとするデータベースの課題は何か。簡潔に説明しなさい。
解答:
読み取りと書き込みの競合を減らし、データベースの同時実行性を高めることです。MVCCでは、データ更新時に新しいバージョンを作成することで、読み取りトランザクションが更新中のデータによってブロックされるのを防ぎます。
データベースの排他制御において、あるデータに専有ロック(Xロック)がかかっている場合、他のトランザクションはそのデータに対してどのような操作が可能か。
ア. 読み取りと書き込みの両方が可能。
イ. 読み取りのみ可能。
ウ. 書き込みのみ可能。
エ. 読み取りも書き込みも不可能。
解答: エ
解説:
専有ロック(Xロック)は最も強力なロックであり、対象のデータへの他のトランザクションからの全てのアクセス(読み取り、書き込み)を排他します。これにより、データの一貫性が保たれます。
デッドロックの発生を回避するための一つの方法として、「複数のデータにロックをかける必要がある場合、全てのトランザクションで同じ順序でロックをかける」というものがある。この方法が有効である理由を簡潔に説明しなさい。
解答:
ロックの獲得順序を統一することで、互いに相手がロックしている資源の解放を待ち合うという循環待機状態(デッドロックの必要条件の一つ)が発生するのを防ぐことができるためです。
ダーティリード(Dirty Read)とは、どのような現象か。簡潔に説明しなさい。
解答:
ダーティリードとは、あるトランザクション(T1)が、まだコミットされていない(ロールバックされる可能性がある)他のトランザクション(T2)によって変更されたデータを読み取ってしまう現象です。もしT2がロールバックされた場合、T1は存在しないはずのデータを読み取ったことになり、データの不整合を招きます。
READ COMMITTED分離レベルでは防ぐことができるが、REPEATABLE READ分離レベルでは防ぐことができる現象は何か。
ア. ダーティリード
イ. ノンリピータブルリード
ウ. ファントムリード
エ. デッドロック
解答: イ
解説:
READ COMMITTEDはダーティリードを防ぎますが、ノンリピータブルリード(同じデータを複数回読み取ったときに値が変わる現象)は防げません。REPEATABLE READはダーティリードとノンリピータブルリードの両方を防ぎます。ファントムリードはSERIALIZABLEのみが防ぎます。
データベースの障害回復において、チェックポイント処理の主な目的は何か。
ア. データベースの完全なバックアップを作成するため。
イ. トランザクションログに記録された全ての情報をディスクに書き出すため。
ウ. 障害発生時の復旧にかかる時間を短縮するため。
エ. ユーザーが手動でデータベースの状態を保存するため。
解答: ウ
解説:
チェックポイントは、メモリ上のバッファキャッシュにある変更されたデータをディスクに強制的に書き出す処理です。これにより、障害発生時にチェックポイント以降のログだけを処理すればよくなるため、復旧にかかる時間を短縮できます。
データベースの障害回復において、まだコミットされていない変更をログ情報に基づいて取り消し、トランザクション開始前の状態に戻す処理を何と呼ぶか。
ア. ロールフォワード (Roll-Forward)
イ. ロールバック (Roll-Back)
ウ. コミット (Commit)
エ. チェックポイント (Checkpoint)
解答: イ
解説:
ロールバック(Roll-Back)は、未コミットのトランザクションによる変更をログ(UNDO情報)に基づいて取り消し、データベースをトランザクション開始前の状態に戻す処理です。ロールフォワードはコミット済みの変更を再度適用する処理です。
NoSQLデータベースが登場した主な背景として、適切でないものはどれか。
ア. 膨大な量の非構造化データの処理要求。
イ. 水平スケーラビリティの実現の容易さへの要求。
ウ. 厳格なACID特性の全てを常に必要とするアプリケーションが増加したため。
エ. 柔軟なスキーマを持つデータモデルへの要求。
解答: ウ
解説:
NoSQLは、RDBMSが提供する厳格なACID特性を緩和することで、高い可用性やスケーラビリティ、パフォーマンス、柔軟なスキーマを実現しました。したがって、厳格なACID特性を必要とするアプリケーションが増加したことがNoSQLの背景ではありません。
JSONやBSONのようなドキュメント形式でデータを格納し、柔軟なスキーマを持つNoSQLデータベースのカテゴリは何か。
ア. Key-Value Store
イ. Document Store
ウ. Column-Family Store
エ. Graph Database
解答: イ
解説:
Document Store(ドキュメント指向データベース)は、JSONやBSON形式のドキュメントとしてデータを格納します。MongoDBなどが代表例です。
分散データベースシステムの利点として、適切でないものはどれか。
ア. システムの水平スケーラビリティを高めることができる。
イ. データの局所性を高め、アクセス速度を向上させることができる。
ウ. 障害発生時のデータ復旧プロセスが常に単一のデータベースより単純になる。
エ. 特定のノードに障害が発生しても、システム全体の可用性を維持しやすい。
解答: ウ
解説:
分散データベースでは、データが複数のノードに分散しているため、障害発生時のデータ復旧や整合性維持のプロセスは、単一のデータベースよりもはるかに複雑になります。ア、イ、エは分散データベースの主な利点です。
分散データベースシステムにおいて、CAP定理が示す3つの特性(Consistency, Availability, Partition tolerance)をすべて同時に満たすことはできない。この定理が意味する「Partition tolerance (分断耐性)」とは何か。
解答:
ネットワーク分断(一部のノード間での通信が途絶える状態)が発生しても、システム全体が停止することなく、動作を継続できる能力のことです。分散システムではネットワーク分断が必ず発生しうるため、分断耐性は必須の特性とされます。
カバリングインデックス(Covering Index / 包含インデックス)とはどのような索引か。そのメリットと共に簡潔に説明しなさい。
解答:
カバリングインデックスとは、問合せに必要な全てのカラムが索引自体に含まれている索引のことです。これにより、問合せの実行時にテーブル本体にアクセスする必要がなくなり、索引だけで結果を返せるため、I/Oが削減され、パフォーマンスが大幅に向上します。
データベースのログファイルには、主にREDO情報とUNDO情報が記録されている。それぞれの役割について簡潔に説明しなさい。
解答:
トランザクションの独立性レベルで最も高いSERIALIZABLE(直列化可能)を選択した場合、データの整合性は最大限に保証されるが、その代償としてトレードオフになる要素は何か。
ア. ストレージ消費量
イ. ネットワーク遅延
ウ. 同時実行性
エ. 開発の複雑さ
解答: ウ
解説:
SERIALIZABLEレベルは、最も厳格な分離を提供するため、他のトランザクションとの競合を避けるために強力なロックを多用します。これにより、トランザクション間の待機が増え、同時に実行できるトランザクションの数が減るため、同時実行性が低下する可能性があります。
データベース設計は、システムの要件を分析し、最適なデータベース構造を構築するプロセスです。このプロセスは通常、以下の3つのフェーズで進められます。
概念設計は、データベース設計の最初のステップであり、最も重要なフェーズの一つです。ここでは、特定のデータベースシステム(DBMS)の種類や物理的な実装方法に依存せず、ビジネス要件やユーザーの視点から、必要なデータとその関連性を洗い出し、明確に定義することを目的とします。
概念設計の主要な成果物は、**E-R図(Entity-Relationship Diagram)**です。E-R図は、エンティティ、属性、リレーションシップをグラフィカルに表現したもので、データベースの「青写真」となります。
概念設計をしっかりと行うことで、後続の論理設計や物理設計がスムーズに進み、システムの要件漏れやデータ不整合を防ぐことができます。
**E-R図(Entity-Relationship Diagram: エンティティ関連図)**は、データベースの概念設計において、現実世界に存在する「モノ」や「コト」、それらの「属性」、そして「モノ」や「コト」同士の「関係」を視覚的に表現するための図法です。
E-R図にはいくつかの表記法がありますが、ここでは代表的な要素とその表現方法を紹介します。
エンティティ (Entity: 実体)
属性 (Attribute: 特徴)
リレーションシップ (Relationship: 関係)
多重度 (Cardinality: カーディナリティ)
顧客が製品を注文し、その注文は複数の製品で構成される場合のE-R図をMermaid形式で表現します。
erDiagram
CUSTOMER ||--o{ ORDER : "places"
ORDER ||--o{ ORDER_DETAIL : "includes"
PRODUCT ||--o{ ORDER_DETAIL : "is_part_of"
CUSTOMER {
int customer_id PK
string customer_name
string address
string phone_number
}
ORDER {
int order_id PK
int customer_id FK
date order_date
string status
}
PRODUCT {
int product_id PK
string product_name
decimal price
int stock_quantity
}
ORDER_DETAIL {
int order_id PK, FK
int product_id PK, FK
int quantity
decimal unit_price
}
図の解説:
CUSTOMERはORDERを「places(行う)」関係にあり、「1顧客は0以上の注文を行う」ことを示します(1対多)。ORDERはORDER_DETAILを「includes(含む)」関係にあり、「1注文は1以上の注文明細を含む」ことを示します(1対多)。PRODUCTはORDER_DETAILに「is_part_of(の一部である)」関係にあり、「1製品は0以上の注文明細に含まれる」ことを示します(1対多)。ORDER_DETAILは、ORDERとPRODUCTの間の多対多の関係を解消するために導入されたエンティティです。このE-R図は、データベースに格納すべき情報とその関係性を、誰にでも分かりやすい形で視覚化するのに役立ちます。
**エンティティ(実体)**は、E-R図を構成する最も基本的な要素であり、現実世界における「識別可能な独立したモノやコト」を表します。データベースでは、このエンティティが「テーブル」に対応します。
ビジネス要件やシステム化の対象となる業務を分析する際、以下の点に着目するとエンティティを特定しやすくなります。
エンティティは、その性質によっていくつかの種類に分類できます。
独立エンティティ(主エンティティ):
顧客、製品、従業員、部署従属エンティティ(弱エンティティ):
家族(従業員に従属)、部署履歴(従業員や部署に従属)関連エンティティ(連関エンティティ):
注文明細(注文と製品の多対多を解消)、受講(学生と科目の多対多を解消)エンティティの各インスタンスを一意に識別するための属性または属性の組み合わせを主キーと呼びます。主キーの選定は、データベースの整合性と効率に大きく影響します。
主キーには、現実世界の意味を持つ自然キー(例: 顧客コード、ISBNコード)と、システムが内部的に生成する意味を持たない代理キー(サロゲートキー)(例: 連番のID)があります。
実務では、変更の可能性が低い連番などの代理キーを主キーとし、業務上の識別子をUNIQUE制約付きの候補キーとすることが推奨されることが多いです。
**リレーションシップ(関係)**は、E-R図において、エンティティ間に存在する論理的なつながりや相互作用を示します。このリレーションシップが、データベースにおけるテーブル間の関連性(FOREIGN KEY)に変換されます。
多重度は、リレーションシップの両端において、一方のエンティティの1つのインスタンスが、もう一方のエンティティのいくつのインスタンスと関連を持つことができるかを示します。これは、E-R図で最も重要な情報の1つです。
1対1 (One-to-One: 1:1)
従業員と経歴情報(1人の従業員は1つの経歴情報を持つ、1つの経歴情報は1人の従業員のもの)FOREIGN KEYとして持つ形で表現されます。1対多 (One-to-Many: 1:N)
部署と従業員(1つの部署には複数の従業員が所属するが、1人の従業員は1つの部署にだけ所属する)FOREIGN KEYとして持たせる形で表現されます。多対多 (Many-to-Many: N:M)
学生と科目(1人の学生は複数の科目を履修し、1つの科目には複数の学生が所属する)FOREIGN KEYとして持ち、それらを複合主キーとすることが多いです。多重度と合わせて、リレーションシップの参加が必須(Mandatory)か任意(Optional)かも表現します。
論理設計は、概念設計で作成したE-R図などの概念データモデルを、特定のリレーショナルデータベースの枠組み(リレーショナルモデル)に変換するフェーズです。この段階では、まだ特定のDBMS製品(Oracle, PostgreSQLなど)の具体的な機能には依存しませんが、リレーショナルデータベースの基本的な制約や特性を考慮に入れます。
論理設計は、データベースの長期的な安定性とパフォーマンスに直結する重要なフェーズです。特に「正規化」は、データベーススペシャリスト試験において頻出のテーマであり、深く理解する必要があります。
**関係スキーマ(Relational Schema)**は、リレーショナルデータベースのテーブルの構造を形式的に記述したものです。論理設計の主要な成果物の一つであり、エンティティがテーブル、属性がカラム、リレーションシップが外部キーとして表現されます。
一般的に、以下のような形式で記述されます。
テーブル名 (主キー, 属性1, 属性2, ..., 外部キー1, 外部キー2, ...)
_)を引くか、PKと表記します。FKと表記するか、外部キーであることを注記します。E-R図の例で示したCUSTOMER, ORDER, PRODUCT, ORDER_DETAILエンティティを関係スキーマに変換してみましょう。
CUSTOMERエンティティ:
CUSTOMER (customer_id, customer_name, address, phone_number)
customer_idが主キーPRODUCTエンティティ:
PRODUCT (product_id, product_name, price, stock_quantity)
product_idが主キーORDERエンティティ:
ORDER (order_id, customer_id FK, order_date, status)
order_idが主キーcustomer_idがCUSTOMERテーブルへの外部キーORDER_DETAILエンティティ:
ORDER_DETAIL (order_id FK, product_id FK, quantity, unit_price)
(order_id, product_id)が複合主キーorder_idがORDERテーブルへの外部キーproduct_idがPRODUCTテーブルへの外部キーこのように、E-R図で表現された概念が、リレーショナルモデルの具体的なテーブル構造として定義されます。
**関数従属(Functional Dependency: FD)**は、リレーショナルデータベースの正規化を理解する上で最も重要な概念の一つです。
「属性集合Xが属性集合Yを関数従属する」とは、X -> Yと表記され、属性集合Xの値が一意に決まれば、属性集合Yの値も一意に決まるという関係を意味します。
学籍番号 -> 学生氏名
製品ID -> 製品名
社員番号 -> (社員氏名, 所属部署名)
関数従属は、テーブル内の属性間の論理的な関係を示しており、この関係を分析することで、データの冗長性や更新時の異常(アノマリ)の原因を特定し、正規化へとつなげていきます。
関数従属には、主キーとの関係によって完全関数従属と部分関数従属があります。これらは第2正規形(2NF)を理解する上で重要な概念です。
属性集合Yが属性集合Xに完全関数従属するとは、X -> Y であり、かつXのどの真部分集合(Xの一部)もYを関数従属しない場合をいいます。
例: 注文明細テーブル
ORDER_DETAIL (注文ID PK, 製品ID PK, 数量, 単価)
複合主キーは(注文ID, 製品ID)。
(注文ID, 製品ID) -> 数量
注文IDだけでは数量は決まらないし、製品IDだけでは数量は決まりません。数量は複合主キー(注文ID, 製品ID)に完全関数従属しています。(注文ID, 製品ID) -> 単価
単価も複合主キーに完全関数従属しています。属性集合Yが属性集合Xに部分関数従属するとは、X -> Y であり、かつXの真部分集合(Xの一部)がYを関数従属する場合をいいます。部分関数従属は、第2正規形(2NF)の違反の原因となります。
例: 注文明細テーブル(製品名を含めてしまった場合)
ORDER_DETAIL (注文ID PK, 製品ID PK, 数量, 単価, 製品名)
複合主キーは(注文ID, 製品ID)。
(注文ID, 製品ID) -> 製品名 という関数従属がある。製品ID -> 製品名 という関数従属も存在する。製品名は複合主キー(注文ID, 製品ID)の一部である製品IDにのみ従属しており、部分関数従属であると言えます。このような部分関数従属があると、データに以下のような問題(更新異常)が生じます。
**推移的関数従属(Transitive Functional Dependency)**は、第3正規形(3NF)を理解する上で重要な概念です。
属性集合X、Y、Zが存在し、X -> Y かつ Y -> Z であり、かつYがXの真部分集合ではなく、Yが候補キーではない場合に、ZはXに推移的に関数従属するといいます。
より平易に言えば、主キーではない属性を介して、他の非主キー属性が主キーに従属している状態です。
例: 従業員テーブル
EMPLOYEE (社員ID PK, 社員氏名, 部署ID FK, 部署名, 部署所在地)
主キーは社員ID。
関数従属の関係は以下のようになります。
社員ID -> 社員氏名社員ID -> 部署ID社員ID -> 部署名社員ID -> 部署所在地部署ID -> 部署名 (部署IDが決まれば部署名が決まる)部署ID -> 部署所在地 (部署IDが決まれば部署所在地が決まる)この場合、社員ID -> 部署ID かつ 部署ID -> 部署名 の関係があるため、部署名は社員IDに推移的に関数従属しています。
同様に、部署所在地も社員IDに推移的に関数従属しています。
このような推移的関数従属があると、データに以下のような問題(更新異常)が生じます。
推移的関数従属は、第3正規形(3NF)への正規化によって解消されます。
**アームストロングの公理(Armstrong's Axioms)**は、リレーショナルデータベースにおける関数従属の性質を形式的に記述した一連の規則です。これらの公理を使うことで、ある関数従属の集合から、それに含まれる全ての関数従属を導き出すことができます。
アームストロングの公理は以下の3つの規則(推論規則)から構成されます。
反射律 (Reflexivity)
Yが属性集合Xの部分集合であるならば、XはYを関数従属する(X -> Y)。(社員ID, 社員氏名) -> 社員ID (社員IDと社員氏名が分かれば、社員IDは一意に決まる)増加律 (Augmentation)
X -> Yであるならば、任意の属性集合Zに対して、XZ -> YZである。社員ID -> 社員氏名 であれば、社員ID, 電話番号 -> 社員氏名, 電話番号推移律 (Transitivity)
X -> Yであり、かつY -> Zであるならば、X -> Zである。社員ID -> 部署ID かつ 部署ID -> 部署名 であれば、社員ID -> 部署名これらの3つの公理は「健全(Sound)」であり「完全(Complete)」であることが証明されています。つまり、これらの公理を使って導出される全ての関数従属は正しいものであり、また、正しい全ての関数従属を導出することができます。
アームストロングの公理は、正規化のプロセスで複雑な関数従属関係を分析し、テーブルの分解が必要かどうかを判断するための理論的な基盤を提供します。
**正規化(Normalization)**は、リレーショナルデータベース設計において、データの冗長性(重複)を排除し、データの整合性(一貫性)を保ち、データ操作時(挿入、更新、削除)に発生する不整合(異常: アノマリ)を防ぐために、テーブルの構造を整理(分解)する体系的なプロセスです。
正規化は、いくつかの段階(正規形)を経て行われます。最も基本的な第1正規形から始まり、段階的に厳しくなる条件を満たすようにテーブルを分解していきます。一般的には、第3正規形(3NF)まで達成されていれば、多くのビジネスアプリケーションで十分な整合性が確保されるとされています。
この後のセクションで、各正規形とその特徴、正規化の方法について詳しく見ていきます。
**第1正規形(First Normal Form: 1NF)**は、正規化の最も基本的な段階です。
テーブルが第1正規形であるための条件は以下の通りです。
電話番号1, 電話番号2, 電話番号3といったカラムが存在する場合や、1つのカラムに複数の値(例: カンマ区切りで複数の電話番号)が入っている場合。住所という1つのカラムに「東京都渋谷区1-2-3」と入っている場合、これを「都道府県」「市区町村」「番地」に分割できるため、原子値ではありません。| 顧客ID | 顧客名 | 電話番号1 | 電話番号2 | 電話番号3 |
|---|---|---|---|---|
| 101 | 山田太郎 | 090-XXXX-1111 | 03-YYYY-2222 | |
| 102 | 佐藤花子 | 090-XXXX-3333 |
このテーブルは、電話番号が繰り返しグループとして存在するため、第1正規形ではありません。
繰り返しグループや非原子属性を解消するために、以下のいずれかの方法でテーブルを分解します。
上記の例を第1正規形に変換する:
新しい顧客電話番号テーブルを分離する方法。
顧客テーブル
CUSTOMER (顧客ID PK, 顧客名)顧客電話番号テーブル
CUSTOMER_PHONE (顧客ID PK, 電話番号 PK)| 顧客ID | 顧客名 |
|---|---|
| 101 | 山田太郎 |
| 102 | 佐藤花子 |
| 顧客ID | 電話番号 |
|---|---|
| 101 | 090-XXXX-1111 |
| 101 | 03-YYYY-2222 |
| 102 | 090-XXXX-3333 |
このように分解することで、データの追加、更新、削除が容易になり、冗長性が低減します。
**第2正規形(Second Normal Form: 2NF)**は、第1正規形よりもさらに冗長性を排除するための段階です。
テーブルが第2正規形であるための条件は以下の通りです。
注文明細と製品情報が一緒になったテーブルを考えます。
ORDER_DETAIL_PRODUCT (注文ID PK, 製品ID PK, 数量, 単価, 製品名, 製品説明)
主キーは複合主キー(注文ID, 製品ID)です。
ここで、以下の関数従属を考えます。
(注文ID, 製品ID) -> 数量 (完全に従属)(注文ID, 製品ID) -> 単価 (完全に従属)製品ID -> 製品名 (主キーの一部にのみ従属)製品ID -> 製品説明 (主キーの一部にのみ従属)製品名と製品説明は、複合主キー(注文ID, 製品ID)全体ではなく、その一部である製品IDにのみ関数従属しています。これは部分関数従属であり、このテーブルは第2正規形ではありません。
ORDER_DETAIL_PRODUCTテーブルに挿入できない(注文IDがないため)。部分関数従属が存在する場合、その部分関数従属を形成している属性(主キーの一部と、それに従属する非キー属性)を新しいテーブルとして分離します。
上記の例を第2正規形に変換する:
注文明細テーブル
ORDER_DETAIL (注文ID PK, 製品ID PK, 数量, 単価)製品テーブル
PRODUCT (製品ID PK, 製品名, 製品説明)製品テーブルの主キー製品IDは、注文明細テーブルでは外部キーとして参照されます。
このように分解することで、データの重複が排除され、更新異常などの問題が解消されます。
**第3正規形(Third Normal Form: 3NF)**は、第2正規形よりもさらに冗長性を排除するための段階です。多くの実用的なデータベース設計では、第3正規形が目標とされます。
テーブルが第3正規形であるための条件は以下の通りです。
第2正規形を満たしているが、第3正規形ではない従業員テーブルを考えます。
EMPLOYEE (社員ID PK, 社員氏名, 部署ID FK, 部署名, 部署所在地)
主キーは社員ID。
ここで、以下の関数従属を考えます。
社員ID -> 社員氏名社員ID -> 部署ID社員ID -> 部署名社員ID -> 部署所在地部署ID -> 部署名 (部署IDが決まれば部署名が決まる)部署ID -> 部署所在地 (部署IDが決まれば部署所在地が決まる)部署名と部署所在地は、主キー社員IDに直接従属しているのではなく、非キー属性である部署IDを介して従属しています(社員ID -> 部署ID -> 部署名)。これは推移的関数従属であり、このテーブルは第3正規形ではありません。
EMPLOYEEテーブルに挿入できない。推移的関数従属が存在する場合、その推移的関数従属を形成している属性(非キー属性と、それに従属する非キー属性)を新しいテーブルとして分離します。
上記の例を第3正規形に変換する:
従業員テーブル
EMPLOYEE (社員ID PK, 社員氏名, 部署ID FK)部署テーブル
DEPARTMENT (部署ID PK, 部署名, 部署所在地)部署テーブルの主キー部署IDは、従業員テーブルでは外部キーとして参照されます。
このように分解することで、データの重複が排除され、更新異常などの問題が解消されます。
第3正規形までがデータベース設計で一般的に目指される正規化のレベルですが、さらに高度な正規形も存在します。これらは特定の状況下でのみ考慮されることが多く、実務では3NFが達成されていれば十分とされることが多いです。
ボイス・コッド正規形 (Boyce-Codd Normal Form: BCNF)
第4正規形 (Fourth Normal Form: 4NF)
第5正規形 (Fifth Normal Form: 5NF)
メリット:
デメリット:
このため、実務では、パフォーマンスと整合性のバランスを取り、**意図的に非正規化(Denormalization)**を行うこともあります。これは、通常、読取性能の向上を目的として、更新異常のリスクを許容しながら冗長なデータをあえて持たせる設計手法です。しかし、非正規化は慎重に、そしてリスクを理解した上で行うべきです。
データベース設計における概念設計の主な目的として、最も適切なものはどれか。
ア. 特定のDBMSの物理的な記憶構造を定義すること。
イ. ビジネス要件から必要なデータとその関連性を抽出し、DBMSに依存しないデータモデルを作成すること。
ウ. SQL文のパフォーマンスを最大化するためのインデックスを設計すること。
エ. 既存のテーブルを統合し、データ冗長性を意図的に増やすこと。
解答: イ
解説:
概念設計は、データベース設計の最初のフェーズであり、ユーザーの視点から現実世界の情報を抽象化してデータモデルを作成します。特定のDBMSに依存せず、ビジネス要件を正確に反映したデータ構造を定義することが目的です。
E-R図において、エンティティ(実体)を表すために一般的に使用される記号はどれか。
ア. ひし形(菱形)
イ. 楕円形
ウ. 長方形
エ. 矢印
解答: ウ
解説:
E-R図の一般的な表記法では、エンティティは長方形で、属性は楕円形で、リレーションシップはひし形で表されます。
「1つの部署には複数の従業員が所属するが、1人の従業員は1つの部署にだけ所属する」という関係の多重度(カーディナリティ)は何か。
ア. 1対1 (One-to-One)
イ. 1対多 (One-to-Many)
ウ. 多対多 (Many-to-Many)
エ. 多対1 (Many-to-One)
解答: イ
解説:
この関係は、部署側から見れば「1つの部署に複数の従業員」なので「多」、従業員側から見れば「1人の従業員は1つの部署」なので「1」です。したがって「1対多」の関係となります。
E-R図で表現された「1対多」のリレーションシップをリレーショナルデータベースで表現する際、一般的にどのような方法がとられるか。
ア. 独立した関連テーブルを作成する。
イ. 「多」側のテーブルに「1」側のテーブルの主キーを外部キーとして持たせる。
ウ. 「1」側のテーブルに「多」側のテーブルの主キーを外部キーとして持たせる。
エ. 両方のテーブルを統合し、単一のテーブルとする。
解答: イ
解説:
1対多の関係では、「多」側のエンティティ(例えば従業員)が「1」側のエンティティ(例えば部署)の主キーを外部キーとして持つことで、関連を表現します。
データベース設計における論理設計の主な目的として、最も適切なものはどれか。
ア. 業務要件を抽出し、E-R図を作成すること。
イ. 特定のDBMS製品を選択し、その設定を行うこと。
ウ. 関係スキーマを定義し、データの冗長性を排除すること。
エ. ディスク容量やアクセス方法などの物理的な側面を考慮すること。
解答: ウ
解説:
論理設計は、概念設計で作成したE-R図をリレーショナルモデルに変換し、正規化を通じてデータの冗長性を排除し、整合性を確保することが主な目的です。
「属性集合Xの値が一意に決まれば、属性集合Yの値も一意に決まる」という関係を何と呼ぶか。
ア. 多値従属
イ. 結合従属
ウ. 関数従属
エ. 候補キー
解答: ウ
解説:
この定義は関数従属(Functional Dependency)そのものです。X -> Yと表記されます。
以下のORDER_DETAIL_PRODUCTテーブルを考える。
ORDER_DETAIL_PRODUCT (注文ID PK, 製品ID PK, 数量, 単価, 製品名, 製品説明)
このテーブルの主キーは(注文ID, 製品ID)である。このテーブルにおいて、第2正規形(2NF)に違反する原因となる「部分関数従属」の例として最も適切なものはどれか。
ア. 注文ID -> 数量
イ. (注文ID, 製品ID) -> 単価
ウ. 製品ID -> 製品名
エ. 注文ID -> 製品名
解答: ウ
解説:
部分関数従属とは、複合主キーの一部に非キー属性が関数従属している状態です。
製品名は主キー全体(注文ID, 製品ID)ではなく、主キーの一部である製品IDのみに決定されます(製品ID -> 製品名)。これは部分関数従属です。
以下のEMPLOYEEテーブルを考える。
EMPLOYEE (社員ID PK, 社員氏名, 部署ID FK, 部署名)
このテーブルの主キーは社員IDである。このテーブルにおいて、第3正規形(3NF)に違反する原因となる「推移的関数従属」の例として最も適切なものはどれか。
ア. 社員ID -> 社員氏名
イ. 部署ID -> 部署名
ウ. 社員ID -> 部署名
エ. 社員ID -> 部署ID
解答: ウ
解説:
推移的関数従属とは、主キーではない属性を介して、他の非主キー属性が主キーに従属している状態です。この場合、社員ID -> 部署ID かつ 部署ID -> 部署名 の関係があるため、部署名は社員IDに推移的に関数従属しています。
アームストロングの公理のうち、「もしX -> Yであり、かつY -> Zであるならば、X -> Zである」と述べられている規則は何か。
ア. 反射律 (Reflexivity)
イ. 増加律 (Augmentation)
ウ. 推移律 (Transitivity)
エ. 分解律 (Decomposition)
解答: ウ
解説:
これはアームストロングの公理の推移律です。関数従属が連鎖的に発生することを示しています。
データベースの正規化を行う主な目的として、最も適切でないものはどれか。
ア. データの冗長性を排除するため。
イ. 更新・挿入・削除異常を防止するため。
ウ. データベースの物理的なアクセス速度を必ず向上させるため。
エ. データ整合性を確保し、データモデルを明確にするため。
解答: ウ
解説:
正規化の主要な目的はデータの冗長性排除と整合性確保です。正規化によってテーブルが分解され、結合操作が増えることで、むしろ物理的なアクセス速度(パフォーマンス)が低下する可能性もあります。そのため、意図的に非正規化を行うこともあります。
テーブルが第1正規形(1NF)であるための条件は何か。簡潔に説明しなさい。
解答:
繰り返しグループ(繰り返し属性)がないこと、および全ての属性が原子値(それ以上分割できない最小単位)であることです。つまり、1つのセルには単一の不可分な値のみが格納されている状態を指します。
以下の学生履修テーブルは第1正規形を満たしているが、第2正規形ではない。これを第2正規形に変換する際、どのようにテーブルを分解すべきか。
STUDENT_COURSE (学生ID PK, 科目ID PK, 学生氏名, 科目名, 履修日)
解答:
このテーブルには以下の部分関数従属が存在する。
学生ID -> 学生氏名科目ID -> 科目名これらを解消するために、テーブルを以下のように分解する。
学生テーブル: STUDENT (学生ID PK, 学生氏名)科目テーブル: COURSE (科目ID PK, 科目名)履修テーブル: ENROLLMENT (学生ID PK, FK, 科目ID PK, FK, 履修日)以下の社員テーブルは第2正規形を満たしているが、第3正規形ではない。これを第3正規形に変換する際、どのようにテーブルを分解すべきか。
EMPLOYEE (社員ID PK, 社員氏名, 部署ID FK, 部署名, 部署所在地)
解答:
このテーブルには以下の推移的関数従属が存在する。
社員ID -> 部署ID -> 部署名社員ID -> 部署ID -> 部署所在地これらを解消するために、テーブルを以下のように分解する。
社員テーブル: EMPLOYEE (社員ID PK, 社員氏名, 部署ID FK)部署テーブル: DEPARTMENT (部署ID PK, 部署名, 部署所在地)正規化を進めることによって得られるメリットを2つ挙げなさい。
解答例:
データベースの**非正規化(Denormalization)**とは何か。その主な目的も合わせて簡潔に説明しなさい。
解答:
非正規化とは、正規化されたデータベースのテーブルを、意図的に冗長な形に戻したり、テーブルを結合したりする設計手法です。主な目的は、結合操作の回数を減らすことで、特に読み取り性能(クエリのパフォーマンス)を向上させることです。データの整合性維持が難しくなるというデメリットがあります。
テーブル内の属性(カラム)または属性の集合で、行を一意に識別できる最小のものを何と呼ぶか。
ア. 主キー (Primary Key)
イ. 外部キー (Foreign Key)
ウ. 候補キー (Candidate Key)
エ. 副キー (Alternate Key)
解答: ウ
解説:
候補キーは、テーブル内の行を一意に識別できる属性(または属性の集合)で、それ以上属性を減らすと一意性を失う「最小の」ものです。主キーはその候補キーの中から一つ選ばれたものです。
E-R図において「多対多」のリレーションシップが存在する場合、論理設計でリレーショナルスキーマに変換する際、どのように表現されるか。
解答:
「多対多」のリレーションシップは、直接リレーショナルスキーマに変換できないため、間に**関連エンティティ(連関エンティティ)**を導入し、それを新しいテーブルとして表現します。この関連エンティティは、元の2つのエンティティの主キーを外部キーとして持ち、それらを複合主キーとすることが一般的です。
E-R図で属性(Attribute)を表すために使用される記号は何か。また、主キーとなる属性を表す際の一般的な慣習も合わせて述べなさい。
解答:
属性は一般的に楕円形で表されます。簡略化されたE-R図では、エンティティの長方形の中に直接属性名を列挙することもあります。主キーとなる属性を表す際は、属性名に下線を引くのが一般的な慣習です。
論理設計と物理設計の主な違いは何か。簡潔に説明しなさい。
解答:
論理設計は、概念設計の成果物をリレーショナルモデルに変換し、正規化を通じてデータの冗長性を排除するフェーズで、特定のDBMSに依存しない。一方、物理設計は、論理設計の成果物を基に、選択したDBMSの特性(インデックス、パーティショニング、記憶域パラメータなど)を考慮し、物理的なデータの格納方法やアクセス方法を具体的に決定するフェーズである。
テーブルが第3正規形(3NF)であるための条件を2つ挙げなさい。
解答:
第2章で、索引(インデックス)はデータベースの検索性能を向上させるために不可欠な要素であると学びました。物理設計のフェーズでは、この索引をどのように設計し、実装すれば、アプリケーションの性能要件を満たせるかを具体的に検討します。
午後試験では、与えられた業務要件やSQLの実行計画(EXPLAINの結果など)を分析し、最適な索引を提案する問題が頻繁に出題されます。ここでは、特に試験で問われやすい索引の設計と、その利用条件について深く掘り下げていきます。
複合索引とは、複数のカラム(列)を組み合わせて作成される索引のことです。単一のカラムに作成される索引よりも、特定の種類のクエリにおいて高い効果を発揮します。
複合索引の設計で最も重要なのは、索引を構成するカラムの順序です。この順序によって、索引が利用できるクエリの範囲が大きく変わります。
複合索引は、その構成カラムの先頭から連続した部分に対して前方一致で利用されます。これを**前方一致の原則(Left-most Prefix Rule)**と呼びます。
例えば、Productsテーブルに(category_id, product_name, price)という複合索引を作成した場合を考えます。
CREATE INDEX idx_products_cat_name_price ON Products (category_id, product_name, price);
この索引は、以下の条件を持つクエリで利用可能です。
WHERE category_id = ? (先頭カラムのみ)WHERE category_id = ? AND product_name = ? (先頭2カラム)WHERE category_id = ? AND product_name = ? AND price = ? (全カラム)一方、以下の条件を持つクエリでは、この複合索引は利用されないか、限定的にしか利用されません。
WHERE product_name = ? (先頭カラムcategory_idが含まれない)WHERE price = ? (先頭カラムcategory_idが含まれない)WHERE product_name = ? AND price = ? (先頭カラムcategory_idが含まれない)WHERE category_id = 1 AND product_name LIKE 'A%' のように、複数の条件でデータを絞り込む場合に有効です。この場合、複合索引の先頭にcategory_id、次にproduct_nameを配置することで効率的な検索が期待できます。ORDER BY category_id, product_name のように、ORDER BY句で複数のカラムが指定されている場合、その順序で複合索引を作成することで、データベースがソート処理を行う手間を省き、高速化につながります。SELECT句に含まれる全てのカラムが複合索引の中に含まれている場合、テーブル本体にアクセスすることなく、索引だけで問合せが完結するため、非常に高い性能を発揮します。午後試験では、以下のような形で複合索引の知識が問われることが多いです。
EXPLAINの結果から、フルテーブルスキャンが発生している原因を特定し、それを解消するための最適な複合索引を提案する。単に「索引を作成する」だけでなく、「どのような索引を、なぜ、どの順序で作成するのか」を明確に説明できるようになることが重要です。
索引はデータベースの検索性能を向上させる強力なツールですが、常に利用されるわけではありません。間違った設計や条件の指定方法により、せっかく作成した索引がデータベースから利用されず、フルテーブルスキャンが発生して性能問題を引き起こすことがあります。
前方一致の原則の不遵守:
WHERE句の条件に含まれていない場合、その索引は利用されないか、非常に限定的な利用にとどまります。idx_products_cat_name_price (category_id, product_name, price)があるのに WHERE product_name = 'PC' で検索した場合。インデックスのカーディナリティが低い場合:
テーブルのデータ量が少ない場合:
OR条件での結合:
WHERE条件をORで結合した場合、各条件に単独で索引が効いていても、それらの索引を組み合わせることが難しい場合があり、フルテーブルスキャンに切り替わることがあります(DBMSやSQLの書き方による)。複合索引の順序の他に、SQLの記述方法やデータ型によっても索引が利用されないことがあります。
索引カラムへの関数適用:
WHERE句で索引が設定されているカラムに対して関数を適用すると、索引は利用されません。オプティマイザは関数の戻り値の評価結果がどうなるか事前に予測できないためです。WHERE SUBSTR(product_name, 1, 1) = 'A' (product_nameに索引があっても使われない)WHERE product_name LIKE 'A%' のように、関数を使わずに索引が利用できる形に条件を書き換える。データ型の不一致:
WHERE句で索引カラムのデータ型と異なるデータ型の値を比較した場合、暗黙的な型変換が発生し、索引が利用されないことがあります。WHERE product_id = '123' (product_idがINT型の場合)WHERE product_id = 123 のように、正しいデータ型で比較する。NOT演算子の使用:
NOT、!=、<>などの否定条件は、多くのレコードが条件に合致する場合、索引が利用されないことがあります。例えば、「〜ではない」という条件は、ほとんど全てのレコードが合致するため、索引を使うよりもフルテーブルスキャンの方が効率的と判断される場合があるためです。WHERE NOT is_available = FALSE (is_available = TRUEと書き換えるべき)ワイルドカード(%や_)を先頭に使用したLIKE検索:
WHERE product_name LIKE '%PC' や WHERE product_name LIKE '_PC' のように、ワイルドカードが検索文字列の先頭にある場合、B-Tree索引の順序性を利用できないため、索引は利用されません。LIKE 'PC%')に限定するか、全文検索機能の利用を検討する。オプティマイザの統計情報が古い:
ANALYZE TABLE, GATHER STATSなどのコマンドを使用)。**クラスタ率(Clustering Factor)**とは、テーブルの物理的な格納順序が、特定の索引の論理的な順序とどの程度一致しているかを示す指標です。索引の効率性、特に範囲検索の性能に大きく影響します。
Ordersテーブルに(order_date)という索引があり、物理的なデータもorder_date順に格納されていればクラスタ率は高いです。
しかし、Ordersテーブルがcustomer_id順に物理的に格納されている場合、order_date索引に対するクラスタ率は低くなります。order_dateの範囲検索をすると、customer_idの異なる多くのブロックからデータを読み込む必要があるため、I/Oが増えます。
午後試験では、「特定の索引のクラスタ率が低いことが原因で性能劣化が起きている」というシナリオが提示され、それを改善するための方法を問われることがあります。
ALTER TABLE MOVEやOPTIMIZE TABLEなどのコマンドを使って、テーブルの物理的な格納順序を、使用頻度の高い索引の順序に合わせて再編成します。ただし、クラスタ化インデックス(Clustered Index)が存在する場合は、そのキー順に物理的に並べられるため、その索引のクラスタ率は常に高くなります。**表領域(Tablespace)**は、データベースにおける物理的な記憶領域を論理的に管理するための単位です。データベース全体をいくつかの表領域に分割し、それぞれの表領域を一つ以上のデータファイルに割り当てます。
ページ(Page)、または**ブロック(Block)**は、データベースにおけるディスクI/Oの最小単位です。データベースがディスクからデータを読み込む際や、ディスクにデータを書き込む際は、必ずこのページ単位で行われます。
データベースのページ内には、将来のデータ挿入や更新に備えて**空き領域(Free Space)**を確保しておくことが重要です。
PCTFREE, PCTUSEDなど)多くのDBMSでは、ページ内の空き領域を管理するためのパラメータを提供しています。
PCTFREE: ページにデータがどれだけ格納されたら、それ以降はINSERTを許可しないかの割合(例: PCTFREE 10なら、ページ容量の90%がデータで埋まったらINSERT停止)。
PCTUSED: ページの使用率がこの値を下回ったら、そのページをINSERT可能な空きページリストに戻す割合(例: PCTUSED 40なら、ページ使用率が40%未満になったらINSERT許可)。
PCTFREEの制限を超えると、行全体が別の空きページに移動(マイグレーション)したり、データが複数ページに分割(チェイニング)されたりすることがあります。これらはディスクI/Oを増やし、パフォーマンスを低下させる原因となります。午後試験では、PCTFREEやPCTUSEDの値を調整することで、更新頻度の高いテーブルや挿入頻度の高いテーブルのI/O性能をどのように改善するか、といった形で問われることがあります。
区分化(Partitioning: パーティショニング)とは、非常に大きなテーブルや索引を、論理的または物理的に小さく分割し、管理しやすくする技術です。ユーザーからは一つのテーブルに見えますが、内部的には複数のパーティションに分割されています。
WHERE句の条件に基づいて、アクセスする必要のないパーティションをスキップし、必要なパーティションにのみアクセスするため、検索範囲が狭まり高速化します。区分化には、データをどのように分割するかに応じていくつかの種類があります。
レンジ区分化 (Range Partitioning)
リスト区分化 (List Partitioning)
ハッシュ区分化 (Hash Partitioning)
コンポジット区分化 (Composite Partitioning)
午後試験では、大量データを扱うシステムの性能問題(例: 特定期間のデータ検索が遅い)や運用管理問題(例: 古いデータの削除に時間がかかる)が提示され、それを区分化によってどのように解決するかを問われることがあります。パーティションキーの選定理由や、パーティションの種類とメリット・デメリットを具体的に説明できるように準備しておきましょう。
**共通テーブル式(CTE)**は、WITH句を使用して定義する一時的な名前付き結果セットです。SELECT, INSERT, UPDATE, DELETE文の中で使用できます。CTEはクエリの読みやすさと保守性を向上させ、複雑なクエリを段階的に構築するのに役立ちます。
WITH CTE名 AS (
SELECT ...
)
SELECT ...
FROM CTE名
WHERE ...;
-- 平均価格より高い製品を、共通テーブル式を使って検索
WITH AveragePrice AS (
SELECT AVG(price) AS avg_p FROM Products
)
SELECT p.product_name, p.price
FROM Products p, AveragePrice ap
WHERE p.price > ap.avg_p;
午後試験では、複雑な集計や階層構造のデータを扱うSQLの問題で、CTEを使った解答が求められたり、CTEの活用によるクエリの改善点を問われたりすることがあります。特に再帰CTEは、部品構成表などの問題で出題される可能性があります。
ウィンドウ関数は、SELECT文のOVER句と組み合わせて使用され、**現在の行に関連する行のグループ(ウィンドウ)**に対して集計や順位付けなどの計算を行うSQL関数です。GROUP BY句による集約と異なり、ウィンドウ関数は元の行を減らすことなく、各行に対して集計結果などを付加できるのが特徴です。
ウィンドウ関数名 ([引数]) OVER (
[PARTITION BY カラム名, ...] -- ウィンドウ(グループ)の定義
[ORDER BY カラム名 [ASC|DESC], ...] -- ウィンドウ内の行の順序
[ROWS/RANGE BETWEEN ...] -- ウィンドウの範囲(オプション)
)
PARTITION BY句を使うことで、特定のカラムの値に基づいて行を区分(パーティション)し、その区分ごとに集計関数を適用できます。
-- 各製品のカテゴリごとの平均価格を、製品ごとに表示
SELECT
product_name,
category_id,
price,
AVG(price) OVER (PARTITION BY category_id) AS avg_price_in_category
FROM
Products;
このクエリでは、category_idが同じ製品同士で平均価格を計算し、その結果を各製品の行に付加します。
ROWS BETWEEN句を使うことで、ウィンドウ内の現在の行の前後の特定の範囲の行に対して集計を行うことができます。移動平均(Moving Average)の計算などに使われます。
-- 発売日順で、その製品と直近2つの製品の平均価格(3製品移動平均)を計算
SELECT
release_date,
product_name,
price,
AVG(price) OVER (ORDER BY release_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg_price
FROM
Products;
ROWS BETWEEN 2 PRECEDING AND CURRENT ROWは、現在の行とその前の2行(計3行)をウィンドウの範囲とします。
LAG()やLEAD()関数を使うと、ウィンドウ内で指定した順序に基づき、現在の行の前の行や後の行のカラム値を取得できます。時系列データの比較などに非常に便利です。
-- 発売日順で、前の製品の価格と現在の製品の価格の差を表示
SELECT
release_date,
product_name,
price,
LAG(price, 1, 0) OVER (ORDER BY release_date) AS previous_price, -- 1行前のprice、無ければ0
price - LAG(price, 1, 0) OVER (ORDER BY release_date) AS price_difference
FROM
Products;
RANK(), DENSE_RANK(), ROW_NUMBER()などの関数を使って、ウィンドウ内で順位を付けることができます。
ROW_NUMBER(): 単純な行番号。重複があっても連番。RANK(): 同じ値には同じ順位を付け、次の順位は重複した数だけスキップされる。DENSE_RANK(): 同じ値には同じ順位を付け、次の順位はスキップされずに連続する。-- 各カテゴリ内で価格の高い順に製品の順位を付ける
SELECT
product_name,
category_id,
price,
RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS rank_in_category
FROM
Products;
NTILE(n)関数は、ウィンドウ内の行をn個のグループに均等に分割し、各行がどのグループに属するかを示す番号を返します。
-- 全製品を価格でソートし、4つの階級に分ける
SELECT
product_name,
price,
NTILE(4) OVER (ORDER BY price DESC) AS price_quartile
FROM
Products;
ウィンドウ関数は、複雑な集計や分析をSQL単体で記述できる強力な機能であり、午後試験でも非常に頻繁に出題されます。特に、「期間を指定した集計」「前後のデータとの比較」「順位付け」といった要件に対して、適切にウィンドウ関数を活用できるかが問われます。PARTITION BY、ORDER BY、ROWS BETWEENの組み合わせを理解し、使いこなすことが重要です。
**トリガー(Trigger)**は、データベース内で特定のイベント(INSERT, UPDATE, DELETEなどのDML操作)が発生した際に、自動的に実行される特別なストアドプロシージャのようなものです。データの整合性保証や監査ログの記録など、様々な用途で利用されます。
CREATE TRIGGER トリガー名
{BEFORE | AFTER} {INSERT | UPDATE | DELETE} ON テーブル名
[FOR EACH ROW] -- 各行に対して実行 (ROWトリガー) / ステートメント全体に対して実行 (STATEMENTトリガー)
[WHEN 条件式] -- オプション: トリガーを起動する条件
BEGIN
-- トリガーが実行されるSQL文や手続き
END;
OLD, NEW)行レベルトリガー(FOR EACH ROW)の場合、INSERT、UPDATE、DELETEの対象となる行の変更前と変更後の値を参照できます。参照にはDBMS固有のキーワード(例: Oracleでは:OLD, :NEW、PostgreSQLではOLD, NEW、MySQLではOLD. NEW.)を使用します。
NEW: 挿入される行、または更新後の行の値を参照。OLD: 削除される行、または更新前の行の値を参照。-- Productsテーブルの価格が更新された際に、変更履歴を記録するトリガー (PostgreSQL/Oracle風)
CREATE TRIGGER trg_product_price_history
AFTER UPDATE OF price ON Products
FOR EACH ROW
BEGIN
INSERT INTO ProductPriceHistory (product_id, old_price, new_price, change_date)
VALUES (OLD.product_id, OLD.price, NEW.price, CURRENT_DATE);
END;
UPDATEトリガーの場合、OF カラム名句を使用することで、特定のカラムが更新された場合にのみトリガーを起動させることができます。これにより、不要なトリガーの実行を防ぎ、パフォーマンスを向上させます。
-- Productsテーブルのpriceカラムが更新された時だけトリガーを起動
CREATE TRIGGER trg_product_price_check
BEFORE UPDATE OF price ON Products -- priceカラムが更新された時のみ
FOR EACH ROW
BEGIN
IF NEW.price < 0 THEN
RAISE EXCEPTION '価格は0以上である必要があります。';
END IF;
END;
WHEN句)WHEN句を使用すると、トリガーが起動する直前に追加の条件を指定できます。WHEN句の条件が真と評価された場合にのみ、トリガー本体の処理が実行されます。
-- Productsテーブルの在庫数が減少した場合のみ、監査ログを記録
CREATE TRIGGER trg_stock_decrease_audit
AFTER UPDATE OF stock_quantity ON Products
FOR EACH ROW
WHEN (NEW.stock_quantity < OLD.stock_quantity) -- 在庫が減った場合のみ起動
BEGIN
INSERT INTO StockAuditLog (product_id, old_quantity, new_quantity, audit_date)
VALUES (OLD.product_id, OLD.stock_quantity, NEW.stock_quantity, CURRENT_DATE);
END;
トリガーの設計で最も注意すべき点の一つに**永久ループ(Infinite Loop)**があります。あるトリガーが実行され、その中で別のテーブルを更新し、そのテーブルの更新がさらに別のトリガーを起動し、それが最初のトリガーを再度起動する、というように、トリガーが連鎖的に無限に実行されてしまう状態です。
TableAのUPDATEでTriggerAが起動。TriggerAがTableBをUPDATEする。TableBのUPDATEでTriggerBが起動。TriggerBがTableAをUPDATEする。WHEN句やIF文を使って、特定の条件が満たされた場合のみ処理を実行するようにする。午後試験では、データの整合性を保証するビジネスルールをトリガーで実装する問題や、既存のシステムで発生している性能問題の原因としてトリガーの不適切な設計(永久ループや無駄な処理)を指摘し、改善策を提案する問題が出題されることがあります。特にOLD/NEWの活用方法やWHEN句による効率化は重要です。
レプリケーション(Replication: 複製)とは、データベースのデータを、ネットワークで接続された複数のデータベースサーバ(マスタとスレーブ)間で複製し、常に同じ状態に保つための技術です。
INSERT, UPDATE, DELETE)を受け付けるデータベースサーバ。SELECT)リクエストを受け付けます。レプリケーションにおけるデータ変更の伝播方式には、大きく分けてイベント型とバッチ型があります。
イベント型レプリケーション:
INSERT, UPDATE, DELETEなどのSQL文や、行単位の変更)をリアルタイムに近い形でスレーブに伝播します。バッチ型レプリケーション:
レプリケーションにおけるコミットの保証度合いによって、同期型と非同期型があります。
同期型レプリケーション (Synchronous Replication)
非同期型レプリケーション (Asynchronous Replication)
レプリケーションは、システムの高可用性やスケーラビリティを実現するための重要な技術であり、午後試験でもシステムの要件に応じて最適なレプリケーション構成(イベント型/バッチ型、同期型/非同期型)を選択し、その理由やメリット・デメリットを説明する問題が出題されます。特に、CAP定理との関連性や、同期型と非同期型のトレードオフ(整合性と性能)は頻出テーマです。
第4章で学んだ内容は、データベーススペシャリスト試験の午後試験、特に午後Ⅰ問題で頻繁に問われるテーマです。物理設計は、概念設計・論理設計で定義されたデータモデルを、実際のDBMS上でどのように効率的に実装・運用するかを決定する重要なフェーズだからです。
ここでは、午後試験でこれらの知識がどのように問われ、どのように解答すべきか、その対策のポイントをまとめます。
EXPLAIN)の出力結果から分析しなさい。」EXPLAIN(またはそれに類する実行計画)の出力結果を読み解き、フルテーブルスキャンや索引レンジスキャン、ソートなどの操作が何を意味するのかを理解する。PCTFREEなど)をどのように設定すべきか、その理由とともに述べなさい。」PCTFREE, PCTUSED)**の役割と相互関係を理解する。PARTITION BYとORDER BY句の役割を説明しなさい。」RANK, LAG, AVGなど)**とOVER句(PARTITION BY, ORDER BY, ROWS BETWEEN)の組み合わせを使いこなせるようにする。BEFORE/AFTER、FOR EACH ROW/STATEMENT)、OLD/NEW参照、WHEN句の利用方法を理解する。午後試験は、単なる知識の有無だけでなく、その知識を現実のシステム課題に適用し、最適な解決策を提案する能力が問われます。各概念を深く理解し、具体的なシナリオに基づいて考え、記述する練習を重ねることが最も効果的な対策となります。
Ordersテーブルに(customer_id, order_date, total_amount)という複合索引が作成されている。以下のWHERE句を持つSQL文のうち、この複合索引が有効に利用されるものはどれか。複数選択可。
ア. WHERE customer_id = 101
イ. WHERE order_date = '2025-01-01'
ウ. WHERE customer_id = 101 AND order_date > '2025-01-01'
エ. WHERE order_date = '2025-01-01' AND total_amount > 1000
オ. WHERE customer_id = 101 AND order_date = '2025-01-01' AND total_amount > 1000
解答: ア, ウ, オ
解説:
複合索引は「前方一致の原則」に従い、先頭から連続した部分に対して利用されます。
customer_idのみを指定しており、先頭カラムを利用できる。customer_idが含まれていないため、索引は利用されない。customer_idとorder_dateを指定しており、先頭2カラムを利用できる。customer_idが含まれていないため、索引は利用されない。Productsテーブルのproduct_nameカラムに索引が作成されている。以下のSQL文のうち、この索引が利用されない可能性が高いものはどれか。
ア. SELECT * FROM Products WHERE product_name LIKE 'デスク%';
イ. SELECT * FROM Products WHERE SUBSTR(product_name, 1, 1) = 'デ';
ウ. SELECT * FROM Products WHERE product_name IS NOT NULL;
エ. SELECT * FROM Products WHERE product_name = 'ノートPC';
解答: イ
解説:
WHERE句で索引カラムに対して関数を適用すると、オプティマイザは索引を利用せずフルテーブルスキャンを選択する可能性が高いです。
IS NOT NULLであり、多くの場合索引を利用できます(ただし、NULL値が多い場合はフルテーブルスキャンの方が速いと判断されることもあります)。データベースのクラスタ率(Clustering Factor)とは何か。また、それが低い場合にどのような問題が発生するか簡潔に説明しなさい。
解答:
クラスタ率とは、テーブルの物理的な格納順序が、特定の索引の論理的な順序とどの程度一致しているかを示す指標です。
問題点: クラスタ率が低い場合、索引を使った範囲検索(Index Range Scan)の際に、データがディスク上のあちこちに散らばって格納されているため、多くのディスクI/Oが発生し、クエリのパフォーマンスが大幅に低下します。
データベースの表領域(Tablespace)の主な役割を2つ挙げなさい。
解答例:
PCTFREEパラメータの主な目的は何か。簡潔に説明しなさい。
解答:
PCTFREEは、データベースのページ(ブロック)内に、将来のデータ更新によって行のサイズが拡張された際に、その行が同じページ内に収まるように確保しておく空き領域の割合を指定するパラメータです。これにより、行のマイグレーション(行移動)やチェイニング(行連鎖)を防ぎ、I/O性能の低下を抑制することを目的とします。
テーブルのパーティショニング(区分化)を導入するメリットとして、最も適切なものはどれか。
ア. データの冗長性を完全に排除できる。
イ. クエリのWHERE句の条件に関わらず、必ず検索性能が向上する。
ウ. 特定のパーティションだけを対象にバックアップやアーカイブが可能になり、管理性が向上する。
エ. INSERT、UPDATE、DELETEの処理が常に高速になる。
解答: ウ
解説:
パーティショニングのメリットの一つに、特定期間のデータや特定カテゴリのデータなど、パーティション単位で独立した管理が可能になることが挙げられます。これにより、バックアップ、アーカイブ、メンテナンスなどの管理作業の柔軟性が増します。
データを日付の範囲(例: 年、月)に基づいて分割するパーティショニングの種類は何か。
ア. レンジ区分化 (Range Partitioning)
イ. リスト区分化 (List Partitioning)
ウ. ハッシュ区分化 (Hash Partitioning)
エ. コンポジット区分化 (Composite Partitioning)
解答: ア
解説:
レンジ区分化は、特定のカラムの値の範囲に基づいてデータを分割する方法で、時系列データや連続的な数値データに適しています。
共通テーブル式(CTE)を使用する主なメリットを1つ挙げなさい。
解答例:
Productsテーブルにおいて、各製品のcategory_idごとに、その製品の価格がカテゴリ内の平均価格より高いかどうかを判定するSELECT文を完成させなさい。
SELECT
product_name,
category_id,
price,
CASE WHEN price > AVG(price) OVER (PARTITION BY category_id) THEN '高い' ELSE '高くない' END AS price_comparison
FROM
Products;
このSELECT文のOVER句の中の[ ______ ]に当てはまるものは何か。
解答: PARTITION BY category_id
解説:
PARTITION BY句は、ウィンドウ関数を適用する行のグループ(区分)を定義します。この場合、category_idごとに平均価格を計算するため、PARTITION BY category_idと指定します。
Productsテーブルのデータを使って、release_dateでソートした際に、各製品の「前の製品の価格」を取得するSQL文を完成させなさい。(前の製品がない場合は0とする)
SELECT
product_name,
release_date,
price,
LAG(price, 1, 0) OVER (ORDER BY release_date) AS previous_product_price
FROM
Products;
このSELECT文のOVER句の中の[ ______ ]に当てはまるものは何か。
解答: ORDER BY release_date
解説:
LAG()関数は、ウィンドウ内で指定された順序に基づいて、現在の行の前の行の値を返します。LAG(price, 1, 0)は、1つ前の行のpriceを取得し、もし前の行がなければ0を返します。この「前の行」を決定するためには、ウィンドウ内の順序をORDER BY句で指定する必要があります。
各category_id内でpriceが高い順に製品の順位を付与したい。同じ価格の製品には同じ順位を付け、次の順位は重複した数だけスキップされる順位付けを行うウィンドウ関数は何か。
ア. ROW_NUMBER()
イ. RANK()
ウ. DENSE_RANK()
エ. NTILE()
解答: イ
解説:
ROW_NUMBER(): 重複を考慮せず一意の連番を付与。RANK(): 同じ値には同じ順位を付け、次の順位は重複数分スキップされる。DENSE_RANK(): 同じ値には同じ順位を付け、次の順位はスキップされずに連続する。NTILE(): 指定した数に均等に分割したグループ番号を付与。AFTER UPDATE ON Orders FOR EACH ROWというトリガーは、どのようなタイミングで起動するか。
ア. Ordersテーブルの行が更新される直前。
イ. Ordersテーブルの行が更新された直後。
ウ. Ordersテーブルに対してUPDATE文が実行される直前。
エ. Ordersテーブルに対してUPDATE文が実行された直後。
解答: イ
解説:
AFTERは、イベント(UPDATE)が発生した後に起動します。FOR EACH ROWは、更新された各行に対してトリガーが起動することを意味します。したがって、Ordersテーブルの行が更新された直後に起動します。
Productsテーブルのpriceカラムが更新された際に、トリガー内で更新前の価格と更新後の価格を比較したい。それぞれOLD.priceとNEW.priceという形式でアクセスできるが、これはどの種類のトリガーで可能か。
ア. BEFORE STATEMENTトリガー
イ. AFTER STATEMENTトリガー
ウ. BEFORE ROWトリガー
エ. AFTER INSERTトリガー
解答: ウ
解説:
OLDおよびNEWの参照は、行レベルトリガー(FOR EACH ROW句が指定されたトリガー)でのみ可能です。BEFOREトリガーではNEWの値を変更できますが、AFTERトリガーではできません。UPDATEトリガーで両方の値を比較できるのはBEFOREまたはAFTERの行レベルトリガーです。選択肢にはBEFORE ROWトリガーがあります。
データベースにおけるトリガーの「永久ループ」とは何か。簡潔に説明しなさい。
解答:
トリガーの永久ループとは、あるトリガーが実行された結果、そのトリガー自身を再度起動したり、別のトリガーを起動し、その別のトリガーが最初のトリガーを起動する、というように、トリガーが連鎖的に無限に実行されてしまう状態のことです。システムのリソースを枯渇させ、データベースを停止させる可能性があります。
データベースのレプリケーションを導入する主な目的を2つ挙げなさい。
解答例:
同期型レプリケーションと非同期型レプリケーションにおける、データの整合性とパフォーマンスに関するトレードオフについて簡潔に説明しなさい。
解答:
データベースの「ページ」または「ブロック」とは何か。簡潔に説明しなさい。
解答:
ページ(またはブロック)は、データベースにおいてディスクI/Oの最小単位となる記憶領域のことです。データベースがディスクからデータを読み書きする際には、必ずこのページ単位で行われます。テーブルの行データや索引のエントリなどがページ内に格納されます。
product_idがINT型で索引が作成されているProductsテーブルに対し、SELECT * FROM Products WHERE product_id = '123';というSQL文が実行された場合、索引が利用されない可能性がある。その主な理由を簡潔に説明しなさい。
解答:
product_idカラムがINT型であるにもかかわらず、WHERE句で文字列リテラル'123'と比較しているため、DBMSがproduct_idカラムに対して暗黙的な型変換を行ってしまう可能性があります。カラム自体に型変換の関数が適用されたのと同じ状態になり、索引の利用効率が著しく低下するか、全く利用されなくなるためです。
NTILE(n)ウィンドウ関数は、どのような計算を行うために使用されるか。簡潔に説明しなさい。
解答:
NTILE(n)ウィンドウ関数は、ウィンドウ内の行を、指定されたn個のグループに均等に分割し、各行がどのグループ(階級)に属するかを示す番号を返します。例えばNTILE(4)は、データを4つの四分位に分割するために使用できます。
午後試験で、遅いSQLの性能改善のためにEXPLAINコマンドの実行結果を分析する問題が出題された場合、特にどのような情報に注目すべきか、2つ挙げなさい。
解答例:
ORDER BY句やGROUP BY句でソート処理が発生している場合、これを索引によって回避できないか検討する。JOINの種類(ネステッドループ、ハッシュ、マージなど)や結合順序が適切かを確認する。この章では、データベーススペシャリスト試験の午後問題、特に午後Ⅱ問題で頻繁に出題される論理設計に焦点を当てます。概念設計で作成したE-R図をリレーショナルデータベースのテーブル構造に正確に落とし込み、データの冗長性を排除し、整合性を保つための知識が問われます。
概念設計で作成する概念データモデルは、ビジネス要件をデータベースの構造に変換する最初のステップです。ここでは、E-R図の要素をより深く理解し、午後試験で与えられる業務記述から正確なデータモデルを導き出すためのポイントを解説します。
E-R図は、概念データモデルを視覚的に表現するツールであり、午後試験では問題文の業務記述をE-R図で表現する能力や、与えられたE-R図を解釈する能力が問われます。
顧客, 製品, 注文)。顧客名, 製品価格)。顧客が注文する)。erDiagram
CUSTOMER ||--o{ ORDER : "places"
ORDER ||--o{ ORDER_DETAIL : "includes"
PRODUCT ||--o{ ORDER_DETAIL : "is_part_of"
CUSTOMER {
int customer_id PK
string customer_name
string address
string phone_number
}
ORDER {
int order_id PK
int customer_id FK
date order_date
string status
}
PRODUCT {
int product_id PK
string product_name
decimal price
int stock_quantity
}
ORDER_DETAIL {
int order_id PK, FK
int product_id PK, FK
int quantity
decimal unit_price
}
午後試験では、このようなE-R図を業務記述から作成したり、E-R図の不備を指摘する問題が出題されます。
リレーションシップはエンティティ間のつながりを示し、その「強さ」や「数」を表す**多重度(カーディナリティ)と参加の任意性(オプショナリティ)**を正確に読み取ることが重要です。
従業員と駐車券(1人の従業員は1枚の駐車券を持ち、1枚の駐車券は1人の従業員に割り当てられる)部署と従業員(1つの部署に複数の従業員が所属し、1人の従業員は1つの部署に所属する)学生と科目(1人の学生は複数の科目を履修し、1つの科目には複数の学生が所属する)リレーションシップの線とエンティティの接続部分に表示される記号で、そのエンティティがリレーションシップに必ず参加しなければならないか(必須:Mandatory)、**参加しなくてもよいか(任意:Optional)**を示します。
erDiagram
CUSTOMER ||--o{ ORDER : "places"
EMPLOYEE ||--|{ DEPARTMENT : "belongs_to"
CUSTOMER ||--o{ ORDER: CUSTOMER側は|(必須)、ORDER側はo(任意)。
EMPLOYEE ||--|{ DEPARTMENT: 両側とも|(必須)。
午後試験では、業務要件を正確に読み解き、適切な多重度と任意性をE-R図に反映できるかが評価のポイントとなります。
概念設計におけるリレーションシップは、論理設計で外部キー(FOREIGN KEY)による参照制約として実装されます。参照制約は、関連するテーブル間のデータの整合性を保証する重要な機能です。
親テーブルの行が削除(ON DELETE)または更新(ON UPDATE)された際に、関連する子テーブルの行に対してどのような操作を行うかを定義します。午後試験では、業務ルールに基づいてこれらのアクションを適切に選択する能力が問われます。
NO ACTION / RESTRICT:
CASCADE:
CUSTOMERが削除されたら、その顧客のORDERも全て削除する。SET NULL:
NOT NULL制約を持つ場合は使用できません。SET DEFAULT:
-- Productsテーブル (子) が Categoriesテーブル (親) を参照する例
CREATE TABLE Products (
product_id INT PRIMARY KEY,
category_id INT,
...
FOREIGN KEY (category_id) REFERENCES Categories(category_id) -- 参照制約
ON DELETE SET NULL -- 親カテゴリが削除されたら、製品のcategory_idはNULLになる
ON UPDATE CASCADE -- 親カテゴリのcategory_idが更新されたら、製品のcategory_idも自動更新される
);
午後試験では、一見簡単そうに見える業務記述の中に、リレーションシップの落とし穴が隠されていることがあります。特に注意すべきパターンを理解しておきましょう。
多対多のリレーションシップの見落とし:
従業員とプロジェクトの間に参加という関連エンティティ(テーブル)を設ける。自己参照(再帰的)リレーションシップの見落とし:
上司エンティティや下位部品エンティティを作成する。従業員テーブル内に上司IDカラムを設け、EMPLOYEE.employee_idを参照する自己参照FOREIGN KEYとする。排他的リレーションシップ:
注文テーブルに宅配IDと店頭受取IDの両方の外部キーを持ち、どちらか一方がNULLになるようにする。これはNULLが多く発生し、整合性チェックも複雑。注文テーブルに配送方法という区分カラムと、宅配ID、店頭受取IDの2つの外部キーを持ち、適切なCHECK制約で排他を保証する。属性とエンティティの混同:
都道府県は住所の属性の一つだが、都道府県自体に県庁所在地や人口などの属性を管理する必要があれば独立したエンティティとすべき。これらのパターンを理解し、業務記述から正確にモデル化する訓練が午後試験突破の鍵となります。
**スーパタイプ(Supertype: 上位型)とサブタイプ(Subtype: 下位型)**は、オブジェクト指向の「継承」の概念をデータモデルに適用したもので、「is-a」の関係(~である)を表現します。共通の特性を持つエンティティ群を一般化(汎化)してスーパタイプとし、固有の特性を持つサブタイプを特殊化(特化)して表現します。
従業員正社員, パートタイマー, 契約社員
従業員が共通して持つ属性(例: 氏名, 生年月日)は従業員エンティティに定義します。サブタイプ固有の属性(例: 正社員の月給、パートタイマーの時給)はそれぞれのサブタイプエンティティに定義します。erDiagram
EMPLOYEE ||--o{ FULL_TIME_EMPLOYEE : "is a"
EMPLOYEE ||--o{ PART_TIME_EMPLOYEE : "is a"
EMPLOYEE ||--o{ CONTRACT_EMPLOYEE : "is a"
EMPLOYEE {
int employee_id PK
string employee_name
date birth_date
}
FULL_TIME_EMPLOYEE {
int employee_id PK, FK
decimal monthly_salary
}
PART_TIME_EMPLOYEE {
int employee_id PK, FK
decimal hourly_wage
int work_hours
}
CONTRACT_EMPLOYEE {
int employee_id PK, FK
date contract_end_date
}
Personエンティティがある場合)。午後試験では、複雑な業務ルール(例: 従業員の種類による属性の違い)をスーパタイプ/サブタイプで適切にモデリングする能力や、その実装方法(リレーショナルスキーマへの変換)が問われます。特に包含制約と完全性制約を業務記述から正確に判断することが重要です。
概念設計で作成したE-R図を、リレーショナルデータベースで実際に構築するためのテーブル構造(関係スキーマ)に変換する詳細なステップが論理設計の後半部分です。ここでは、各要素がどのようにテーブルとして表現されるかを具体的に見ていきます。
**主キー(Primary Key)**は、リレーショナルテーブルの各行を一意に識別するためのカラム(またはカラムの組み合わせ)です。
午後試験では、業務要件から主キーを適切に選定できるかが問われます。
customer_id, product_id)。不変で一意性が保証されやすいが、業務上の意味がないため、ユーザーに提示する際には別の識別子が必要になることがある。午後試験では、自然キーと代理キーのどちらを選ぶべきか、それぞれのメリット・デメリットを考慮して判断する問題が出題されます。特に、複合主キー(複数のカラムを組み合わせた主キー)の設計では、部分関数従属を発生させないよう注意が必要です。
**外部キー(Foreign Key)**は、テーブル間のリレーションシップを表現するためのカラムです。子テーブルの外部キーが、親テーブルの主キーを参照することで、関連性のあるデータの一貫性(参照整合性)を保ちます。
FOREIGN KEY (外部キーカラム) REFERENCES 親テーブル名(親テーブルの主キーカラム)ON DELETE/ON UPDATEアクションを業務ルールに合わせて適切に選択できることも求められます。主キーや外部キー以外のカラムは、エンティティが持つ具体的な情報、つまり「非キー属性」となります。これらの属性に対しても、データ型、NOT NULL制約、UNIQUE制約、CHECK制約などを適切に設定し、データ整合性を確保する必要があります。
他の属性から計算で導き出せる属性を派生属性と呼びます(例: 生年月日から年齢を計算)。
午後試験では、派生属性をデータベースに格納すべきか、クエリ実行時に計算すべきか、性能要件や更新頻度などを考慮して判断する問題が出題されることがあります。
概念設計で定義したスーパタイプとサブタイプを、リレーショナルデータベースのテーブル構造に落とし込む方法にはいくつかのパターンがあります。午後試験では、それぞれの実装方法のメリット・デメリットを理解し、業務要件に合った最適な方法を選択する能力が問われます。
単一テーブル方式 (Single Table Inheritance)
NULLを許容する。NULL値が多くなりストレージ効率が悪い。サブタイプが増えるとカラム数が多くなる。CHECK制約による整合性確保がポイント。クラス階層テーブル方式 (Class Table Inheritance / 継承テーブル方式)
JOINが必要になり、クエリが複雑になる。JOINによるデータ取得方法がポイント。具象テーブル方式 (Concrete Table Inheritance)
NULLが少ない。UNION ALLなどが必要になり複雑。共通属性の変更時に全てのサブタイプテーブルを更新する必要がある。午後試験では、これらの実装方法について、業務要件(例: 検索頻度、更新頻度、サブタイプの追加・削除頻度)や性能要件、保守性などを考慮し、最適なものを選択し、その理由を論理的に説明できる能力が問われます。
第5章で学んだ論理設計の知識は、データベーススペシャリスト試験の午後Ⅱ問題の核となる部分です。午後Ⅱでは、多くの場合、与えられた業務記述を基にE-R図を作成・修正したり、正規化を進めて関係スキーマを定義したりする能力が問われます。
ここでは、午後試験でこれらの知識がどのように問われ、どのように解答すべきか、その対策のポイントをまとめます。
午後Ⅱ問題は、与えられた情報から論理的な思考を重ね、設計プロセスを追体験するような問題が多いです。単なる知識の暗記だけでなく、なぜそのような設計になるのか、どのようなメリット・デメリットがあるのかを自分の言葉で論理的に説明できる能力が問われます。多くの過去問を実際に解き、模範解答と自分の解答を比較分析する訓練を徹底しましょう。
概念データモデルの主要な成果物であり、エンティティ、属性、リレーションシップを視覚的に表現する図は何か。
ア. データフロー図 (DFD)
イ. 状態遷移図 (STD)
ウ. クラス図
エ. E-R図 (エンティティ関連図)
解答: エ
解説:
E-R図は、データベースの概念設計において、現実世界に存在するモノやコト、それらの属性、そしてモノやコト同士の関係を視覚的に表現するための図法です。
「1つの製品は複数の部品で構成され、1つの部品は複数の製品に使用される」という関係の多重度(カーディナリティ)は何か。
ア. 1対1
イ. 1対多
ウ. 多対多
エ. 多対1
解答: ウ
解説:
一方のエンティティの1つのインスタンスが他方の複数のインスタンスと関連し、かつ他方の1つのインスタンスも最初の複数のインスタンスと関連する場合、多対多(N:M)の関係となります。
E-R図で「参加が任意」であることを示す表記(例: クローズフィート記法)はどれか。
ア. 線上に1本の縦棒
イ. 線上に2本の縦棒
ウ. 線上に小さな円
エ. 線上にクロウズフィート(カラスの足)
解答: ウ
解説:
クローズフィート記法では、参加が必須の場合は線上に縦棒(|)を、任意の場合は小さな円(o)を記します。
親テーブルの行が削除された際に、関連する子テーブルの行も自動的に削除されるようにするON DELETEアクションはどれか。
ア. NO ACTION
イ. RESTRICT
ウ. SET NULL
エ. CASCADE
解答: エ
解説:
ON DELETE CASCADEは、親テーブルの行が削除されると、その親を参照している子テーブルの関連する行も自動的に削除する動作です。
E-R図で多対多のリレーションシップを表現した場合、論理設計でリレーショナルスキーマに変換する際には、どのように解消するのが一般的か。簡潔に説明しなさい。
解答:
多対多のリレーションシップは、直接リレーショナルスキーマ(テーブル)で表現できないため、間に**関連エンティティ(連関エンティティ)**を導入して解消します。この関連エンティティは、元の2つのエンティティの主キーを外部キーとして持ち、それらを複合主キーとすることが一般的です。
「従業員が上司を持つ(上司も従業員である)」という階層構造をデータベースで表現するためのリレーションシップの種類は何か。
ア. 排他的リレーションシップ
イ. 多対多リレーションシップ
ウ. 自己参照リレーションシップ
エ. 外部キーリレーションシップ
解答: ウ
解説:
自己参照リレーションシップは、エンティティ自身が自分自身とリレーションシップを持つ場合で、階層構造を表現する際によく用いられます。この場合、EMPLOYEEテーブル内に上司IDカラムを設け、それがEMPLOYEE.employee_idを参照する外部キーとなります。
スーパタイプ/サブタイプのリレーションシップにおいて、スーパタイプの全てのインスタンスが必ずいずれかのサブタイプに属さなければならないという制約を何と呼ぶか。
ア. 排他制約
イ. 重なり制約
ウ. 完全性制約 (Complete)
エ. 部分性制約 (Partial)
解答: ウ
解説:
完全性制約(Complete Constraint)は、スーパタイプのインスタンスが、必ず一つ以上のサブタイプに属することを要求します。
スーパタイプのインスタンスが、いずれか一つのサブタイプにのみ属することができるという包含制約を何と呼ぶか。
ア. 排他 (Disjoint)
イ. 重なり (Overlap)
ウ. 完全 (Complete)
エ. 部分 (Partial)
解答: ア
解説:
排他(Disjoint)制約は、スーパタイプのインスタンスが、複数のサブタイプに同時に属することを禁止します。重なり(Overlap)はその逆で、複数のサブタイプに属することを許容します。
主キーが満たすべき要件として、適切でないものはどれか。
ア. 一意性(各行を一意に識別できること)
イ. 非NULL性(値がNULLであってはならないこと)
ウ. 不変性(原則として、値が変更されないこと)
エ. 業務上の意味を必ず持つこと(自然キーであること)
解答: エ
解説:
主キーは業務上の意味を持つ自然キーでも、システムが自動生成する意味を持たない代理キー(サロゲートキー)でも構いません。実際、代理キーの方が不変性や簡潔性に優れるため、広く利用されます。
主キーとして代理キー(サロゲートキー)を使用する主な利点を1つ挙げなさい。
解答例:
顧客テーブルに生年月日カラムがあり、年齢カラムは生年月日から計算できる派生属性である。この年齢カラムをデータベースに格納しない設計を選択した場合の主なメリットは何か。
解答:
常に最新の年齢が取得できること(データの整合性が保たれること)と、年齢カラム分のストレージ容量を節約できることです。格納しない場合、生年月日が更新されれば年齢も自動的に最新になるため、更新時のデータ不整合リスクがありません。
スーパタイプ/サブタイプの実装方法の一つである「単一テーブル方式」の主なデメリットを1つ挙げなさい。
解答例:
NULL値の多発: 各サブタイプ固有の属性をすべて一つのテーブルに持つため、あるサブタイプのレコードでは他のサブタイプの属性がNULLとなり、NULL値が多く発生しストレージ効率が低下する。正社員の月給は0より大きい)を実装するのが難しい、またはCHECK制約が複雑になる。スーパタイプ/サブタイプの実装方法の一つである「クラス階層テーブル方式」が「単一テーブル方式」と比較して優れている点(メリット)を1つ挙げなさい。
解答例:
NULL値の削減: 各サブタイプ固有の属性がそれぞれのテーブルに格納されるため、NULL値の発生が抑えられ、ストレージ効率が向上する。NOT NULLなど)を明確に定義できる。学生エンティティと科目エンティティの間に「多対多」の履修リレーションシップがある。これを論理設計で解消し、関係スキーマとして表現しなさい。
解答:
以下のように3つのテーブルに分解する。
学生 (学生ID PK, 学生名)科目 (科目ID PK, 科目名)履修 (学生ID PK, FK, 科目ID PK, FK, 履修日)ここで、履修テーブルが関連エンティティとなり、学生IDと科目IDの複合主キーを持つ。
主キーでも外部キーでもない、エンティティが持つ具体的な情報を示すカラムを何と呼ぶか。
ア. 候補キー
イ. 非キー属性
ウ. 複合属性
エ. 派生属性
解答: イ
解説:
非キー属性(Non-Key Attribute)は、主キーでも外部キーでもない、エンティティの具体的な特徴を表す属性です。
「取引先は顧客であるか、または仕入先であるかのいずれかであり、両方ではない」という業務ルールは、どのような種類のリレーションシップを示すか。
解答:
排他的リレーションシップです。取引先というスーパタイプに対して、顧客と仕入先というサブタイプが排他(Disjoint)の関係にあることを示します。
商品テーブルに原価と売価があり、利益率は (売価 - 原価) / 売価 * 100 で計算できる派生属性である。この利益率をテーブルに格納する設計を選択した場合の主なデメリットは何か。
解答:
データの更新時にデータ不整合が発生するリスクがあることです。原価や売価が更新された際に利益率も同時に更新しないと、利益率の値が古くなり、実際の値と乖離してしまう可能性があります。また、利益率分のストレージ容量も余計に消費します。
ON DELETE SET NULLアクションを持つ参照制約を設定する際、子テーブルの外部キーカラムに対してどのような制約がないことを確認する必要があるか。
解答:
子テーブルの外部キーカラムが**NOT NULL制約**を持っていないことを確認する必要があります。SET NULLアクションは、親の行が削除された際に子の外部キーをNULLにするため、子の外部キーがNOT NULL制約を持っているとエラーが発生します。
データベースの論理設計において、正規化を行うことが特に重要な理由を簡潔に説明しなさい。
解答:
論理設計段階での正規化は、データの冗長性を排除し、更新、挿入、削除の際に発生しうるデータ異常(アノマリ)を防止することで、データベース全体のデータ整合性(一貫性)を確保するために不可欠です。これにより、データの品質と信頼性が向上し、アプリケーション開発や保守の容易性にも寄与します。
午後Ⅱ問題において、与えられた業務記述からE-R図を作成する際、特にどのような点に注意して記述を読み解くべきか、2つ挙げなさい。
解答例:
データベーススペシャリスト試験の午後問題、特に午後Ⅱでは、単なるデータベースの技術知識だけでなく、与えられた業務を深く理解し、それをデータモデルとして表現する能力が問われます。そのためには、ITシステムが支える主要な業務プロセス(業務知識)を把握しておくことが不可欠です。
この章では、代表的な業務プロセスである「販売管理」と「生産管理」に焦点を当て、その流れ、登場する主要なデータ(エンティティ)、そしてデータ間の関係性を分かりやすく解説します。
販売管理とは、顧客への「見積」から「受注」、「出荷」、「請求」、「入金」までの一連の業務プロセスを管理することです。企業の売上に関わる根幹の業務であり、データベースで管理される情報の典型例です。
見積は、顧客からの引き合い(問い合わせ)に対し、商品やサービスの価格、数量、納期などを提示する業務です。
graph TD
A["顧客からの問い合わせ"] --> B["見積作成"];
B --> C["顧客へ提示"];
C -- "承認" --> D["見積承認"];
C -- "却下" --> E["見積却下"];
erDiagram
CUSTOMER ||--o{ QUOTATION : "requests"
QUOTATION ||--o{ QUOTATION_DETAIL : "contains"
PRODUCT ||--o{ QUOTATION_DETAIL : "includes"
受注は、顧客から提示された見積や、それ以外の方法で、正式な注文(オーダー)を受け付ける業務です。
graph TD
A["顧客からの注文"] --> B["受注登録"];
B --> C["在庫・納期確認"];
C --> D["顧客へ納期回答"];
erDiagram
CUSTOMER ||--o{ ORDER : "places"
ORDER ||--o{ ORDER_DETAIL : "contains"
PRODUCT ||--o{ ORDER_DETAIL : "includes"
QUOTATION ||--o| ORDER : "generated_from"
QUOTATIONとORDERは1対1または1対多の関係(1つの見積もりから複数の注文が発生することもあるため)。
出荷指示は、受注した商品を倉庫から顧客へ発送するよう、倉庫部門に指示を出す業務です。
erDiagram
ORDER ||--o{ SHIPPING_INSTRUCTION : "instruct_shipping"
SHIPPING_INSTRUCTION ||--o{ SHIPPING_INSTRUCTION_DETAIL : "contains"
PRODUCT ||--o{ SHIPPING_INSTRUCTION_DETAIL : "includes"
出庫指示は、出荷指示に基づいて倉庫内で特定の商品をピッキング(取り出し)するよう作業員に指示する業務です。出庫実績は、実際に出庫された内容を記録する業務です。
erDiagram
SHIPPING_INSTRUCTION ||--o{ PICKING_INSTRUCTION : "generates"
PICKING_INSTRUCTION ||--o{ PICKING_INSTRUCTION_DETAIL : "contains"
PRODUCT ||--o{ PICKING_INSTRUCTION_DETAIL : "instructs_to_pick"
PICKING_INSTRUCTION ||--o{ PICKING_RESULT : "records_result_of"
PRODUCT ||--o{ PICKING_RESULT : "picked"
出荷実績は、実際に出荷が完了した内容を記録する業務です。出庫実績と照合され、最終的な顧客への出荷情報を確定します。
erDiagram
PICKING_RESULT ||--o{ SHIPPING_RECORD : "generates"
SHIPPING_RECORD ||--o{ SHIPPING_RECORD_DETAIL : "contains"
PRODUCT ||--o{ SHIPPING_RECORD_DETAIL : "shipped"
請求は、出荷した商品やサービスに対して、顧客に代金の支払いを要求する業務です。
erDiagram
CUSTOMER ||--o{ INVOICE : "receives"
ORDER ||--o| INVOICE : "associated_with"
INVOICE ||--o{ INVOICE_DETAIL : "contains"
PRODUCT ||--o{ INVOICE_DETAIL : "billed"
graph TD
見積("見積") --> 受注("受注");
受注 --> 出荷指示("出荷指示");
出荷指示 --> 出庫指示("出庫指示");
出庫指示 --> 出庫実績("出庫実績");
出庫実績 --> 出荷実績("出荷実績");
出荷実績 --> 請求("請求");
請求 --> 入金("入金");
午後試験では、このような一連の業務フロー全体を俯瞰し、各エンティティ間の連携やデータの一貫性をどのように保つべきかが問われます。
生産管理とは、顧客の需要や販売計画に基づいて、製品を効率的に製造し、供給するまでの一連の業務プロセスを管理することです。原材料の調達から製造計画、生産実行、品質管理、完成品の在庫管理まで多岐にわたります。
製品の製造は、様々なきっかけで開始されます。これを生産トリガーとも呼びます。
登場する主なデータ(エンティティ):
**品目(Item)**とは、生産管理において扱う全ての「モノ」の総称です。完成品、半製品、部品、原材料など、種類に関わらず一意に識別・管理されます。
品目の中でも、完成品や半製品を製造するためには、どの部品がどれだけ必要かを示す**部品構成表(BOM)**が非常に重要です。部品構成表は階層構造をしており、製品とその部品、さらにその部品の部品といった関係を管理します。
graph TD
A["製品A"] --> B["部品B"];
A --> C["部品C"];
B --> D["部品D"];
C --> D;
C --> E["部品E"];
業務では、このような階層構造を持つデータを扱うことが多いため、午後試験でも関連問題が出題されることがあります。
所要量展開(MRP)は、生産計画や顧客からの注文(独立需要)に基づいて、完成品を製造するために必要な部品や原材料の必要量と必要時期を計算することです。部品構成表(BOM)がこの計算の基礎となります。
製造指図は、所要量展開の結果に基づいて、実際に製品や部品を製造するよう製造現場に指示を出す業務です。
生産に必要な原材料や部品の不足分は、外部の仕入先(サプライヤー)に発注し、それが届けられた際に入荷として受け入れます。
graph TD
A["所要量展開"] --> B["発注"];
B --> C["入荷"];
erDiagram
SUPPLIER ||--o{ PURCHASE_ORDER : "supplies for"
PURCHASE_ORDER ||--o{ PURCHASE_ORDER_DETAIL : "contains"
ITEM ||--o{ PURCHASE_ORDER_DETAIL : "orders"
PURCHASE_ORDER ||--o{ GOODS_RECEIPT : "receives"
ITEM ||--o{ GOODS_RECEIPT : "received"
graph TD
A["需要/計画"] --> B["所要量展開_MRP"];
B --> C{"部品不足?"};
C -- "Yes" --> D["発注"];
D --> E["入荷"];
C -- "No" --> F["製造指図"];
E --> F;
F --> G["製造実行"];
G --> H["製造実績"];
H --> I["完成品在庫"];
午後試験では、これらの業務フローを正確に理解し、データ間の依存関係や整合性を考慮したデータモデルを構築できるかが問われます。特に、在庫管理や原価計算といった側面とデータベース設計を結びつける問題が出題されることがあります。
一般的な販売管理の一連の業務プロセスにおいて、「受注」の次に発生する業務として最も適切なものはどれか。
ア. 見積
イ. 請求
ウ. 出荷指示
エ. 入金
解答: ウ
解説:
販売管理の一般的なプロセスは「見積 → 受注 → 出荷指示 → 出庫指示・実績 → 出荷実績 → 請求 → 入金」の順に進みます。受注が確定した後、倉庫に出荷を依頼するための「出荷指示」が出されます。
「見積(Quotation)」業務において、主要な情報を管理するために最低限必要なエンティティの組み合わせとして適切なものはどれか。
ア. 顧客、製品、注文
イ. 顧客、製品、見積、見積明細
ウ. 製品、出荷指示、請求
エ. 従業員、製品、見積
解答: イ
解説:
見積は顧客と製品を対象に行われるため、顧客情報、製品情報、そして見積書そのものの情報(見積)とその詳細(見積明細)が必要となります。注文は受注業務以降に発生するエンティティです。
「顧客からの注文は、必ず以前に提示された見積に基づいて行われる」という業務ルールがある場合、注文 (Order)エンティティと見積 (Quotation)エンティティ間のリレーションシップの多重度と任意性として最も適切なものはどれか。
ア. 注文(多) - 見積(1) (必須)
イ. 注文(1) - 見積(1) (必須)
ウ. 注文(多) - 見積(1) (注文は見積に対して必須、見積は注文に対して任意)
エ. 注文(1) - 見積(多) (必須)
解答: ア
解説:
「顧客からの注文は、必ず以前に提示された見積に基づいて行われる」ということは、「1つの注文は必ず1つの見積から来る(注文→見積が必須で1)」ことを意味します。
「1つの見積からは、複数の注文が発生する可能性がある」と考えるのが自然なので、「見積→注文が任意で多」となります。
したがって、「注文(多) - 見積(1)」で、注文側から見積側への関連は必須です。
「出庫指示」と「出庫実績」の業務において、指示数量と実際数量の両方を記録することが重要な理由を簡潔に説明しなさい。
解答:
指示数量と実際数量の両方を記録することで、ピッキング作業における過不足や間違いを把握し、在庫差異の原因特定や作業品質の評価に役立てることができます。また、顧客への出荷情報との突合や、在庫管理の正確性を保つためにも重要です。
販売管理において、請求業務が開始される典型的なきっかけ(トリガー)となる業務は何か。
ア. 見積が承認された時
イ. 注文が確定された時
ウ. 製品の出荷が完了した時
エ. 入金が確認された時
解答: ウ
解説:
一般的に、請求書は商品やサービスが顧客に提供され、出荷が完了したことを確認した後で発行されます。
生産管理において、製品の製造を行うきっかけとなる「需要予測」以外に、考えられるトリガーを1つ挙げなさい。
解答例:
生産管理で扱う「品目(Item)」には、通常どのような種類の「モノ」が含まれるか。適切なものをすべて選択しなさい。
ア. 完成品
イ. 半製品
ウ. 部品
エ. 原材料
オ. サービス
解答: ア, イ, ウ, エ
解説:
生産管理における品目は、製造に関わる全ての物理的な「モノ」を指します。完成品、半製品、部品、原材料などが該当します。サービスは物理的なモノではないため、通常は品目としては扱われませんが、品目として管理される完成品に付随するサービスとして管理されることはあります。
「部品構成表(BOM)」が生産管理において果たす最も重要な役割は何か。
ア. 製品の価格を決定するため。
イ. 完成品を製造するために必要な部品の種類と数量を示すため。
ウ. 従業員の勤務時間を管理するため。
エ. 顧客からのクレーム情報を記録するため。
解答: イ
解説:
部品構成表(BOM)は、ある製品がどのような部品や原材料から構成されているか、そしてそれぞれがどれだけ必要かを示すリストであり、所要量展開(MRP)の基礎となります。
「所要量展開(MRP)」の主な目的は何か。簡潔に説明しなさい。
解答:
所要量展開(MRP)の主な目的は、完成品の生産計画や受注量に基づいて、それを製造するために必要な部品や原材料の「必要量」と「いつまでに必要か(必要時期)」を正確に計算することです。これにより、過剰な在庫や部品不足を防ぎ、生産計画を最適化します。
「製造指図(Production Order)」は、生産管理のどの段階で発行されるか。
ア. 顧客からの受注時
イ. 部品構成表の作成時
ウ. 所要量展開(MRP)の結果に基づいて
エ. 完成品の出荷時
解答: ウ
解説:
所要量展開(MRP)によって、どのような製品や部品をどれだけ製造する必要があるかが明確になった後、具体的な製造作業を指示するために製造指図が発行されます。
生産管理における「発注」業務で作成される主なエンティティは何か。また、そのエンティティが参照する主なエンティティも挙げなさい。
解答:
発注 (PurchaseOrder)、発注明細 (PurchaseOrderDetail)仕入先 (Supplier)、品目 (Item)
(PurchaseOrderはSupplierを参照し、PurchaseOrderDetailはPurchaseOrderとItemを参照します。)注文 (Order)エンティティと注文明細 (OrderDetail)エンティティのリレーションシップは、一般的にどのような多重度になるか。
ア. 注文(1) - 注文明細(1)
イ. 注文(1) - 注文明細(多)
ウ. 注文(多) - 注文明細(1)
エ. 注文(多) - 注文明細(多)
解答: イ
解説:
1つの注文は複数の製品を含む注文明細を持つことができ、1つの注文明細は必ず1つの注文に属します。したがって、1対多(Order:1 - OrderDetail:N)の関係となります。
製品Aが部品Bと部品Cから構成され、部品Bは部品Dから構成される階層構造を持つ場合、この部品構成表をデータベースで表現するために必要な主要なエンティティとその関係について簡潔に説明しなさい。
解答:
主要なエンティティは品目 (Item)と部品構成 (BillOfMaterial)です。
Itemテーブルが全ての部品や製品の基本情報を持ち、BillOfMaterialテーブルが親品目IDと子品目ID、使用数量などの情報を持つことで、Item間の自己参照リレーションシップを通じて階層構造を表現します。
出荷実績(ShippingRecord)エンティティに記録される情報として、主要なものを2つ挙げなさい。
解答例:
「1つの発注に対して複数の入荷実績がある場合があり、1つの入荷実績は必ず1つの発注に対するものである」という業務ルールがある場合、入荷 (GoodsReceipt)エンティティと発注 (PurchaseOrder)エンティティ間のリレーションシップの多重度と任意性として最も適切なものはどれか。
ア. 入荷(多) - 発注(1) (必須)
イ. 入荷(1) - 発注(多) (必須)
ウ. 入荷(多) - 発注(1) (入荷は発注に対して必須、発注は入荷に対して任意)
エ. 入荷(1) - 発注(多) (入荷は発注に対して任意、発注は入荷に対して必須)
解答: ア
解説:
「1つの入荷実績は必ず1つの発注に対するもの」なので、入荷側から発注側への関連は必須で1。「1つの発注に対して複数の入荷実績がある場合がある」ので、発注側から入荷側への関連は多(かつ発注にまだ入荷がない可能性があるので任意)。
結果として「入荷(多) - 発注(1)」で、入荷から発注への関連が必須となります。
顧客 (Customer)エンティティが持つべき主要な属性を3つ挙げなさい。
解答例:
製造指図(ProductionOrder)の主な目的は何か。簡潔に説明しなさい。
解答:
製造指図は、所要量展開(MRP)の結果に基づいて、特定の製品や部品を、いつまでに、どれだけ製造すべきかを製造現場に具体的に指示するための業務指示書です。製造の実行管理、進捗管理、および実績記録の基礎となります。
データベーススペシャリスト試験の午後Ⅱ問題では、業務知識をどのように活用する能力が問われるか、簡潔に説明しなさい。
解答:
午後Ⅱ問題では、与えられた複雑な業務記述を正確に読み解き、その業務の流れやルールを理解した上で、適切なエンティティ、属性、リレーションシップを抽出し、データモデル(E-R図や関係スキーマ)として表現する能力が問われます。単なるデータベースの技術知識だけでなく、ビジネスプロセスをデータとしてどのように捉えるかが重要となります。
販売管理において、受注が発生した際と出荷が発生した際で、製品の在庫数に与える影響はそれぞれどのように処理されるべきか。
解答:
製品の在庫数を直接減らすのではなく、引当在庫(注文済みで、まだ出荷されていない在庫)として管理し、実在庫からは減らさないことが多いです。製品の実在庫数を減少させます。生産管理において、発注業務を自動化するための情報として、品目 (Item)エンティティが持つべき属性と、所要量計画 (MRPPlan)エンティティが持つべき属性をそれぞれ1つずつ挙げなさい。
解答:
品目 (Item)エンティティ: 安全在庫数、標準リードタイム、仕入先IDなど(安全在庫を下回ったら自動発注など)。所要量計画 (MRPPlan)エンティティ: 必要数量、必要時期など(MRPの計算結果に基づいて発注量を決定するため)。