コラム

カテゴリ:システム開発

最速でプログラマーを育てるアクセライトメソッド ~Lesson3 データベース編~

database

こんにちは、システム開発部の大下です。
今回はプログラマー研修第3回目、データベースです。

さて、データベースとは何でしょうか。プログラミング言語の名前ではありません。まずはwikipediaを参照してみましょう。

データベース(英: database, DB)とは、検索や蓄積が容易にできるよう整理された情報の集まり。 通常はコンピュータによって実現されたものを指すが、紙の住所録などをデータベースと呼ぶ場合もある。 狭義には、データベース管理システム (Database Management System, DBMS) またはそれが扱う対象のことをいう。

データベース

とのことです。
これは教科書的な定義ですので、ある程度わかっている人向けの認識補強ですね。今日はデータベースをゼロから考えてみます。

データベースの位置づけ

まずはプログラムにおけるデータベースの位置づけを考えてみましょう。

プログラムの構成要素は、大きくはロジックとデータに分かれます。

スーパーマリオを例に説明すると、Aボタンを押したらジャンプして、タイムオーバーになったらマリオを一人失うといった決まり/手続きがロジックです。今キノコを食べて大きくなってるとか、予備のキノコを持ってる、マリオはあと7人いるとか、そういった情報を保持しているのがデータとなります。

マリオや土管のグラフィックは画像ファイルですのでこれもデータですね。ただしこれらはゲームの途中で変化しない静的なデータになり、一方でアイテムリストとかコインの数とかはゲーム中に変動する動的なデータとなります。

super_mario

さて、プログラミングを始めると、やはりゲームを書きたくなります。前回は単語当てゲームなんてのをやりました。

(a)単語あてゲームを作成せよ。
ゲームのルールは以下のとおりとする。まず、正解の単語(英単語)をあらかじめ決めておく。ここでは例として、単語を “accelight” とする。
つぎに、プレイヤーはアルファベットを入力する。入力した英数字が’a’であれば、”a********”のように正解の単語のうち、そのアルファベットのaの文字のところだけを表示し、他はアスタリスクで表示する。次に’i’を入力した場合、”a****i***”と表示する。ヒントは5回とする。
ヒントを出すのが完了したら、”正解の単語を入力してください。”と表示し、プレイヤーに正解を入力させ、正否の結果を表示する。

シンプルなゲームですのですぐに作れました。ところが、少しばかり欲が出てきて、この単語当てゲームで一発当てたいと思いはじめました。目の付け所はさておき、その場合にはもっと本気で開発をする必要があります。

スコアを出したり、履歴機能も欲しいですね。ネットワーク対戦とかも熱いかも!

今までに勉強したプログラムでは、動的なデータ(ヒントを表示した回数、入力された文字のリスト等)は、全て変数に格納していました。プログラムが起動している限りはそれでも良いのですが、現状ですと、プログラムが終了したら動的なデータは全て消失します。これではリッチなユーザーエクスペリエンスを提供することができません。

そういえばかつてファミコンのソフトには動的なデータを保存する機能がありませんでした。毎回はじめからです。
ところがドラゴンクエスト3の”冒険の書”機能に代表されるセーブデータ機能の登場により、前回の続きからゲームを開始することができるようになり、人類は急激に幸せになりました。(それと同時に数々の悲劇も。。)

データの保存先はファイル

そのようなわけで、データはプレイの都度保存したいですね。そこで使用できるのがフォルダとファイル、のファイルです。
プログラムがデータを保存したい場合も、人間と同様、ファイルを利用します。プログラムは人間にできない突飛なことばかりをやっているわけではないのです。個人的にはここら辺の理解はとても大切だと思っています。

では早速ファイルにデータを書き込んでみましょう。フォーマットはプログラマが自由に決定することができます。

例えば

残機:7, 予備のキノコ:3

あたりでどうでしょう。

JSON形式が便利

