新規作成

This commit is contained in:
m-kyono
2026-10-28 10:43:56 +09:00
commit 1da62d0e19
12 changed files with 1347 additions and 0 deletions

128
question-spec/.gitignore vendored Normal file
View File

@@ -0,0 +1,128 @@
# ===== Java =====
*.class
*.log
*.jar
*.war
*.ear
*.nar
hs_err_pid*
replay_pid*
target/
build/
out/
bin/
.gradle/
.mvn/wrapper/maven-wrapper.jar
!gradle/wrapper/gradle-wrapper.jar
.classpath
.project
.settings/
*.iml
*.ipr
*.iws
.idea/
.apt_generated/
.factorypath
nbproject/
.springBeans
.sts4-cache/
# ===== C# / .NET =====
[Bb]in/
[Oo]bj/
[Dd]ebug/
[Rr]elease/
x64/
x86/
[Ll]og/
[Ll]ogs/
.vs/
*.user
*.suo
*.userosscache
*.sln.docstates
*.userprefs
*.pdb
*.cache
*.nupkg
*.snupkg
packages/
!packages/build/
project.lock.json
artifacts/
TestResults/
*.dotCover
*.csproj.user
.vscode/
launchSettings.json
*_i.c
*_p.c
msbuild.log
msbuild.err
msbuild.wrn
# ===== Python =====
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
*.egg
dist/
develop-eggs/
eggs/
sdist/
wheels/
.eggs/
pip-wheel-metadata/
pip-log.txt
.venv/
venv/
env/
ENV/
.env
.pytest_cache/
.mypy_cache/
.ruff_cache/
.tox/
.coverage
.coverage.*
htmlcov/
.ipynb_checkpoints/
*.sqlite3
db.sqlite3
# ===== PHP =====
vendor/
composer.phar
.phpunit.result.cache
.phpunit.cache/
.php-cs-fixer.cache
.php_cs.cache
.phpstorm.meta.php
auth.json
*.phar
# ===== Windows =====
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
Desktop.ini
$RECYCLE.BIN/
*.lnk
*.stackdump
*.cab
*.msi
*.msix
*.msm
*.msp
# ===== エディタ・その他 =====
*.swp
*.swo
*~
.DS_Store
*.tmp
*.bak

View File

