Database 使い方

通常のデータベース命令は、DB クラスを通じて実行することになります。 Fuel ではどのようにデータベースを取り扱うかを以下の例で確認してみてください。

データベースの使用法は大きく2つに分けられます:

クエリの実行

始めに、DB::query を使用してクエリを準備します。

// 返り値: Database_Query オブジェクト
$query = DB::query('SELECT * FROM `users`');

これで、クエリを実行できます:

$query = DB::query('SELECT * FROM `users`');

// 返り値: Database_MySQLi_Result オブジェクト
$query->execute();

// 別のデータベース接続に対して実行したい場合
$query->execute('another_group');
// もしくは
$query->execute(Database_Connection::instance('another_group'));

// 以下のようにメソッドチェーンが可能です:
$result = DB::query('SELECT * FROM `users`')->execute();

SELECT 文

まずは DB::query を使用してデータを取得してみましょう。 結果を取得するにあたり、どのようなクエリを 実行しようとしているか見ていきましょう。


$result = DB::query('SELECT * FROM `users`', DB::SELECT)->execute();

DB::select を使用してデータを取得することもできます。

// 「SELECT `id`, `name` FROM `users`;」 が実行されます
$result = DB::select('id','name')->from('users')->execute();

または DB::select_array を使用して、 カラム名をキーとした配列データを取得することもできます。

// 「SELECT `id`, `name` FROM `users`;」 が実行されます
$colums = array('id', 'name');
$result = DB::select_array($columns)->from('users')->execute();

列にエイリアス(別名)を付けたい場合は、代わりの文字列を配列で指定します。

// 「SELECT `name` as `the_name` FROM `users`;」 が実行されます
$result = DB::select(array('name','the_name'))->from('users')->execute();

distinct に true を指定して、重複のないデータを取得します:

// 「SELECT DISTINCT `name` FROM `users`;」 が実行されます
$users = DB::select('name')->from('users')->distinct(true)->execute();

print_r($users->as_array());
/*
Array
(
    [0] => Array
        (
            [name] => Dirk
        )

    [1] => Array
        (
            [name] => John
        )

)
*/

結果の取得

SELECTクエリの実行は、要求されたデータベースのレコードの値を含む結果オブジェクトを生成します。 デフォルトでは、結果は連想配列で取得します。以下に、 この振る舞いを変更する例を示します。

// 連想配列として結果が返ります。
$result = DB::select('id','name')->from('users')->as_assoc()->execute();

// オブジェクトとして結果が返ります。
$result = DB::select('id','name')->from('users')->as_object()->execute();

// Model_Users オブジェクトとして結果が返ります。
$result = DB::select()->from('users')->as_object('Model_Users')->execute();

// Model_Users オブジェクトとして結果が返ります。 (Usersモジュールのmodel)
$result = DB::select()->from('users')->as_object('\\Users\\Model_Users')->execute();

クラス名を as_object() に渡す場合、必要があれば namespace を含めてください。もし指定されたクラスが存在しない場合、 as_object() は無視され、インデックス付きの配列が返却されるでしょう。

何レコードが取得できたか知りたいって?それは超シンプルです!


$result = DB::select('*')->from('users')->execute();
// ただ結果をカウントするだけ。int が返ります。
$num_rows = count($result);

取得した結果にアクセスするには、結果オブジェクトを直接ループするか、結果の配列を取得します。

$result = DB::select()->from('users')->execute();
foreach($result as $item)
{
	// $item に関する処理
}

$result_array = $result->as_array();
foreach($result_array as $item)
{
	// $item に関する処理
}

オプションとして、as_arrayから返る配列のキーと値を指定することもできます。

$result = DB::select()->from('users')->execute();
$on_key = $result->as_array('id');
foreach($on_key as $id => $item)
{
	// $id にはレコード ID が入る
	// $item またはその $id に関する処理
}