アイテムにはキノコだけではなくフラワーとかスターとかも必要でした。アイテムを以下のようにまとめてみましょう。

残機:7, アイテム:{キノコ:3, フラワー:2, スター:0}

プログラムでは日本語がやや微妙な振る舞いをするので一般的には英数字と記号を使いますね。

remaining_mario:7,items:{mashroom:3,flower:2,star:0}

ここにもう少し装飾を施して、変数名や値を二重引用符でくくってみましょう。

{“remaining_mario”:”7″,”items”:{“mashroom”:”3″,”flower”:”2″,”star”:”0″}}

これはJSON形式といって、PHP→Javascript, Java→http→Ruby のように言語を横断する際にも共通語として使える大変便利な形式です。JavascriptをベースとしていますのでJavascriptだと変換なしでプログラム中に記述して配列やオブジェクトの初期化ができます。自然言語でいう英語のような立ち位置ですね。

昔はこのような共通言語がなかったため、言語間のやりとりではXMLが使われていました。ですがXMLはJSONに比べて記述が複雑になりがちで、可読性も低くやや扱いにくいというデメリットがあり、JSON形式はここ数年で主流のデータ形式になってきました。

では次に値を参照してみましょう。サンプルの言語は例によってPHPです。

// ファイル名
$file_path = ‘./userdata.db’;
// ファイルの中身を読みだす
$data_text = get_file_contents($file_path);
// JSON形式の文字列をphpのOBJECTに変換する
$data = json_decode($dta_text);
// キノコの数を取得する。キノコという属性がないとエラーになるのが嫌なので@を付けておくとエラーを防げる。
$num_kinoko = @$data->items->mashroom;

関数を使ってさらに便利にしてみましょう。

// 専用の関数を定義
function get_num_userdata_item($name) {
// ファイル名
$file_path = ‘./userdata.db’;
// ファイルの中身を読みだす
$data_text = get_file_contents($file_path);
// JSON形式の文字列をphpのOBJECTに変換する
$data = json_decode($dta_text);
// 引数に渡した名前のアイテム数を取得する。
$num_item = @$data->items->$name;

return $num_item;
}
// キノコの数を取得する
$num_kinoko = get_num_userdata_item(‘mashroom’);

結構便利ですね。
これで十分な気がしてきました。

ファイルに保存する問題点

実際のところサンプルとしてはこれで十分ですが、この手法には問題があります。

問題1 オーバーヘッドが大きい

データアクセスのたびにファイルを読み込んでいますので、データ量が増えてファイルサイズが大きくなってるくると、処理が重くなります。

全データを読み込んでおけばいいと思いましたか?そうするとメモリーを食いますし、あとは複数人で同時にデータにアクセスするという将来的な拡張に対応できません。

ですので理想は、必要なタイミングで必要な箇所のみをファイルに読み書きする、となります。

問題2 必要なデータを探すのが大変

JSON形式でデータを持つと、特定の条件をもつデータの抽出や、データの計算等が面倒です。
例えばアイテムの中で、個数が1個以上のものだけを取得したい場合、さきほどのケースですと、一覧を取得してループをする必要があります。

あるいはアイテムの合計数を取得したければやはり一覧を取得してループをする必要があります。

// 調べた結果を格納するための配列
$list = array();
// すべてのアイテムをループで処理
foreach ($data->items as $key => $num) {
// 0個より大きいもののみを配列につめる
if ($num > 0) {
$list[] = $key;
}
}
// 正しく取得できてるか出力してみる
var_dump($list);

でも本当はこんな感じで取得したいですよね。

// itemsの中で “num>0” の条件に合うものだけを取得する
$list = get_item($data, “num>0”); // こんな関数があったとしたら

問題3: データ構造を変更するのが大変