@@ -0,0 +1,45 @@
# DB連携系 共通前提
本資料の練習問題は、複数のプログラミング言語(Java / PHP / C# / Python)で共通して利用できるよう記述されています。使用するデータベース接続の仕組み(JDBC、PDO、ADO.NET、DB-API 2.0準拠のドライバ など)やSQLへのパラメータの指定方法、自動採番された値の取得方法など、言語・環境固有の仕様に基づき、問題文の表現をご使用の環境の仕様に適宜読み替えて進めてください。
この系統の各設問に共通する前提事項をまとめます。各`QuestionXX`の仕様は、この内容を前提として記述しています。
## データベースへの接続について
- 前提として、次の接続情報でアクセスできるデータベースサーバーが、あらかじめ用意されているものとします。
- ホスト:`127.0.0.1`
- データベース名:`rezodb`
- ユーザー名:`rezouser`
- パスワード:`Rezo_0000`
- (上記は一例です。実際の環境や使用するデータベース製品に合わせて読み替えてください)
- 各設問のプログラムでは、上記のデータベースに接続してSQLを実行したうえで、使用し終えたら必ず接続を切断する処理を実装してください。
- SQL文に値を埋め込む際は、文字列としてそのまま連結するのではなく、パラメータとして値を渡す仕組み(プレースホルダ/バインド変数に相当する仕組み)を使用してください。
## 部署テーブル(department)
以下の項目を持つ「部署」テーブルが、あらかじめ用意されているものとします。
| カラム名 | 内容 | 型 |
| --- | --- | --- |
| id_department | 部署ID(主キー。新規登録時は自動的に採番される) | 整数 |
| nm_department | 部署名 | 文字列 |
初期データとして、以下の5件が登録されているものとします。
| id_department | nm_department |
| --- | --- |
| 1 | 営業部 |
| 2 | 人事部 |
| 3 | 開発部 |
| 4 | 東京支店 |
| 5 | 大阪支店 |
- 部署ID `1`〜`3` の部署には、社員テーブル(`Question06`で使用)の社員が所属しています。社員テーブルは部署IDで部署テーブルを参照しているため、これらの部署を削除しようとするとエラーになります。
- 部署ID `4`・`5` の部署には、所属する社員がいません。削除を扱う設問(`Question05`、`Question08`)では、これらの部署を削除の対象とします。
## 各設問を実行する際の注意
- 各設問はそれぞれ独立したプログラムとして実装しますが、データベース自体は設問をまたいで共有される永続的なものです。そのため、**各設問を実行する前には、データベースが上記の初期データの状態になっていることを確認してから実行してください**(前の設問で行った登録・更新・削除の内容は、次の設問には引き継がれません)。
- 初期データの状態に戻すには、テーブル作成用SQL(`DB連携系/sql/`配下の `CreateTable-MySQL.sql` または `CreateTable-SQLServer.sql`)を実行し直してください。このSQLはテーブルを削除して作り直すため、自動採番される部署IDも初期状態(次に登録するデータが`6`)に戻ります。
- 登録したデータを削除するだけでは、自動採番される値は元に戻りません。そのため、テーブルを作り直さずに登録を繰り返すと、各設問の実行例よりも大きい部署IDが採番されます。部署IDの数字だけが実行例と異なる場合は、実装の誤りではありません。
- `Question06`でのみ、上記の部署テーブルに加えて「社員テーブル」も使用します。社員テーブルの定義は`Question06`の仕様内で説明します(社員テーブルは、テーブル作成用SQLによって部署テーブルと一緒に作成されます)。

View File

@@ -0,0 +1,98 @@
# Question01 - 検索系SQL(全件取得)
本資料の練習問題は、複数のプログラミング言語(Java / PHP / C# / Python)で共通して利用できるよう記述されています。使用するデータベース接続の仕組み(JDBC、PDO、ADO.NET、DB-API 2.0準拠のドライバ など)やSQLへのパラメータの指定方法、自動採番された値の取得方法など、言語・環境固有の仕様に基づき、問題文の表現をご使用の環境の仕様に適宜読み替えて進めてください。
[共通の前提](../00.共通前提.md)を参照してください。
## この問題のねらい
- データベースに接続し、SQLを実行して結果を取得したうえで、接続を切断するという一連の流れを実装できること
以下の設問はそれぞれ独立したプログラムとして実装してください。
## ファイル名・フォルダ構成
- 設問ごとに1つのフォルダを作成し、そのフォルダの直下にプログラムのファイルを配置すること。
- フォルダ名は、設問番号に対応した連番(`question01`、`question02`、…)とすること(全言語共通・小文字)。
- ファイル名は、設問番号に対応した連番(`Question01`、`Question02`、…)を基本とし、言語の慣習に合わせて次のとおりとすること。
- 本問題(Question01-SelectAll)の構成は次のとおり。
```
Question01-SelectAll/
├── question01/    ← 設問1
│ └── Question01.<拡張子>
├── question02/    ← 設問2
│ └── Question02.<拡張子>
└── question03/    ← 設問3
└── Question03.<拡張子>
```
- Java: `Question01.java`(公開クラス名もファイル名と同じ `Question01` とする)
- C#: `Question01.cs`
- PHP: `Question01.php`
- Python: `question01.py`(モジュール名は小文字とする慣習のため、ファイル名のみ小文字)
- 上記ツリー中の `Question01.<拡張子>` は、使用する言語に応じて上記のファイル名に読み替えること。
- プロジェクトファイルが必要な場合など、言語・開発環境の規則上やむを得ない場合は、その規則を優先してよい。その場合も、設問ごとのフォルダ分けと連番の命名は維持すること。
- 設問内で追加で作成するクラス・関数などは、その設問のフォルダ直下に配置すること。
- 他の設問で作成したクラス等を使用する設問では、各フォルダ単独で実行できるよう、そのフォルダ直下にも同じ内容を配置すること。
---
## 設問1
部署テーブルから全件のデータ(部署ID・部署名)を取得し、部署IDの昇順で、1件につき1行、部署IDと部署名をタブ区切りで出力するプログラムを実装してください。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- 取得したデータは、取得した件数分すべて出力すること
- ソートを使用すること
### 実行例
```
1 営業部
2 人事部
3 開発部
4 東京支店
5 大阪支店
```
---
## 設問2
部署テーブルから全件のデータ(部署ID・部署名)を取得し、部署IDの**降順**で、1件につき1行、部署IDと部署名をタブ区切りで出力するプログラムを実装してください。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- 並び替えはSQL側(データベースへの問い合わせ)で行うこと
- 取得したデータは、取得した件数分すべて出力すること
### 実行例
```
5 大阪支店
4 東京支店
3 開発部
2 人事部
1 営業部
```
---
## 設問3
部署テーブルに登録されている部署の件数を取得し、「部署は全部でX件登録されています」(Xは取得した件数)の形式で出力するプログラムを実装してください。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- 件数は、取得した全データを1件ずつ数えるのではなく、集計を行う仕組み(SQLの集計関数に相当するもの)を使って、データベース側で算出すること
### 実行例
```
部署は全部で5件登録されています
```

View File

@@ -0,0 +1,122 @@
# Question02 - 検索系SQL(パラメータあり)
本資料の練習問題は、複数のプログラミング言語(Java / PHP / C# / Python)で共通して利用できるよう記述されています。使用するデータベース接続の仕組み(JDBC、PDO、ADO.NET、DB-API 2.0準拠のドライバ など)やSQLへのパラメータの指定方法、自動採番された値の取得方法など、言語・環境固有の仕様に基づき、問題文の表現をご使用の環境の仕様に適宜読み替えて進めてください。
[共通の前提](../00.共通前提.md)を参照してください。
## この問題のねらい
- 実行のたびに異なる値(パラメータ)をSQLの実行結果に反映させる方法を理解する
- SQLに値を直接埋め込むのではなく、プレースホルダ(バインド変数。Java: `PreparedStatement`/PHP: `PDOStatement`(`PDO::prepare()`)/C#: `SqlCommand`の`Parameters`/Python: DB-API 2.0の`cursor.execute()`へのパラメータ指定 など、各言語のデータベース接続の仕組みにおけるプレースホルダに相当するもの)を使って安全に値を渡せること
以下の設問はそれぞれ独立したプログラムとして実装してください。
## ファイル名・フォルダ構成
- 設問ごとに1つのフォルダを作成し、そのフォルダの直下にプログラムのファイルを配置すること。
- フォルダ名は、設問番号に対応した連番(`question01`、`question02`、…)とすること(全言語共通・小文字)。
- ファイル名は、設問番号に対応した連番(`Question01`、`Question02`、…)を基本とし、言語の慣習に合わせて次のとおりとすること。
- 本問題(Question02-SelectWithParameter)の構成は次のとおり。
```
Question02-SelectWithParameter/
├── question01/    ← 設問1
│ └── Question01.<拡張子>
├── question02/    ← 設問2
│ └── Question02.<拡張子>
└── question03/    ← 設問3
└── Question03.<拡張子>
```
- Java: `Question01.java`(公開クラス名もファイル名と同じ `Question01` とする)
- C#: `Question01.cs`
- PHP: `Question01.php`
- Python: `question01.py`(モジュール名は小文字とする慣習のため、ファイル名のみ小文字)
- 上記ツリー中の `Question01.<拡張子>` は、使用する言語に応じて上記のファイル名に読み替えること。
- プロジェクトファイルが必要な場合など、言語・開発環境の規則上やむを得ない場合は、その規則を優先してよい。その場合も、設問ごとのフォルダ分けと連番の命名は維持すること。
- 設問内で追加で作成するクラス・関数などは、その設問のフォルダ直下に配置すること。
- 他の設問で作成したクラス等を使用する設問では、各フォルダ単独で実行できるよう、そのフォルダ直下にも同じ内容を配置すること。
---
## 設問1
標準入力から部署IDを受け取り、その部署IDに一致する部署のデータ(部署ID・部署名)をタブ区切りで出力するプログラムを実装してください。
### 手順・要件
1. 次の処理を、有効な入力が得られるまで繰り返してください。
1. 「検索する部署IDを入力してください」と表示する
2. 標準入力から1行分のテキストを読み込む
3. 読み込んだ内容が整数として解釈できない場合、「数値を入力してください」と表示し、手順1に戻る
4. 整数として解釈できた場合、その値を部署IDとして繰り返し処理を終了する
2. 確定した部署IDを使って、部署テーブルから一致するデータを検索する。この際、SQLに値を直接埋め込むのではなく、プレースホルダ(バインド変数。Java: `PreparedStatement`/PHP: `PDOStatement`(`PDO::prepare()`)/C#: `SqlCommand`の`Parameters`/Python: DB-API 2.0の`cursor.execute()`へのパラメータ指定 など)を使用して値を渡すこと
3. 検索結果が存在する場合、その部署ID・部署名をタブ区切りで出力する
4. 検索結果が存在しない場合、「一致する部署は見つかりませんでした」と出力する
### 実行例
- 入力が `2` の場合
- 出力:`2 人事部`
- 入力が `99`(存在しない部署ID)の場合
- 出力:`一致する部署は見つかりませんでした`
- 入力が `abc`(数値でない)の場合
- 出力:`数値を入力してください`(その後、再度入力を促す)
---
## 設問2
標準入力から部署名の一部の文字列を受け取り、部署名にその文字列を含む部署のデータ(部署ID・部署名)を、部署IDの昇順で、1件につき1行、タブ区切りで出力するプログラムを実装してください(該当するデータは0件・1件・複数件のいずれの場合もあります)。
### 手順・要件
1. 「検索する部署名の一部を入力してください」と表示する
2. 標準入力から1行分のテキストを読み込む
3. 読み込んだ文字列を部署名に含む部署のデータを、部署テーブルから検索する。この際、SQLに値を直接埋め込むのではなく、プレースホルダ(バインド変数。Java: `PreparedStatement`/PHP: `PDOStatement`(`PDO::prepare()`)/C#: `SqlCommand`の`Parameters`/Python: DB-API 2.0の`cursor.execute()`へのパラメータ指定 など)を使用し、部分一致検索に対応した形で値を渡すこと
4. 検索結果が1件以上存在する場合、該当するすべてのデータを部署IDの昇順でタブ区切りで出力する
5. 検索結果が存在しない場合、「一致する部署は見つかりませんでした」と出力する
### 実行例
- 入力が `部` の場合
- 出力:
```
1 営業部
2 人事部
3 開発部
```
- 入力が `営業` の場合
- 出力:`1 営業部`
- 入力が `総務`(一致するものがない文字列)の場合
- 出力:`一致する部署は見つかりませんでした`
---
## 設問3
標準入力から部署IDの下限値を受け取り、その値**以上**の部署IDを持つ部署のデータ(部署ID・部署名)を、部署IDの昇順で、1件につき1行、タブ区切りで出力するプログラムを実装してください。
### 手順・要件
1. 次の処理を、有効な入力が得られるまで繰り返してください。
1. 「検索する部署IDの下限値を入力してください」と表示する
2. 標準入力から1行分のテキストを読み込む
3. 読み込んだ内容が整数として解釈できない場合、「数値を入力してください」と表示し、手順1に戻る
4. 整数として解釈できた場合、その値を下限値として繰り返し処理を終了する
2. 確定した下限値を使って、部署テーブルから、部署IDがその値以上であるデータを検索する。この際、SQLに値を直接埋め込むのではなく、プレースホルダ(バインド変数。Java: `PreparedStatement`/PHP: `PDOStatement`(`PDO::prepare()`)/C#: `SqlCommand`の`Parameters`/Python: DB-API 2.0の`cursor.execute()`へのパラメータ指定 など)を使用し、比較演算子を伴う条件として値を渡すこと
3. 検索結果が1件以上存在する場合、該当するすべてのデータを部署IDの昇順でタブ区切りで出力する
4. 検索結果が存在しない場合、「一致する部署は見つかりませんでした」と出力する
### 実行例
- 入力が `2` の場合
- 出力:
```
2 人事部
3 開発部
4 東京支店
5 大阪支店
```
- 入力が `10`(該当するデータがない値)の場合
- 出力:`一致する部署は見つかりませんでした`

View File

@@ -0,0 +1,114 @@
# Question03 - 更新系SQL(登録)
本資料の練習問題は、複数のプログラミング言語(Java / PHP / C# / Python)で共通して利用できるよう記述されています。使用するデータベース接続の仕組み(JDBC、PDO、ADO.NET、DB-API 2.0準拠のドライバ など)やSQLへのパラメータの指定方法、自動採番された値の取得方法など、言語・環境固有の仕様に基づき、問題文の表現をご使用の環境の仕様に適宜読み替えて進めてください。
[共通の前提](../00.共通前提.md)を参照してください。
## この問題のねらい
- データベースに新しいデータを登録するSQLを実行できること
- 登録時に自動的に採番される値(主キー)の扱いを理解する
- 登録した内容が実際にデータベースへ反映されていることを、検索によって確認できること
以下の設問はそれぞれ独立したプログラムとして実装してください。
## ファイル名・フォルダ構成
- 設問ごとに1つのフォルダを作成し、そのフォルダの直下にプログラムのファイルを配置すること。
- フォルダ名は、設問番号に対応した連番(`question01`、`question02`、…)とすること(全言語共通・小文字)。
- ファイル名は、設問番号に対応した連番(`Question01`、`Question02`、…)を基本とし、言語の慣習に合わせて次のとおりとすること。
- 本問題(Question03-Insert)の構成は次のとおり。
```
Question03-Insert/
├── question01/    ← 設問1
│ └── Question01.<拡張子>
├── question02/    ← 設問2
│ └── Question02.<拡張子>
└── question03/    ← 設問3
└── Question03.<拡張子>
```
- Java: `Question01.java`(公開クラス名もファイル名と同じ `Question01` とする)
- C#: `Question01.cs`
- PHP: `Question01.php`
- Python: `question01.py`(モジュール名は小文字とする慣習のため、ファイル名のみ小文字)
- 上記ツリー中の `Question01.<拡張子>` は、使用する言語に応じて上記のファイル名に読み替えること。
- プロジェクトファイルが必要な場合など、言語・開発環境の規則上やむを得ない場合は、その規則を優先してよい。その場合も、設問ごとのフォルダ分けと連番の命名は維持すること。
- 設問内で追加で作成するクラス・関数などは、その設問のフォルダ直下に配置すること。
- 他の設問で作成したクラス等を使用する設問では、各フォルダ単独で実行できるよう、そのフォルダ直下にも同じ内容を配置すること。
## 実行例の部署IDについて
- 各設問の実行例に示す部署ID(`6`、`7` など)は、テーブル作成用SQL([共通の前提](../00.共通前提.md)を参照)を実行して部署テーブルを作り直した直後に、その設問を初めて実行した場合の値です。
- 自動採番される値は、登録したデータを削除しても元に戻りません。テーブルを作り直さずに登録を繰り返した場合や、別の設問で登録した後に実行した場合は、実行例よりも大きい部署IDが採番されます。
- このように部署IDの数字だけが実行例と異なる場合でも、次の点を満たしていれば正しく実装できています。
- 部署IDを指定せずに登録しており、既存のデータと重複しない部署IDが自動的に採番されていること
- 確認のための検索で、登録した部署名とその部署IDが出力されること
- 実行例と同じ部署IDで確認したい場合は、テーブル作成用SQLを実行し直してから、各設問を実行してください。
---
## 設問1
標準入力から部署名を受け取り、部署テーブルに新しいデータとして登録するプログラムを実装してください。
### 要件
- 「登録する部署名を入力してください」と表示し、標準入力から部署名を読み込むこと
- 部署IDは指定せず、登録時に自動的に採番される値を使用すること
- 部署名の登録には、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用すること
- 登録が完了したら、「登録完了」と出力すること
- 登録完了の出力に続けて、「確認のため、検索する部署名を入力してください」と表示し、標準入力から部署名を読み込んだうえで、その部署名に一致する部署のデータを部署テーブルから検索し、検索結果(部署ID・部署名)をタブ区切りで出力すること(登録内容がデータベースに反映されていることを、自分で検索して確認できるようにする)。該当するデータが存在しない場合は、「一致する部署は見つかりませんでした」と出力すること
### 実行例
- 「登録する部署名を入力してください」と表示された後に `広報部` と入力した場合
- 出力:`登録完了`
- 続けて「確認のため、検索する部署名を入力してください」と表示された後に `広報部` と入力した場合
- 出力:`6 広報部`
---
## 設問2
標準入力から部署名を3件連続で受け取り、3件とも部署テーブルにまとめて登録するプログラムを実装してください。
### 手順・要件
1. 「1件目の部署名を入力してください」「2件目の部署名を入力してください」「3件目の部署名を入力してください」と、この順に1件ずつ表示し、それぞれ標準入力から部署名を読み込む
2. 読み込んだ3件の部署名を、この順で部署テーブルに登録する
3. 部署IDはいずれも指定せず、登録時に自動的に採番される値を使用すること
4. 部署名の登録には、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用すること
5. 3件とも登録が完了したら、「3件登録完了」と出力する
6. 続けて、「確認のため、検索する部署名を入力してください」と表示し、標準入力から部署名を読み込んだうえで、その部署名に一致する部署のデータを部署テーブルから検索し、検索結果(部署ID・部署名)をタブ区切りで出力すること(登録内容がデータベースに反映されていることを、自分で検索して確認できるようにする)。該当するデータが存在しない場合は、「一致する部署は見つかりませんでした」と出力すること
### 実行例
- 1件目に `広報部`、2件目に `法務部`、3件目に `経理部` と入力した場合
- 出力:`3件登録完了`
- 続けて「確認のため、検索する部署名を入力してください」と表示された後に `法務部` と入力した場合
- 出力:`7 法務部`
---
## 設問3
標準入力から部署名を受け取り、部署テーブルに新しいデータとして登録するプログラムを実装してください。ただし、同じ部署名が既に登録されている場合は、登録を行わないようにしてください。
### 手順・要件
1. 「登録する部署名を入力してください」と表示し、標準入力から部署名を読み込む
2. 読み込んだ部署名と一致するデータが、部署テーブルに既に存在するかどうかを検索する。この際、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用すること
3. 既に存在する場合、登録は行わず、「(部署名)は既に登録されています」と出力する
4. 存在しない場合、部署IDを指定せず(自動的に採番される値を使用して)新しいデータとして登録し、「登録完了」と出力する
5. 手順4で登録した場合は、続けて「確認のため、検索する部署名を入力してください」と表示し、標準入力から部署名を読み込んだうえで、その部署名に一致する部署のデータを検索し、検索結果(部署ID・部署名)をタブ区切りで出力すること(登録内容がデータベースに反映されていることを、自分で検索して確認できるようにする)。手順3で登録を行わなかった場合、この確認のための検索は行わない
### 実行例
- `広報部`(未登録の部署名)と入力した場合
- 出力:`登録完了`
- 続けて「確認のため、検索する部署名を入力してください」と表示された後に `広報部` と入力した場合
- 出力:`6 広報部`
- `営業部`(既に登録されている部署名)と入力した場合
- 出力:`営業部は既に登録されています`

View File

@@ -0,0 +1,115 @@
# Question04 - 更新系SQL(更新)
本資料の練習問題は、複数のプログラミング言語(Java / PHP / C# / Python)で共通して利用できるよう記述されています。使用するデータベース接続の仕組み(JDBC、PDO、ADO.NET、DB-API 2.0準拠のドライバ など)やSQLへのパラメータの指定方法、自動採番された値の取得方法など、言語・環境固有の仕様に基づき、問題文の表現をご使用の環境の仕様に適宜読み替えて進めてください。
[共通の前提](../00.共通前提.md)を参照してください。
## この問題のねらい
- データベースに登録されている既存のデータを更新するSQLを実行できること
- 更新条件(対象を絞り込む条件)を変えることで、更新される件数が変わることを理解する
- 更新した内容が実際にデータベースへ反映されていることを、検索によって確認できること
以下の設問はそれぞれ独立したプログラムとして実装してください。
## ファイル名・フォルダ構成
- 設問ごとに1つのフォルダを作成し、そのフォルダの直下にプログラムのファイルを配置すること。
- フォルダ名は、設問番号に対応した連番(`question01`、`question02`、…)とすること(全言語共通・小文字)。
- ファイル名は、設問番号に対応した連番(`Question01`、`Question02`、…)を基本とし、言語の慣習に合わせて次のとおりとすること。
- 本問題(Question04-Update)の構成は次のとおり。
```
Question04-Update/
├── question01/    ← 設問1
│ └── Question01.<拡張子>
├── question02/    ← 設問2
│ └── Question02.<拡張子>
└── question03/    ← 設問3
└── Question03.<拡張子>
```
- Java: `Question01.java`(公開クラス名もファイル名と同じ `Question01` とする)
- C#: `Question01.cs`
- PHP: `Question01.php`
- Python: `question01.py`(モジュール名は小文字とする慣習のため、ファイル名のみ小文字)
- 上記ツリー中の `Question01.<拡張子>` は、使用する言語に応じて上記のファイル名に読み替えること。
- プロジェクトファイルが必要な場合など、言語・開発環境の規則上やむを得ない場合は、その規則を優先してよい。その場合も、設問ごとのフォルダ分けと連番の命名は維持すること。
- 設問内で追加で作成するクラス・関数などは、その設問のフォルダ直下に配置すること。
- 他の設問で作成したクラス等を使用する設問では、各フォルダ単独で実行できるよう、そのフォルダ直下にも同じ内容を配置すること。
---
## 設問1
標準入力から部署IDと新しい部署名を受け取り、その部署IDに一致する部署の部署名を更新するプログラムを実装してください。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- 「更新対象の部署IDを入力してください」と表示して標準入力から部署IDを読み込み、続けて「新しい部署名を入力してください」と表示して標準入力から新しい部署名を読み込むこと
- 部署名の更新には、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用すること
- 更新の結果、実際に更新された件数を確認し、次のとおり出力すること
- 1件以上更新された場合:「更新完了」
- 該当する部署IDが存在せず、1件も更新されなかった場合:「一致する部署は見つかりませんでした」
- 更新完了の出力に続けて、「確認のため、検索する部署IDを入力してください」と表示し、標準入力から部署IDを読み込んだうえで、その部署IDに一致する部署のデータを部署テーブルから検索し、検索結果(部署ID・部署名)をタブ区切りで出力すること(更新内容がデータベースに反映されていることを、自分で検索して確認できるようにする)
### 実行例
- 「更新対象の部署IDを入力してください」に対して `2`、「新しい部署名を入力してください」に対して `人材開発部` と入力した場合
- 出力:`更新完了`
- 続けて「確認のため、検索する部署IDを入力してください」と表示された後に `2` と入力した場合
- 出力:`2 人材開発部`
- 「更新対象の部署IDを入力してください」に対して `99`(存在しない部署ID)、「新しい部署名を入力してください」に対して `広報部` と入力した場合
- 出力:`一致する部署は見つかりませんでした`
---
## 設問2
部署テーブルに登録されている**すべて**の部署の部署名の末尾に、共通の文字列「(本社)」を追加する一括更新を行うプログラムを実装してください(部署IDによる絞り込みは行わず、全件を対象とすること)。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- 更新の結果、実際に更新された件数を確認し、「X件更新しました」(Xは更新件数)の形式で出力すること
- 出力に続けて、「確認のため、検索する部署IDを入力してください」と表示し、標準入力から部署IDを読み込んだうえで、その部署IDに一致する部署のデータを部署テーブルから検索し、検索結果(部署ID・部署名)をタブ区切りで出力すること(更新内容がデータベースに反映されていることを、自分で検索して確認できるようにする)
### 実行例
- 出力:`5件更新しました`
- 続けて「確認のため、検索する部署IDを入力してください」と表示された後に `1` と入力した場合
- 出力:`1 営業部(本社)`
### 注意
- この設問のプログラムは、実行するたびに部署名の末尾へ「(本社)」を追加します。続けて2回以上実行すると「営業部(本社)(本社)」のように重複して追加されるため、実行する前には、テーブル作成用SQLを実行し直して初期データの状態に戻してください([共通の前提](../00.共通前提.md)を参照)。
---
## 設問3
標準入力から部署名の一部の文字列を受け取り、部署名にその文字列を含むすべての部署の部署名の末尾に、共通の文字列「(本社)」を追加する一括更新を行うプログラムを実装してください(該当する部署は0件・1件・複数件のいずれの場合もあります)。
### 手順・要件
1. 「更新対象とする部署名の一部を入力してください」と表示する
2. 標準入力から1行分のテキストを読み込む
3. 読み込んだ文字列を部署名に含むすべての部署を対象に、部署名の末尾に「(本社)」を追加する更新を行う。この際、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用し、部分一致条件として値を渡すこと
4. 更新の結果、実際に更新された件数を確認し、次のとおり出力すること
- 1件以上更新された場合:「X件更新しました」(Xは更新件数)
- 該当する部署が存在せず、1件も更新されなかった場合:「一致する部署は見つかりませんでした」
5. 1件以上更新した場合は、続けて「確認のため、検索する部署IDを入力してください」と表示し、標準入力から部署IDを読み込んだうえで、その部署IDに一致する部署のデータを検索し、検索結果(部署ID・部署名)をタブ区切りで出力すること(更新内容がデータベースに反映されていることを、自分で検索して確認できるようにする)。手順4で1件も更新されなかった場合、この確認のための検索は行わない
### 実行例
- 入力が `部` の場合
- 出力:`3件更新しました`
- 続けて「確認のため、検索する部署IDを入力してください」と表示された後に `2` と入力した場合
- 出力:`2 人事部(本社)`
- 入力が `総務`(一致するものがない文字列)の場合
- 出力:`一致する部署は見つかりませんでした`
### 注意
- 設問2を実行した後のデータベースでこの設問を実行すると、部署名が既に「営業部(本社)」のようになっているため、「営業部(本社)(本社)」のように重複して追加されます。この設問を実行する前(2回目以降の実行も含む)には、テーブル作成用SQLを実行し直して初期データの状態に戻してください([共通の前提](../00.共通前提.md)を参照)。

View File

@@ -0,0 +1,125 @@
# Question05 - 更新系SQL(削除)
本資料の練習問題は、複数のプログラミング言語(Java / PHP / C# / Python)で共通して利用できるよう記述されています。使用するデータベース接続の仕組み(JDBC、PDO、ADO.NET、DB-API 2.0準拠のドライバ など)やSQLへのパラメータの指定方法、自動採番された値の取得方法など、言語・環境固有の仕様に基づき、問題文の表現をご使用の環境の仕様に適宜読み替えて進めてください。
[共通の前提](../00.共通前提.md)を参照してください。
## この問題のねらい
- データベースに登録されている既存のデータを削除するSQLを実行できること
- 削除条件(対象を絞り込む条件)を変えることで、削除される件数が変わることを理解する
- 削除した内容が実際にデータベースへ反映されていることを、検索によって確認できること
以下の設問はそれぞれ独立したプログラムとして実装してください。
部署ID `1`〜`3` の部署には社員テーブルの社員が所属しているため、削除しようとするとエラーになります。動作確認では、所属する社員がいない部署ID `4`・`5` の部署(東京支店・大阪支店)を削除の対象としてください([共通の前提](../00.共通前提.md)を参照)。
## ファイル名・フォルダ構成
- 設問ごとに1つのフォルダを作成し、そのフォルダの直下にプログラムのファイルを配置すること。
- フォルダ名は、設問番号に対応した連番(`question01`、`question02`、…)とすること(全言語共通・小文字)。
- ファイル名は、設問番号に対応した連番(`Question01`、`Question02`、…)を基本とし、言語の慣習に合わせて次のとおりとすること。
- 本問題(Question05-Delete)の構成は次のとおり。
```
Question05-Delete/
├── question01/    ← 設問1
│ └── Question01.<拡張子>
├── question02/    ← 設問2
│ └── Question02.<拡張子>
└── question03/    ← 設問3
└── Question03.<拡張子>
```
- Java: `Question01.java`(公開クラス名もファイル名と同じ `Question01` とする)
- C#: `Question01.cs`
- PHP: `Question01.php`
- Python: `question01.py`(モジュール名は小文字とする慣習のため、ファイル名のみ小文字)
- 上記ツリー中の `Question01.<拡張子>` は、使用する言語に応じて上記のファイル名に読み替えること。
- プロジェクトファイルが必要な場合など、言語・開発環境の規則上やむを得ない場合は、その規則を優先してよい。その場合も、設問ごとのフォルダ分けと連番の命名は維持すること。
- 設問内で追加で作成するクラス・関数などは、その設問のフォルダ直下に配置すること。
- 他の設問で作成したクラス等を使用する設問では、各フォルダ単独で実行できるよう、そのフォルダ直下にも同じ内容を配置すること。
---
## 設問1
標準入力から部署IDを受け取り、その部署IDに一致する部署のデータを部署テーブルから削除するプログラムを実装してください。
**※この設問を実行する前(2回以上実行する場合も含む)に、テーブル作成用SQLを実行し直して、データベースを初期データの状態に戻してください。** 削除したデータは元に戻らないため、初期状態に戻さずに実行すると、削除の対象とする部署(東京支店・大阪支店)が残っておらず、実行例のとおりの結果になりません。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- 「削除対象の部署IDを入力してください」と表示し、標準入力から部署IDを読み込むこと
- 部署IDの指定には、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用すること
- 削除の結果、実際に削除された件数を確認し、次のとおり出力すること
- 1件以上削除された場合:「削除完了」
- 該当する部署IDが存在せず、1件も削除されなかった場合:「一致する部署は見つかりませんでした」
- 削除完了の出力に続けて、「確認のため、検索する部署IDを入力してください」と表示し、標準入力から部署IDを読み込んだうえで、その部署IDに一致する部署のデータを部署テーブルから検索すること(削除内容がデータベースに反映されていることを、自分で検索して確認できるようにする)。検索結果が存在しない場合は「一致する部署は見つかりませんでした」と出力し、存在する場合は検索結果(部署ID・部署名)をタブ区切りで出力すること
### 実行例
- 「削除対象の部署IDを入力してください」に対して `4` と入力した場合
- 出力:`削除完了`
- 続けて「確認のため、検索する部署IDを入力してください」と表示された後に `4` と入力した場合
- 出力:`一致する部署は見つかりませんでした`
- 「削除対象の部署IDを入力してください」に対して `99`(存在しない部署ID)と入力した場合
- 出力:`一致する部署は見つかりませんでした`
---
## 設問2
標準入力から部署IDの下限値を受け取り、その値以上の部署IDを持つすべての部署のデータを、部署テーブルから削除するプログラムを実装してください(該当する部署は0件・1件・複数件のいずれの場合もあります)。
**※この設問を実行する前(2回以上実行する場合も含む)に、テーブル作成用SQLを実行し直して、データベースを初期データの状態に戻してください。** 削除したデータは元に戻らないため、初期状態に戻さずに実行すると、削除の対象とする部署(東京支店・大阪支店)が残っておらず、実行例のとおりの結果になりません。
### 手順・要件
1. 次の処理を、有効な入力が得られるまで繰り返してください。
1. 「削除対象とする部署IDの下限値を入力してください」と表示する
2. 標準入力から1行分のテキストを読み込む
3. 読み込んだ内容が整数として解釈できない場合、「数値を入力してください」と表示し、手順1に戻る
4. 整数として解釈できた場合、その値を下限値として繰り返し処理を終了する
2. 確定した下限値を使って、部署テーブルから、部署IDがその値以上であるデータを削除する。この際、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用し、比較演算子を伴う条件として値を渡すこと
3. 削除の結果、実際に削除された件数を確認し、次のとおり出力すること
- 1件以上削除された場合:「X件削除しました」(Xは削除件数)
- 該当する部署が存在せず、1件も削除されなかった場合:「一致する部署は見つかりませんでした」
4. 1件以上削除した場合は、続けて「確認のため、検索する部署IDを入力してください」と表示し、標準入力から部署IDを読み込んだうえで、その部署IDに一致する部署のデータを検索すること(削除内容がデータベースに反映されていることを、自分で検索して確認できるようにする)。検索結果が存在しない場合は「一致する部署は見つかりませんでした」と出力し、存在する場合は検索結果(部署ID・部署名)をタブ区切りで出力すること。手順3で1件も削除されなかった場合、この確認のための検索は行わない
### 実行例
- 入力が `4` の場合
- 出力:`2件削除しました`
- 続けて「確認のため、検索する部署IDを入力してください」と表示された後に `4` と入力した場合
- 出力:`一致する部署は見つかりませんでした`
- 入力が `10`(該当する部署がない値)の場合
- 出力:`一致する部署は見つかりませんでした`
---
## 設問3
標準入力から部署名の一部の文字列を受け取り、部署名にその文字列を含むすべての部署のデータを、部署テーブルから削除するプログラムを実装してください。
**※この設問を実行する前(2回以上実行する場合も含む)に、テーブル作成用SQLを実行し直して、データベースを初期データの状態に戻してください。** 削除したデータは元に戻らないため、初期状態に戻さずに実行すると、削除の対象とする部署(東京支店・大阪支店)が残っておらず、実行例のとおりの結果になりません。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- 「削除対象の部署名の一部を入力してください」と表示し、標準入力から部署名の一部の文字列を読み込むこと
- 部署名の指定には、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用し、部分一致検索に対応した形で値を渡すこと
- 削除の結果、実際に削除された件数を確認し、次のとおり出力すること
- 1件以上削除された場合:「X件削除しました」(Xは削除件数)
- 一致するデータが存在せず、1件も削除されなかった場合:「一致する部署は見つかりませんでした」
- 1件以上削除した場合は、続けて「確認のため、検索する部署IDを入力してください」と表示し、標準入力から部署IDを読み込んだうえで、その部署IDに一致する部署のデータを検索すること(削除内容がデータベースに反映されていることを、自分で検索して確認できるようにする)。検索結果が存在しない場合は「一致する部署は見つかりませんでした」と出力し、存在する場合は検索結果(部署ID・部署名)をタブ区切りで出力すること。一致するデータが存在せず削除が行われなかった場合、この確認のための検索は行わない
### 実行例
- 「削除対象の部署名の一部を入力してください」に対して `支店` と入力した場合
- 出力:`2件削除しました`
- 続けて「確認のため、検索する部署IDを入力してください」と表示された後に `4` と入力した場合
- 出力:`一致する部署は見つかりませんでした`
- 「削除対象の部署名の一部を入力してください」に対して `総務`(一致するものがない文字列)と入力した場合
- 出力:`一致する部署は見つかりませんでした`

View File

@@ -0,0 +1,123 @@
# Question06 - 複数テーブルの結合検索
本資料の練習問題は、複数のプログラミング言語(Java / PHP / C# / Python)で共通して利用できるよう記述されています。使用するデータベース接続の仕組み(JDBC、PDO、ADO.NET、DB-API 2.0準拠のドライバ など)やSQLへのパラメータの指定方法、自動採番された値の取得方法など、言語・環境固有の仕様に基づき、問題文の表現をご使用の環境の仕様に適宜読み替えて進めてください。
[共通の前提](../00.共通前提.md)を参照してください。
## この問題のねらい
- 複数のテーブルを内部結合(INNER JOIN)して検索し、関連するデータをまとめて取得できること
## 前提:社員テーブル(employee)
共通の前提の部署テーブルに加えて、以下の項目を持つ「社員」テーブルが、あらかじめ用意されているものとします。社員テーブルの各データは、所属する部署を部署IDで参照します。
| カラム名 | 内容 | 型 |
| --- | --- | --- |
| id_employee | 社員ID(主キー。新規登録時は自動的に採番される) | 整数 |
| nm_employee | 社員名 | 文字列 |
| id_department | 所属する部署の部署ID(部署テーブルのid_departmentを参照) | 整数 |
初期データとして、以下の4件が登録されているものとします。
| id_employee | nm_employee | id_department |
| --- | --- | --- |
| 1 | 山田太郎 | 1 |
| 2 | 鈴木花子 | 2 |
| 3 | 佐藤次郎 | 3 |
| 4 | 田中三郎 | 1 |
以下の設問はそれぞれ独立したプログラムとして実装してください。
## ファイル名・フォルダ構成
- 設問ごとに1つのフォルダを作成し、そのフォルダの直下にプログラムのファイルを配置すること。
- フォルダ名は、設問番号に対応した連番(`question01`、`question02`、…)とすること(全言語共通・小文字)。
- ファイル名は、設問番号に対応した連番(`Question01`、`Question02`、…)を基本とし、言語の慣習に合わせて次のとおりとすること。
- 本問題(Question06-Join)の構成は次のとおり。
```
Question06-Join/
├── question01/    ← 設問1
│ └── Question01.<拡張子>
├── question02/    ← 設問2
│ └── Question02.<拡張子>
└── question03/    ← 設問3
└── Question03.<拡張子>
```
- Java: `Question01.java`(公開クラス名もファイル名と同じ `Question01` とする)
- C#: `Question01.cs`
- PHP: `Question01.php`
- Python: `question01.py`(モジュール名は小文字とする慣習のため、ファイル名のみ小文字)
- 上記ツリー中の `Question01.<拡張子>` は、使用する言語に応じて上記のファイル名に読み替えること。
- プロジェクトファイルが必要な場合など、言語・開発環境の規則上やむを得ない場合は、その規則を優先してよい。その場合も、設問ごとのフォルダ分けと連番の命名は維持すること。
- 設問内で追加で作成するクラス・関数などは、その設問のフォルダ直下に配置すること。
- 他の設問で作成したクラス等を使用する設問では、各フォルダ単独で実行できるよう、そのフォルダ直下にも同じ内容を配置すること。
---
## 設問1
社員テーブルと部署テーブルを内部結合し、社員ID順に、すべての社員の社員名と、その社員が所属する部署の部署名を取得して出力するプログラムを実装してください。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- テーブルの結合には内部結合(INNER JOIN)を使用し、2つのテーブルのデータを1回のSQLで取得すること
- 取得結果を先頭から1件ずつ取り出し、社員名・部署名をタブ区切りで出力すること
### 実行例
```
山田太郎 営業部
鈴木花子 人事部
佐藤次郎 開発部
田中三郎 営業部
```
---
## 設問2
標準入力から部署名を受け取り、社員テーブルと部署テーブルを内部結合して、その部署名に一致する部署に所属する社員を社員ID順に取得し、社員名を出力するプログラムを実装してください(該当する社員は0件・1件・複数件のいずれの場合もあります)。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- 「検索する部署名を入力してください」と表示し、標準入力から部署名を読み込むこと
- テーブルの結合には内部結合(INNER JOIN)を使用して2つのテーブルのデータを1回のSQLで取得し、部署名による絞り込みは、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用すること
- 取得結果を先頭から1件ずつ取り出し、社員名を1件ずつ出力すること
- 該当する社員が1件も存在しない場合は、「一致する社員は見つかりませんでした」と出力すること
### 実行例
- 入力が `営業部` の場合
- 出力:
```
山田太郎
田中三郎
```
- 入力が `広報部`(存在しない部署名)の場合
- 出力:`一致する社員は見つかりませんでした`
---
## 設問3
社員テーブルと部署テーブルを内部結合し、部署ごとに所属する社員の人数を集計したうえで、部署IDの昇順で、部署名と所属人数を出力するプログラムを実装してください。
### 要件
- データベースへの接続・SQLの実行・接続の切断を、すべて自分で実装すること
- テーブルの結合・人数の集計は、1件ずつ数える繰り返し処理ではなく、1回のSQLで行うこと。結合には内部結合(INNER JOIN)を、人数の集計には集計関数に相当する仕組みを使用すること
- 内部結合のため、所属する社員がいない部署(東京支店・大阪支店)は出力されない
- 取得結果を先頭から1件ずつ取り出し、「(部署名):(所属人数)人」の形式で出力すること
### 実行例
```
営業部:2人
人事部:1人
開発部:1人
```

View File

@@ -0,0 +1,147 @@
# Question07 - 接続・切断処理の共通部品化
本資料の練習問題は、複数のプログラミング言語(Java / PHP / C# / Python)で共通して利用できるよう記述されています。使用するデータベース接続の仕組み(JDBC、PDO、ADO.NET、DB-API 2.0準拠のドライバ など)やSQLへのパラメータの指定方法、自動採番された値の取得方法など、言語・環境固有の仕様に基づき、問題文の表現をご使用の環境の仕様に適宜読み替えて進めてください。
[共通の前提](../00.共通前提.md)を参照してください。
## この問題のねらい
- データベースへの接続・切断や、後処理のクローズ処理など、複数のプログラムで共通して必要になる処理を、再利用可能な部品としてまとめられること
- 既に作成したプログラムを、入力と出力(動作)を変えずに、共通部品を使う形に書き直せること
これまでの問題(`Question01`〜`Question05`)では、プログラムごとにデータベースへの接続・切断の処理を毎回自分で実装してきました。この問題では、それらの共通する処理を1つの部品にまとめ、以前の問題で作成したプログラムを、その部品を使う形に書き直します。
扱うSQLや入出力は以前の問題と同じです。新しい処理を覚えるのではなく、**書き直す前と同じ入力を与えて、同じ出力になること**を確認しながら進めてください。
以下の設問1で作成する共通部品は、設問2・3でもそのまま使用します。
## ファイル名・フォルダ構成
- 設問ごとに1つのフォルダを作成し、そのフォルダの直下にプログラムのファイルを配置すること。
- フォルダ名は、設問番号に対応した連番(`question01`、`question02`、…)とすること(全言語共通・小文字)。
- ファイル名は、設問番号に対応した連番(`Question01`、`Question02`、…)を基本とし、言語の慣習に合わせて次のとおりとすること。
- 本問題(Question07-ConnectionUtility)の構成は次のとおり。
```
Question07-ConnectionUtility/
├── question01/       ← 設問1
│ ├── Question01.<拡張子>
│ └── common/
│ └── DbUtil.<拡張子> ← 共通部品
├── question02/       ← 設問2
│ ├── Question02.<拡張子>
│ └── common/
│ └── DbUtil.<拡張子> ← 設問1と同じ内容
└── question03/       ← 設問3
├── Question03.<拡張子>
└── common/
└── DbUtil.<拡張子> ← 設問1と同じ内容
```
- Java: `Question01.java`(公開クラス名もファイル名と同じ `Question01` とする)
- C#: `Question01.cs`
- PHP: `Question01.php`
- Python: `question01.py`(モジュール名は小文字とする慣習のため、ファイル名のみ小文字)
- 上記ツリー中の `Question01.<拡張子>` は、使用する言語に応じて上記のファイル名に読み替えること。
- プロジェクトファイルが必要な場合など、言語・開発環境の規則上やむを得ない場合は、その規則を優先してよい。その場合も、設問ごとのフォルダ分けと連番の命名は維持すること。
- 共通部品は、各設問のフォルダの中に `common` フォルダを作成し、その中に配置すること。共通部品のファイル名は、言語の慣習に合わせて次のとおりとすること(クラス名を付ける言語では、クラス名も `DbUtil` とする)。
| 部品 | フォルダ | Java | C# | PHP | Python |
| --- | --- | --- | --- | --- | --- |
| 共通部品(接続・切断) | `common` | `DbUtil.java` | `DbUtil.cs` | `DbUtil.php` | `db_util.py` |
- 共通部品は設問2・3でも使用するため、各フォルダ単独で実行できるよう、設問2・3のフォルダにも設問1と同じ内容の `common` フォルダを配置すること。
---
## 設問1
### 共通部品の作成
次の3つの処理を持つ、データベース接続用の共通部品(`common` フォルダの `DbUtil`。ファイル名は「ファイル名・フォルダ構成」を参照)を作成してください(以降の設問でも、この共通部品をそのまま使用します。内容は変更しないものとします)。
1. **接続を取得する処理**:共通の前提のデータベースに接続し、接続を表す値を返す
2. **ステートメントをクローズする処理**:SQL実行に使用した値(ステートメント)を受け取り、値が存在する場合にクローズする
3. **接続を切断する処理**:接続を表す値を受け取り、値が存在する場合に切断する
- 補足: 使用する言語に、ステートメントに相当する値を明示的にクローズする標準的な手段がない場合は、後始末に相当する処理(結果セットの解放や、変数への `null` の代入など)で代用してよい
### 書き直すプログラム
`Question01`の設問1で作成したプログラム(部署テーブルの全件を部署IDの昇順で出力するプログラム)を、作成した共通部品を使う形に書き直してください。
### 要件
- データベースへの接続・ステートメントのクローズ・接続の切断は、すべて共通部品を経由して行い、書き直したプログラムの中には接続・切断の処理を直接記述しないこと
- 入力と出力は、書き直す前と同じとすること。具体的には次のとおり
- 部署テーブルから全件のデータ(部署ID・部署名)を取得し、部署IDの昇順で、1件につき1行、部署IDと部署名をタブ区切りで出力する
### 動作確認
書き直す前と同じ出力になることを確認してください(`Question01`の設問1の実行例と同じです)。
```
1 営業部
2 人事部
3 開発部
4 東京支店
5 大阪支店
```
---
## 設問2
`Question02`の設問1で作成したプログラム(標準入力から受け取った部署IDに一致する部署のデータを出力するプログラム)を、設問1で作成した共通部品を使う形に書き直してください。
### 要件
- データベースへの接続・ステートメントのクローズ・接続の切断は、すべて設問1で作成した共通部品を経由して行い、書き直したプログラムの中には接続・切断の処理を直接記述しないこと
- 入力と出力は、書き直す前と同じとすること。具体的には次のとおり
1. 次の処理を、有効な入力が得られるまで繰り返す
1. 「検索する部署IDを入力してください」と表示する
2. 標準入力から1行分のテキストを読み込む
3. 読み込んだ内容が整数として解釈できない場合、「数値を入力してください」と表示し、手順1に戻る
4. 整数として解釈できた場合、その値を部署IDとして繰り返し処理を終了する
2. 確定した部署IDを使って、部署テーブルから一致するデータを検索する。この際、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用する
3. 検索結果が存在する場合、その部署ID・部署名をタブ区切りで出力する
4. 検索結果が存在しない場合、「一致する部署は見つかりませんでした」と出力する
### 動作確認
書き直す前と同じ入力を与え、同じ出力になることを確認してください(`Question02`の設問1の実行例と同じです)。
- 入力が `2` の場合
- 出力:`2 人事部`
- 入力が `99`(存在しない部署ID)の場合
- 出力:`一致する部署は見つかりませんでした`
- 入力が `abc`(数値でない)の場合
- 出力:`数値を入力してください`(その後、再度入力を促す)
---
## 設問3
`Question04`の設問1で作成したプログラム(標準入力から受け取った部署IDの部署名を更新するプログラム)を、設問1で作成した共通部品を使う形に書き直してください。
### 要件
- データベースへの接続・ステートメントのクローズ・接続の切断は、すべて設問1で作成した共通部品を経由して行い、書き直したプログラムの中には接続・切断の処理を直接記述しないこと
- 入力と出力は、書き直す前と同じとすること。具体的には次のとおり
- 「更新対象の部署IDを入力してください」と表示して標準入力から部署IDを読み込み、続けて「新しい部署名を入力してください」と表示して標準入力から新しい部署名を読み込む
- 部署名の更新には、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用する
- 更新の結果、実際に更新された件数を確認し、次のとおり出力する
- 1件以上更新された場合:「更新完了」
- 該当する部署IDが存在せず、1件も更新されなかった場合:「一致する部署は見つかりませんでした」
- 更新完了の出力に続けて、「確認のため、検索する部署IDを入力してください」と表示し、標準入力から部署IDを読み込んだうえで、その部署IDに一致する部署のデータを部署テーブルから検索し、検索結果(部署ID・部署名)をタブ区切りで出力する
### 動作確認
書き直す前と同じ入力を与え、同じ出力になることを確認してください(`Question04`の設問1の実行例と同じです)。
- 「更新対象の部署IDを入力してください」に対して `2`、「新しい部署名を入力してください」に対して `人材開発部` と入力した場合
- 出力:`更新完了`
- 続けて「確認のため、検索する部署IDを入力してください」と表示された後に `2` と入力した場合
- 出力:`2 人材開発部`
- 「更新対象の部署IDを入力してください」に対して `99`(存在しない部署ID)、「新しい部署名を入力してください」に対して `広報部` と入力した場合
- 出力:`一致する部署は見つかりませんでした`

View File

@@ -0,0 +1,273 @@
# Question08 - データアクセス・データ受け渡し専用の部品の導入(基本CRUD一式)
本資料の練習問題は、複数のプログラミング言語(Java / PHP / C# / Python)で共通して利用できるよう記述されています。使用するデータベース接続の仕組み(JDBC、PDO、ADO.NET、DB-API 2.0準拠のドライバ など)やSQLへのパラメータの指定方法、自動採番された値の取得方法など、言語・環境固有の仕様に基づき、問題文の表現をご使用の環境の仕様に適宜読み替えて進めてください。
[共通の前提](../00.共通前提.md)を参照してください。
## この問題のねらい
- データベースへのアクセス処理を専門に行う部品(DAOに相当する仕組み)を作り、呼び出し元と分離できること
- テーブルの1行分のデータを保持する、データ受け渡し専用の入れ物(DTOに相当する仕組み)を作り、データアクセス部品と呼び出し元の間のデータのやり取りに使えること
- 検索・登録・更新・削除という基本的なデータ操作一式を、同じデータアクセス部品にまとめられること
以下の設問1で作成する部署データ・部署データアクセス部品は、設問2以降でもそのまま使用・拡張します。
## ファイル名・フォルダ構成
- 設問ごとに1つのフォルダを作成し、そのフォルダの直下にプログラムのファイルを配置すること。
- フォルダ名は、設問番号に対応した連番(`question01`、`question02`、…)とすること(全言語共通・小文字)。
- ファイル名は、設問番号に対応した連番(`Question01`、`Question02`、…)を基本とし、言語の慣習に合わせて次のとおりとすること。
- 本問題(Question08-DaoDtoCrud)の構成は次のとおり。
```
Question08-DaoDtoCrud/
├── question01/         ← 設問1
│ ├── Question01.<拡張子>
│ ├── common/
│ │ └── DbUtil.<拡張子>    ← Question07の共通部品
│ ├── dto/
│ │ └── DepartmentDTO.<拡張子> ← 部署データ
│ └── dao/
│ └── DepartmentDAO.<拡張子> ← 部署データアクセス部品
├── question02/         ← 設問2
│ ├── Question02.<拡張子>
│ ├── common/
│ │ └── DbUtil.<拡張子>    ← Question07の共通部品
│ ├── dto/
│ │ └── DepartmentDTO.<拡張子> ← 部署データ
│ └── dao/
│ └── DepartmentDAO.<拡張子> ← 部署データアクセス部品
├── question03/         ← 設問3
│ ├── Question03.<拡張子>
│ ├── common/
│ │ └── DbUtil.<拡張子>    ← Question07の共通部品
│ ├── dto/
│ │ └── DepartmentDTO.<拡張子> ← 部署データ
│ └── dao/
│ └── DepartmentDAO.<拡張子> ← 部署データアクセス部品
├── question04/         ← 設問4
│ ├── Question04.<拡張子>
│ ├── common/
│ │ └── DbUtil.<拡張子>    ← Question07の共通部品
│ ├── dto/
│ │ └── DepartmentDTO.<拡張子> ← 部署データ
│ └── dao/
│ └── DepartmentDAO.<拡張子> ← 部署データアクセス部品
└── question05/         ← 設問5
├── Question05.<拡張子>
├── common/
│ └── DbUtil.<拡張子>    ← Question07の共通部品
├── dto/
│ └── DepartmentDTO.<拡張子> ← 部署データ
└── dao/
└── DepartmentDAO.<拡張子> ← 部署データアクセス部品
```
- Java: `Question01.java`(公開クラス名もファイル名と同じ `Question01` とする)
- C#: `Question01.cs`
- PHP: `Question01.php`
- Python: `question01.py`(モジュール名は小文字とする慣習のため、ファイル名のみ小文字)
- 上記ツリー中の `Question01.<拡張子>` は、使用する言語に応じて上記のファイル名に読み替えること。
- プロジェクトファイルが必要な場合など、言語・開発環境の規則上やむを得ない場合は、その規則を優先してよい。その場合も、設問ごとのフォルダ分けと連番の命名は維持すること。
- 部品は、各設問のフォルダの中に次のフォルダを作成し、その中に配置すること。ファイル名は言語の慣習に合わせて次のとおりとすること(クラス名を付ける言語では、クラス名もファイル名の拡張子を除いた部分と同じ `DbUtil`・`DepartmentDTO`・`DepartmentDAO` とする)。
| 部品 | フォルダ | Java | C# | PHP | Python |
| --- | --- | --- | --- | --- | --- |
| 共通部品(接続・切断。`Question07`で作成したもの) | `common` | `DbUtil.java` | `DbUtil.cs` | `DbUtil.php` | `db_util.py` |
| 部署データ | `dto` | `DepartmentDTO.java` | `DepartmentDTO.cs` | `DepartmentDTO.php` | `department_dto.py` |
| 部署データアクセス部品 | `dao` | `DepartmentDAO.java` | `DepartmentDAO.cs` | `DepartmentDAO.php` | `department_dao.py` |
- 部署データ・部署データアクセス部品は設問2以降で拡張していくため、各設問のフォルダには、その設問の時点の内容を配置すること(各フォルダ単独で実行できるようにする)。共通部品は、`Question07`で作成したものと同じ内容を配置すること。
---
## 設問1
部署の1件分のデータ(部署ID・部署名)を保持する入れ物(以下「部署データ」とする。`dto` フォルダの `DepartmentDTO`)を作成してください。
`Question07`で作成した共通部品(`common` フォルダの `DbUtil`)を使用して、データベースへのアクセス処理を専門に行う部品(以下「部署データアクセス部品」とする。`dao` フォルダの `DepartmentDAO`)を作成してください。
まず、部署データアクセス部品に、次の全件取得処理を追加してください。
- 部署テーブルから全件のデータを取得し、1件ずつ部署データに変換したうえで、部署データの一覧(リスト)として返す処理
呼び出し元のプログラムでは、部署データアクセス部品の全件取得処理を呼び出し、取得した一覧を先頭から順に取り出して、それぞれの部署ID・部署名をタブ区切りで出力してください。
### 要件
- 実際にデータベースへ接続してSQLを実行する処理は、すべて部署データアクセス部品の内部で行うこと
- 取得したデータは、部署データという入れ物を経由して呼び出し元に渡すこと
### ヒント
- 部品の役割分担は次のとおりです。呼び出し元のプログラムにはSQLや接続・切断の処理が出てこず、部署データアクセス部品を呼び出すだけになるのが完成形です。
```
呼び出し元(Question01)
│ ① 全件取得処理を呼び出す
▼
部署データアクセス部品(DepartmentDAO)
│ ② 共通部品(DbUtil)で接続し、SQLを実行する
▼
データベース
│ ③ 結果を1行ずつ部署データ(DepartmentDTO)に詰めて一覧にし、呼び出し元へ返す
▼
呼び出し元(Question01)
④ 一覧から部署データを1つずつ取り出し、部署ID・部署名を出力する
```
- **部署データ(DepartmentDTO)**:部署ID・部署名の2つの項目と、それぞれの値を設定する手段・取り出す手段だけを持たせます。データベースへのアクセスや出力の処理は持たせません。
- **部署データアクセス部品(DepartmentDAO)の全件取得処理**:取得結果を1行ずつ取り出すたびに部署データを1つ作って部署ID・部署名を設定し、一覧に追加していきます。最後に、その一覧を戻り値として返します。接続の取得・切断には共通部品を使います。
- **呼び出し元**:全件取得処理の戻り値(部署データの一覧)を先頭から順に取り出し、部署データから部署ID・部署名を取り出して出力します。
### 実行例
```
1 営業部
2 人事部
3 開発部
4 東京支店
5 大阪支店
```
---
## 設問2
設問1の部署データアクセス部品に、次の1件取得処理を追加してください。
- 部署IDを1つ受け取り、部署テーブルから該当する部署のデータを検索し、見つかった場合は部署データに変換して返す処理。該当するデータが存在しない場合は、値が無いことを示す特別な値(以下「値なし」とする。Java・C#・PHP: `null`/Python: `None`)を返すものとする
呼び出し元のプログラムでは、「検索する部署IDを入力してください」と表示して標準入力から部署IDを受け取り、部署データアクセス部品の1件取得処理を呼び出してください。
### 要件
- 実際にデータベースへ接続してSQLを実行する処理は、すべて部署データアクセス部品の内部で行うこと
- 取得結果が「値なし」かどうかを明示的に判定し、次のとおり出力すること
- 見つかった場合:部署ID・部署名をタブ区切りで出力する
- 見つからなかった場合:「一致する部署は見つかりませんでした」と出力する
### ヒント
- **部署データアクセス部品の1件取得処理**:受け取った部署IDをパラメータとして渡してSQLを実行します。結果が1行あれば部署データを1つ作って値を設定して返し、結果が無ければ「値なし」を返します。戻り値は、設問1の一覧ではなく部署データ1つ(または「値なし」)です。
- **呼び出し元**:戻り値を受け取ったら、まず「値なし」かどうかを判定し、値がある場合だけ部署データから部署ID・部署名を取り出して出力します。「値なし」のまま中身を取り出そうとすると、多くの言語でエラーになります。
### 実行例
- 入力が `2` の場合
- 出力:`2 人事部`
- 入力が `99`(存在しない部署ID)の場合
- 出力:`一致する部署は見つかりませんでした`
---
## 設問3
設問1の部署データアクセス部品に、次の登録処理を追加してください。
- 部署名を1つ受け取り、部署IDを指定せず(自動的に採番される値を使用して)、部署テーブルに新しいデータとして登録する処理
呼び出し元のプログラムでは、「登録する部署名を入力してください」と表示して標準入力から部署名を受け取り、部署データアクセス部品の登録処理を呼び出して登録を行ってください。
### 要件
- 実際にデータベースへ接続してSQLを実行する処理は、すべて部署データアクセス部品の内部で行い、呼び出し元はその部品を呼び出すだけにすること
- 部署名の登録には、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用すること
- 登録が完了したら、「登録完了」と出力すること
- 登録完了の出力に続けて、設問1で作成した全件取得処理を呼び出し、取得した部署データの一覧を部署IDの昇順で、1件につき1行、部署ID・部署名をタブ区切りで出力すること(登録内容がデータベースに反映されていることを、検索によって確認できるようにする)
### ヒント
- **部署データアクセス部品の登録処理**:部署名を受け取り、パラメータとして渡して登録のSQLを実行します。部署IDは自動的に採番されるため、受け取る必要はありません。
- **呼び出し元**:登録処理を呼び出して「登録完了」と出力した後、設問1の全件取得処理を呼び出します。一覧を出力する処理は設問1の呼び出し元と同じ書き方で実装できます。
- 「登録完了」などのメッセージは呼び出し元で出力し、部署データアクセス部品には出力の処理を持たせないようにすると、役割分担がはっきりします。
### 実行例
- 「登録する部署名を入力してください」に対して `広報部` と入力した場合
- 出力:
```
登録完了
1 営業部
2 人事部
3 開発部
4 東京支店
5 大阪支店
6 広報部
```
- 上記の部署ID `6` は、テーブル作成用SQLを実行して部署テーブルを作り直した直後に実行した場合の値です。自動採番される値は登録したデータを削除しても元に戻らないため、登録を繰り返した後などは、より大きい部署IDが採番されます。部署IDの数字だけが異なる場合は、実装の誤りではありません([共通の前提](../00.共通前提.md)を参照)。
---
## 設問4
設問1の部署データアクセス部品に、次の更新処理を追加してください。
- 部署IDと新しい部署名を受け取り、その部署IDに一致する部署の部署名を更新する処理
呼び出し元のプログラムでは、「更新対象の部署IDを入力してください」と表示して標準入力から部署IDを、続けて「新しい部署名を入力してください」と表示して標準入力から新しい部署名を受け取り、部署データアクセス部品の更新処理を呼び出して更新を行ってください。
### 要件
- 実際にデータベースへ接続してSQLを実行する処理は、すべて部署データアクセス部品の内部で行い、呼び出し元はその部品を呼び出すだけにすること
- 部署名の更新には、SQLに値を直接埋め込むのではなく、パラメータとして値を渡す仕組みを使用すること
- 部署データアクセス部品の更新処理は、処理結果として、実際に更新されたレコード件数(整数値)を返すこと
- 更新の結果、実際に更新された件数を確認し、次のとおり出力すること
- 1件以上更新された場合:「更新完了」
- 該当する部署IDが存在せず、1件も更新されなかった場合:「一致する部署は見つかりませんでした」
- 更新完了の場合は、続けて設問2で作成した1件取得処理を使って更新対象の部署IDのデータを取得し、部署ID・部署名をタブ区切りで出力すること(更新内容がデータベースに反映されていることを、検索によって確認できるようにする)。更新が行われなかった場合、この確認のための取得は行わない
### ヒント
- **部署データアクセス部品の更新処理**:部署IDと新しい部署名を受け取り、パラメータとして渡して更新のSQLを実行します。多くの言語・環境では、更新のSQLを実行すると、実際に更新された件数を取得できます。その件数をそのまま戻り値として返します。
- **呼び出し元**:更新処理の戻り値(更新件数)を見て、「更新完了」か「一致する部署は見つかりませんでした」かを判断して出力します。件数による判断と出力は部署データアクセス部品ではなく、呼び出し元で行います。
- 更新完了の場合の確認は、設問2の1件取得処理と、その戻り値から部署ID・部署名を取り出して出力する書き方をそのまま使えます。
### 実行例
- 「更新対象の部署IDを入力してください」に対して `2`、「新しい部署名を入力してください」に対して `人材開発部` と入力した場合
- 出力:
```
更新完了
2 人材開発部
```
- 「更新対象の部署IDを入力してください」に対して `99`(存在しない部署ID)、「新しい部署名を入力してください」に対して `広報部` と入力した場合
- 出力:`一致する部署は見つかりませんでした`
---
## 設問5
設問1の部署データアクセス部品に、次の削除処理を追加してください。
- 部署IDを1つ受け取り、部署テーブルから該当する部署のデータを削除する処理
呼び出し元のプログラムでは、「削除対象の部署IDを入力してください」と表示して標準入力から削除対象の部署IDを受け取り、部署データアクセス部品の削除処理を呼び出して削除を行ってください。
なお、部署ID `1`〜`3` の部署には社員テーブルの社員が所属しているため、削除しようとするとエラーになります。動作確認では、所属する社員がいない部署ID `4`・`5` の部署を削除の対象としてください([共通の前提](../00.共通前提.md)を参照)。削除したデータは元に戻らないため、この設問を実行する前(2回以上実行する場合も含む)には、テーブル作成用SQLを実行し直して、データベースを初期データの状態に戻してください。
### 要件
- 実際にデータベースへ接続してSQLを実行する処理は、すべて部署データアクセス部品の内部で行い、呼び出し元はその部品を呼び出すだけにすること
- 部署データアクセス部品の削除処理は、処理結果として、実際に削除されたレコード件数(整数値)を返すこと
- 削除の結果、実際に削除された件数を確認し、次のとおり出力すること
- 1件以上削除された場合:「削除完了」
- 該当する部署IDが存在せず、1件も削除されなかった場合:「一致する部署は見つかりませんでした」
- 削除完了の場合は、続けて設問2で作成した1件取得処理を使って削除対象の部署IDのデータを取得すること(削除内容がデータベースに反映されていることを、検索によって確認できるようにする)。取得結果が「値なし」であれば「一致する部署は見つかりませんでした」と出力する。削除が行われなかった場合、この確認のための取得は行わない
### ヒント
- **部署データアクセス部品の削除処理**:部署IDを受け取り、パラメータとして渡して削除のSQLを実行します。設問4の更新処理と同じく、SQLの実行で得られる実際に削除された件数を、そのまま戻り値として返します。
- **呼び出し元**:削除処理の戻り値(削除件数)を見て、「削除完了」か「一致する部署は見つかりませんでした」かを判断して出力します。
- 削除完了の場合の確認では、設問2の1件取得処理を呼び出し、戻り値が「値なし」であることを判定します。削除が正しく行われていれば、1件取得処理は「値なし」を返します。
### 実行例
- 「削除対象の部署IDを入力してください」に対して `4` と入力した場合
- 出力:
```
削除完了
一致する部署は見つかりませんでした
```
- 「削除対象の部署IDを入力してください」に対して `99`(存在しない部署ID)と入力した場合
- 出力:`一致する部署は見つかりませんでした`