$key_value = $result->as_array('id', 'email');
foreach($key_value as $id => $email)
{
	// ここで $email には電子メールのフィールドが入るので
	// $id や $email に関する処理ができる
}

抽出条件

WHERE 句

クエリに条件を追加するために、私たちは、WHERE 句をセットすることができます。 これらの例は、UPDATE句とDELETE句にも当てはまります。

// SELECT * FROM `users` WHERE `id` = 1 を実行
$result = DB::select()->from('users')->where('id', 1)->execute();

演算子を使うには、以下のようにします:

// SELECT * FROM `users` WHERE `id` = 1 を実行
$result = DB::select()->from('users')->where('id', '=', 1)->execute();

// SELECT * FROM `users` WHERE `id` IN (1, 2, 3) を実行
$id_array = array(1,2,3);
$result = DB::select()->from('users')->where('id', 'in', $id_array)->execute();

// SELECT * FROM `users` WHERE `id` BETWEEN 1 AND 2 を実行
$result = DB::select()->from('users')->where('id', 'between', array(1, 2))->execute();

// SELECT * FROM `users` WHERE `id` != 1 を実行
$result = DB::select()->from('users')->where('id', '!=', 1)->execute();

// SELECT * FROM `users` WHERE `name` LIKE "john%" を実行
$who = "john%";
$result = DB::select()->from('users')->where('id', 'like', $who)->execute();

グループ化されたWHERE句もサポートされています:

// SELECT * FROM `users` WHERE (`name` = 'John' AND `email` = 'john@example.com')
// OR (`name` = 'mike' OR `name` = 'dirk')
$result = DB::select()->from('users')->where_open()
	->where('name', 'John')
	->and_where('email', 'john@example.com')
->where_close()
->or_where_open()
	->where('name', 'mike')
	->or_where('name', 'dirk')
->or_where_close()->execute();

BETWEEN句と、IN句も whereメソッドで指定できます。

// SELECT * FROM `users` WHERE `id` BETWEEN 1 AND 10
$users = DB::select()->from('users')->where('id', 'between', array(1, 10))->execute();

// SELECT * FROM `users` WHERE `name` IN ('john', 'simon', 'dirk')
$users = DB::select()->from('users')->where('name', 'in', array('john', 'simon', 'dirk'))->execute();

ORDER BY 句

データをソートするためには、order_by メソッドを使用します。

//SELECT * FROM `users` ORDER BY `name` ASC
DB::select()->from('users')->order_by('name','asc');

// SELECT * FROM `users` ORDER BY `name` ASC, `surname` DESC
DB::select()->from('users')->order_by('name','asc')->order_by('surname', 'desc');

// 2 番目の引数を省略すれば、order by の昇順降順を省くことができます。
// SELECT * FROM `users` ORDER BY `name`
DB::select()->from('users')->order_by('name');

LIMIT 句、OFFSET 句

取得するレコード数を制限するには、limit メソッド及び、offset メソッドを使用します。 offsetメソッドは、データを取得する際にのみ利用可能なことに注意してください。

// SELECT * FROM `users` LIMIT 1
DB::select()->from('users')->limit(1);

// SELECT * FROM `users` LIMIT 10 OFFSET 5
DB::select()->from('users')->limit(10)->offset(5);

// SELECT * FROM `users` ORDER BY `id` ASC LIMIT 10
DB::select('users')->order_by('id','asc')->limit(10);

UPDATE 文

データを更新するためには、DB::updateを使用します。 もし更新クエリの実行が成功した場合には、更新が影響したレコード数を 整数値で返却します。

1 カラムを更新する

// UPDATE `users` SET `name` = "John Random" WHERE `id` = "2"; を実行
$result = DB::update('users')
	->value("name", "John Random")
	->where('id', '=', '2')
	->execute();

複数カラムを更新する