JSON形式の場合は割と柔軟なのですが、そもそものデータ構造を変化させる、とかそれに合わせて旧データを変換するとかは結構大変な作業になります。
プログラムを開発していくなかで、実はアイテムを保持していた履歴情報も持ちたくなった、とか、それぞれのアイテムの取得時刻まで記録する必要があったといったような拡張は常にあります。
仕様変更にストレスを抱くのはプログラマーの常ですが、事前に仕様変更の可能性を想定することと、拡張可能性を頭に入れて設計するのもプログラマの仕事です。

データをプリミティブに扱うことの最大の問題

そしてもうひとつの問題が、データを扱うということ自体は多くのプログラマーにとって退屈であることです。
マリオがジャンプをする処理とか、スターをとったら無敵になるといった処理を書いているときは楽しい作業に分類されますが、データが正しく保存されることを確保する作業というのは重要度が高い割りに退屈で気を使う作業です。
データはもっと気軽に扱いたいものです。何かいい方法はないかなぁ。

エクセルについて考える

もう少し引っ張りましょう。

プログラムをいったん離れてみて、現実的にPC上で上記のようなデータを持ちたいとき、あなたならどうしますか。私なら大好きなエクセルをつかいます。

エクセルだったらこんな感じですかね。

excel

エクセルであれば、シートを分けて上手にデータを管理しておくことで、フィルターを使って特定の行の抽出ができますし、列や行の追加、削除も簡単です。嗚呼、エクセルってなんて便利なんでしょう。

プログラムからもエクセルみたいにデータを扱えればいいのに。。
そうです、それがデータベースです。

データベースとエクセルの構造はよく似てる

データベースとエクセルの構造は非常によく似ています。
エクセルのファイルは、データベースでいう(狭義の)データベースと概ね同等です。
エクセルのシートは、データベースのテーブルと概ね同等です。
一枚のシート、ひとつのテーブルにはM列xN行のデータを扱うことができます。
大きな違いとしては、データベースのテーブルの列にはすべて同じ型の値が格納されますが、エクセルはどんな値を入れても自由です。Excel方眼紙なんて言葉があるくらいエクセルは自由です。

そのようなわけで、エクセルを扱うくらいの軽い気持ちでデータベースに向き合ってみてください。

SQLの命令は4つだけ(覚える)

そろそろ本題に入りましょう。
本日はデータベースの概念と、それを扱うためのSQLという言語を学習します。

関係データベース管理システム (RDBMS) において、データの操作や定義を行うためのデータベース言語(問い合わせ言語),ドメイン固有言語である。

SQL

とあるように、SQLはデータベースを扱う言語です。
言語というと敷居が高く感じるかもしれませんが、SQLについては覚えることが非常に少ないです。
データベースで覚えなければいけない命令は

  • データの取得(SELECT)
  • データの追加(INSERT)
  • データの変更(UPDATE)
  • データの削除(DELETE)

の4つになります。
ほかにもインスタンスやテーブルの作成、修正、削除といった命令もありますが、通常それらはGUIのツールを介して行いますので、SQLのコマンドとして覚える必要はありません。

さあ、これで心の準備は整いました。
覚えることは少ないですので気軽に取り組みましょう。

環境はMySQL, MariaDB, PostgreSQL, その他どのようなものでも問題ありません。
用意された/できる環境でやってみましょう。

9, 10 はそれぞれビューとストアドプロシージャに関する問題で、プロジェクトによって使う使わないが分かれたりすると思いますのでオプションです。
所要時間は1日~4日あたりで取り組んでください。

今回の振り返り

いかがでしたか。
データベースは様々なプログラムで必要になってくるツールですので、しっかり基本を押さえましょう。
覚えるべき命令は4つだけ、です。

次回はなんとオブジェクト指向について学習していきます。
要点をぎゅっと絞って導入しますのでお楽しみにしていてください。

大下知樹

この記事を書いた人

大下知樹

営業/設計をメインに、空いている時間でプログラミングも担当。目的の達成にこだわり、言語にはこだわらない。初学者に優しいPHPが好き。