Database 使い方

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

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

Query results

A database query always returns the result in an iterator object.
There are two types of result object available, each with their pros and cons.

  • Database_Result
  • Database_Cached
A Database_Result object fetches rows from the result one at the time, and doesn't store it. This means that this object has a low memory footprint, but only allows sequential access to the rows retrieved, in the sequence they are returned, one at the time, from start to finish.

In plain PHP, you can roughly compare it to:
while ($row = $pdoResult->fetch())
{
	// do something with $row
}
A Database_Cached object however fetches all rows from the result at once, and stores it in the object. This means that, depending on the size of the resultset, it might have quite a substantial memoty footprint. But the plus side is, it allows you random access to the rows retrieved, and you access all rows simultaneously, multiple times, iterate over it backwards, anything you could do with an array of values.

In plain PHP, you can roughly compare it to:
$rows = $pdoResult->fetchAll(PDO::FETCH_NUM); // or FETCH_ASSOC, depending on your db config
foreach ($rows as $row)
{
	// do something with $row
}
You can control the type of result object returned globally, per database connection, using the enable_cache configuration item, on the defined database connection, in your db.php config file. By default, caching is enabled. You can override the global setting per query, using:
// this returns a Database_Result, independent of the global setting
$result = \DB::select()->from('table')->caching(false)->execute();

// this returns a Database_Cached, independent of the global setting
$result = \DB::select()->from('table')->caching(true)->execute();

クエリの実行

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

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

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

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

<<<<<<< HEAD
// 返り値: Database_MySQLi_Result オブジェクト
=======
// return a new Database_xxx_Result or Database_xxx_Cached object
>>>>>>> 1.8/master
$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`;」 が実行されます
$columns = 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('name', '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()->from('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(*) as 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 つの引数をとります: 第 1 引数は有効期限 (キャッシュが有効となる秒数)、 第 2 引数は、クエリのカスタムキー (デフォルトでは、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");