// UPDATE `users`
// SET `group` = "Peter Griffon", `email` = "peter@thehindenpeter.com"
// WHERE `id` = "16"; を実行
$result = DB::update('users')
	->set(array(
		'name'  => "Peter Griffon",
		'email' => "peter@thehindenpeter.com"
	))
	->where('id', '=', '16')
	->execute();

INSERT 文

データをインサートするには、DB::insertを使用します。 INSERT 文が成功した場合には、インサートされたIDのリストと、インサートされた レコード数を含む配列が返却されます。

// INSERT INTO `users`(`name`,`email`,`password`)
// VALUES ("John Random", "john@example.com", "s0_s3cr3t") を実行
list($insert_id, $rows_affected) = DB::insert('users')->set(array(
	'name' => 'John Random',
	'email' => 'john@example.com',
	'password' => 's0_s3cr3t',
))->execute();

カラム名と値を別々にセットすることもできます。

// INSERT INTO `users`(`name`,`email`,`password`)
// VALUES ("John Random", "john@example.com", "s0_s3cr3t") を実行
list($insert_id, $rows_affected) = DB::insert('users')->columns(array(
	'name', 'email', 'password'
))->values(array(
	'John Random', 'john@example.com', 's0_s3cr3t'
))->execute();

DELETE 文

レコードを削除するには、DB::deleteを使用します。 実行された場合、削除されたレコード数が返却されます。

// users テーブルを空にする
$result = DB::delete('users')->execute(); // (int) 20

// DELETE FROM `users` WHERE `email` LIKE "%@example.com" を実行
$result = DB::delete('users')->where('email', 'like', '%@example.com')->execute(); // (int) 7

表の結合

データを取得する際、他のテーブルを 結合させることができます。

// SELECT * FROM `users` LEFT JOIN `roles` ON `roles`.`id` = `users`.`role_id` を実行
$result = DB::select()->from('users')->join('roles','LEFT')->on('roles.id', '=', 'users.role_id');

// SELECT * FROM `users` RIGHT OUTER JOIN `roles` ON `roles`.`id` = `users`.`role_id` を実行
$result = DB::select()->from('users')->join('roles','right outer')->on('roles.id', '=', 'users.role_id');

// カラム名の代わりにリテラル値 1 を結合
$result = DB::select()->from('users')->join('roles','right outer')->on('roles.id', '=', DB::expr('1'));

エスケープ

データベース操作の際、カラム名と値 は、デフォルトでエスケープされます。いくつかの場面で値をエスケープしたくないと思うでしょう。DBクラスはデータベース表現を作成する機能、DB::expr を提供します。もし値をエスケープされるのを望まない場合、データベース表現の中でそれを囲んでください。

データベース表現は COUNTのようなMySQLのネイティブ関数 やDEFAULT のような定数を扱う際に特に有用です。

// カラムにデフォルト値でセットする
DB::update('users')->where('id', '=', 1)->set(array(
	'some_column' => DB::expr('DEFAULT'),
))->execute();

// SELECT COUNT(*) FROM `users`
$result = DB::select(DB::expr('COUNT(*) as count'))->from('users')->execute();

// 現在(先頭)の結果セットを取得
$result_arr = $result->current();

// 行数を取得
$count = $result_arr['count'];

値のバインド

クエリービルダは、安全かつ確実なやり方で手書きのクエリに変数を割り当てる、 バインディング機能を提供します。

クエリバインディングは、 SQLの中でユニークなプレースホルダを置くことにより動作します。 クエリビルダは、 (バインドした時ではなく)クエリが実行のためにコンパイルされる際に、 これらのプレースホルダを対応する値で置換します。

あなたはFuelPHP標準記法を使用して、プレースホールダーを定義します。それはコロンから始まる文字列です。 例 (:varname)

$name = 'John'; // 割り当てたい変数をセット
$query = "SELECT * FROM users WHERE username = :name"; // 実行したいクエリ

// 変数をバインドしてクエリを実行する。SELECT * FROM users WHERE username = 'John' が生成される
$result = DB::query($query)->bind('name', $name)->execute();

変数は、リファレンスにより割り当てられます。したがって、あなたは最初にクエリと割り当てたい変数を最初に定義し、 後から割り当てた値を変更することができます。

// クエリオブジェクトを生成
$query = DB::query("SELECT * FROM users WHERE username = :name");

$name = 'unknown';                // デフォルト値で変数をセットし、
$query->bind('name', $name);     // クエリに割り当てる。

// いくつかのコードのあとで、割り当てた変数を変更する。
$name = 'Sally';

// 変数をバインドしてクエリを実行する。SELECT * FROM users WHERE username = 'Sally' が生成される
$result = $query->execute();

変数はリファレンスで割り当てられるので、リテラルでは割り当てられ”ません” もしそうした場合、 "Cannot pass parameter 2 by reference" という例外が発生します!

// これは例外が発生します。
$query = DB::query("SELECT * FROM users WHERE username = :name")->bind('name', 'value')->execute();

下記のように、param() メソッドを使って割り当てることができます:

// これなら動くでしょう。
$query = DB::query("SELECT * FROM users WHERE username = :name")->param('name', 'value')->execute();

最後に、あなたが 2 つを混ぜたい場合、parameters() メソッドを使うことができます:

// クエリオブジェクトを生成
$query = DB::query("SELECT * FROM users WHERE username = :name AND state = :state");

$name = 'John'; // 割り当てたい変数に値をセットする。 

// 変数と リテラルを割り当てる
$query->parameters(array('name' => &$name, 'state' => 'new'));

// クエリを実行。SELECT * FROM users WHERE username = 'John' AND state = 'new' が生成される
$result = $query->execute();

いくつかのフレームワークは、クエスチョンマーク(?)をプレースホルダに使用します。そのバインディングシステムは、 最初のクエスチョンマークが最初の値で置換される、といった順番に依存し動作します。 しかし、FuelPHPでは、順番によるバインディングは適切ではなく、プレースホールダーと値には1対1の対応があります。 それは同様に、1 つのクエリでプレースホルダを複数回使用できることを意味します。

クエリキャッシュ

クエリビルダは、クエリ結果のキャッシュもサポートします。これによりデータベースアクセスを減らすことができます。 これは、バックエンドでキャッシュクラスを使用し、キャッシュの読み込みと再生成の両方を行います。
cached() メソッドは、3つの引数をとります: 第一引数は有効期限 (キャッシュが有効となる秒数)、 第二引数は、クエリのカスタムキー (デフォルトでは、SQLのmd5 ハッシュ値)、そして最後は、あなたが空の結果をキャッシュしたくないか を指定する、boolean値です。 カスタムキャッシュキーを使用すると、 手動で特定のクエリのキャッシュを削除したり、特定の階層へクエリキャッシュのセットを グループ化したりできるようになります。

// クエリを実行し、1時間キャッシュします。
// もしまったく同じクエリが次回実行された場合、キャッシュされた値が返ります。
// これは、 3600 秒間有効です。もし有効期限後にクエリが実行された場合、
// 再度クエリが走り、再度 3600秒間キャッシュされるでしょう。
$query = DB::query("SELECT * FROM users")->cached(3600)->execute();

// キャッシュされた結果を削除するために、キーを指定します。 
// これは、データが更新され、キャッシュを削除するのが必要だと知っている場合に有用です。
// 空の結果はキャッシュされません。
$query = DB::query("SELECT * FROM users")->cached(3600, "foo.bar", false)->execute();

// これは前回のクエリのキャッシュを削除します。
Cache::delete("foo.bar");
// もしくは、 "foo" ディレクトリのキャッシュをすべて削除します。
Cache::delete_all("foo");

// デフォルトでは、すべてのクエリは、 "db" ディレクトリに配置されます。
// したがって、明示的にキーがセットされていない、すべてのクエリキャッシュを削除するためには、次のように行います。
Cache::delete_all("db");