This commit is contained in:
cuiliang
2016-06-11 19:49:57 +08:00
2065 changed files with 88639 additions and 74804 deletions

View File

@ -1,8 +1,8 @@
クエリビルダ
============
[データベースアクセスオブジェクト](db-dao.md) の上に構築されているクエリビルダは、SQL をプログラム的に、かつ、DBMS の違いを意識せずに作成することを可能にしてくれます。
クエリビルダを使うと、生の SQL を書くことに比べて、より読みやすい SQL 関連のコードを書き、より安全な SQL 文を生成することが容易になります。
[データベースアクセスオブジェクト](db-dao.md) の上に構築されているクエリビルダは、SQL クエリをプログラム的に、かつ、DBMS の違いを意識せずに作成することを可能にしてくれます。
クエリビルダを使うと、生の SQL を書くことに比べて、より読みやすい SQL 関連のコードを書き、より安全な SQL 文を生成することが容易になります。
通常、クエリビルダの使用は、二つのステップから成ります。
@ -20,7 +20,7 @@ $rows = (new \yii\db\Query())
->all();
```
上記のコードは、次の SQL を生成して実行します。
上記のコードは、次の SQL クエリを生成して実行します。
ここでは、`:last_name` パラメータは `'Smith'` という文字列にバインドされています。
```sql
@ -30,15 +30,15 @@ WHERE `last_name` = :last_name
LIMIT 10
```
> Info|情報: 通常は、[[yii\db\QueryBuilder]] ではなく、主として [[yii\db\Query]] を使用します。
> Info: 通常は、[[yii\db\QueryBuilder]] ではなく、主として [[yii\db\Query]] を使用します。
前者は、クエリメソッドの一つを呼ぶときに、後者によって黙示的に起動されます。
[[yii\db\QueryBuilder]] は、DBMS に依存しない [[yii\db\Query]] オブジェクトから、DBMS に依存する SQL 文を生成する (例えば、テーブルやカラムの名前を DBMS ごとに違う方法で引用符で囲む) 役割を負っているクラスです。
## クエリを構築する <span id="building-queries"></span>
[[yii\db\Query]] オブジェクトを構築するために、さまざまなクエリ構築メソッドを呼んで、SQL のさまざまな部分を定義します。
[[yii\db\Query]] オブジェクトを構築するために、さまざまなクエリ構築メソッドを呼んで、SQL クエリのさまざまな部分を定義します。
これらのメソッドの名前は、SQL 文の対応する部分に使われる SQL キーワードに似たものになっています。
例えば、SQL `FROM` の部分を定義するためには、`from()` メソッドを呼び出します。
例えば、SQL クエリ`FROM` の部分を定義するためには、`from()` メソッドを呼び出します。
クエリ構築メソッドは、すべて、クエリオブジェクトそのものを返しますので、複数の呼び出しをチェーンしてまとめることが出来ます。
以下で、それぞれのクエリ構築メソッドの使用方法を説明しましょう。
@ -58,7 +58,7 @@ $query->select(['id', 'email']);
$query->select('id, email');
```
選択されるカラム名は、生の SQL を書くときにするように、テーブル接頭辞 および/または カラムのエイリアスを含むことが出来ます。
選択されるカラム名は、生の SQL クエリを書くときにするように、テーブル接頭辞 および/または カラムのエイリアスを含むことが出来ます。
例えば、
```php
@ -85,12 +85,19 @@ $query->select(['user_id' => 'user.id', 'email']);
```php
<<<<<<< HEAD
<<<<<<< HEAD
$query->select(["CONCAT(first_name, ' ', last_name]) AS full_name", 'email']);
=======
$query->select(["CONCAT(first_name, ' ', last_name) AS full_name", 'email']);
>>>>>>> yiichina/master
=======
$query->select(["CONCAT(first_name, ' ', last_name) AS full_name", 'email']);
>>>>>>> master
```
生の SQL が使われる場所ではどこでもそうですが、セレクトに DB 式を書く場合には、テーブルやカラムの名前を表すために
[特定のデータベースに依存しない引用符の構文](db-dao.md#quoting-table-and-column-names) を使うことが出来ます。
バージョン 2.0.1 以降では、サブクエリもセレクトすることが出来ます。
各サブクエリは、[[yii\db\Query]] オブジェクトの形で指定しなければなりません。
例えば、
@ -120,7 +127,7 @@ $query->from('user');
```
セレクトの対象になる (一つまたは複数の) テーブルは、文字列または配列として指定することが出来ます。
テーブル名は、生の SQL を書くときにするように、スキーマ接頭辞 および/または テーブルエイリアスを含むことが出来ます。例えば、
テーブル名は、生の SQL を書くときにするように、スキーマ接頭辞 および/または テーブルエイリアスを含むことが出来ます。例えば、
```php
$query->from(['public.user u', 'public.post p']);
@ -149,7 +156,7 @@ $query->from(['u' => $subQuery]);
### [[yii\db\Query::where()|where()]] <span id="where"></span>
[[yii\db\Query::where()|where()]] メソッドは、SQL `WHERE` 句を定義します。
[[yii\db\Query::where()|where()]] メソッドは、SQL クエリ`WHERE` 句を定義します。
`WHERE` の条件を指定するために、次の三つの形式から一つを選んで使うことが出来ます。
- 文字列形式、例えば、`'status=1'`
@ -159,7 +166,7 @@ $query->from(['u' => $subQuery]);
#### 文字列形式 <span id="string-format"></span>
文字列形式は、非常に単純な条件を定義する場合に最適です。
文字列形式は、非常に単純な条件を定義する場合や、DBMS の組み込み関数を使う必要がある場合に最適です。
これは、生の SQL を書いている場合と同じように動作します。
例えば、
@ -168,6 +175,9 @@ $query->where('status=1');
// あるいは、パラメータバインディングを使って、動的にパラメータをバインドする
$query->where('status=:status', [':status' => $status]);
// date フィールドに対して MySQL の YEAR() 関数を使う生の SQL
$query->where('YEAR(somedate) = 2015');
```
次のように、条件式に変数を直接に埋め込んではいけません。
@ -185,6 +195,9 @@ $query->where('status=:status')
->addParams([':status' => $status]);
```
生の SQL が使われる場所ではどこでもそうですが、文字列形式で条件を書く場合には、テーブルやカラムの名前を表すために
[特定のデータベースに依存しない引用符の構文](db-dao.md#quoting-table-and-column-names) を使うことが出来ます。
#### ハッシュ形式 <span id="hash-format"></span>
@ -212,6 +225,10 @@ $userQuery = (new Query())->select('id')->from('user');
$query->where(['id' => $userQuery]);
```
ハッシュ形式を使う場合、Yii は内部的にパラメータバインディングを使用します。
従って、[文字列形式](#string-format) とは対照的に、ここでは手動でパラメータを追加する必要はありません。
#### 演算子形式 <span id="operator-format"></span>
演算子形式を使うと、任意の条件をプログラム的な方法で指定することが出来ます。
@ -257,7 +274,7 @@ $query->where(['id' => $userQuery]);
`false` または空の配列を使って、値が既にエスケープ済みであり、それ以上エスケープを適用すべきでないことを示すことが出来ます。
エスケープマッピングを使用する場合 (または第三のオペランドが与えられない場合) は、値が自動的に一組のパーセント記号によって囲まれることに注意してください。
> Note|注意: PostgreSQL を使っている場合は、`like` の代りに、大文字と小文字を区別しない比較のための [`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE) を使うことも出来ます。
> Note: PostgreSQL を使っている場合は、`like` の代りに、大文字と小文字を区別しない比較のための [`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE) を使うことも出来ます。
- `or like`: オペランド 2 が配列である場合に `LIKE` 述語が `OR` によって結合される以外は、`like` 演算子と同じです。
@ -273,6 +290,9 @@ $query->where(['id' => $userQuery]);
- `>``<=`、その他、二つのオペランドを取る有効な DB 演算子全て: 最初のオペランドはカラム名、第二のオペランドは値でなければなりません。
例えば、`['>', 'age', 10]``age>10` を生成します。
演算子形式を使う場合、Yii は内部的にパラメータバインディングを使用します。
従って、[文字列形式](#string-format) とは対照的に、ここでは手動でパラメータを追加する必要はありません。
#### 条件を追加する <span id="appending-conditions"></span>
@ -293,7 +313,7 @@ if (!empty($search)) {
}
```
`$search` が空でない場合は次の SQL が生成されます。
`$search` が空でない場合は次の WHERE 条件 が生成されます。
```sql
WHERE (`status` = 10) AND (`title` LIKE '%yii%')
@ -314,15 +334,29 @@ $query->filterWhere([
```
[[yii\db\Query::filterWhere()|filterWhere()]] と [[yii\db\Query::where()|where()]] の唯一の違いは、前者は [ハッシュ形式](#hash-format) の条件において提供された空の値を無視する、という点です。
従って、`$email` が空で `$sername` がそうではない場合は、上記のコードは、結果として `...WHERE username=:username` という SQL になります。
従って、`$email` が空で `$sername` がそうではない場合は、上記のコードは、結果として `WHERE username=:username` という SQL 条件になります。
> Info|情報: 値が空であると見なされるのは、null、空の配列、空の文字列、または空白のみを含む文字列である場合です。
> Info: 値が空であると見なされるのは、null、空の配列、空の文字列、または空白のみを含む文字列である場合です。
[[yii\db\Query::andWhere()|andWhere()]] または [[yii\db\Query::orWhere()|orWhere()]] と同じように、[[yii\db\Query::andFilterWhere()|andFilterWhere()]] または [[yii\db\Query::orFilterWhere()|orFilterWhere()]] を使って、既存の条件に別のフィルタ条件を追加することも出来ます。
さらに加えて、値の方に含まれている比較演算子を適切に判断してくれる [[yii\db\Query::andFilterCompare()]] があります。
```php
$query->andFilterCompare('name', 'John Doe');
$query->andFilterCompare('rating', '>9');
$query->andFilterCompare('value', '<=100');
```
比較演算子を明示的に指定することも可能です。
```php
$query->andFilterCompare('name', 'Doe', 'like');
```
### [[yii\db\Query::orderBy()|orderBy()]] <span id="order-by"></span>
[[yii\db\Query::orderBy()|orderBy()]] メソッドは SQL `ORDER BY` 句を指定します。例えば、
[[yii\db\Query::orderBy()|orderBy()]] メソッドは SQL クエリ`ORDER BY` 句を指定します。例えば、
```php
@ -336,14 +370,14 @@ $query->orderBy([
上記のコードにおいて、配列のキーはカラム名であり、配列の値は並べ替えの方向です。
PHP の定数 `SORT_ASC` は昇順、`SORT_DESC` は降順を指定するものです。
`ORDER BY` が単純なカラム名だけを含む場合は、生の SQL を書くときにするように、文字列を使って指定することが出来ます。
`ORDER BY` が単純なカラム名だけを含む場合は、生の SQL を書くときにするように、文字列を使って指定することが出来ます。
例えば、
```php
$query->orderBy('id ASC, name DESC');
```
> Note|注意: `ORDER BY` が何らかの DB 式を含む場合は、配列形式を使わなければなりません。
> Note: `ORDER BY` が何らかの DB 式を含む場合は、配列形式を使わなければなりません。
[[yii\db\Query::addOrderBy()|addOrderBy()]] を呼んで、`ORDER BY' 句にカラムを追加することが出来ます。
例えば、
@ -355,7 +389,7 @@ $query->orderBy('id ASC')
### [[yii\db\Query::groupBy()|groupBy()]] <span id="group-by"></span>
[[yii\db\Query::groupBy()|groupBy()]] メソッドは SQL の `GROUP BY` 句を指定します。
[[yii\db\Query::groupBy()|groupBy()]] メソッドは SQL クエリの `GROUP BY` 句を指定します。
例えば、
```php
@ -363,18 +397,22 @@ $query->orderBy('id ASC')
$query->groupBy(['id', 'status']);
```
`GROUP BY` が単純なカラム名だけを含む場合は、生の SQL を書くときにするように、文字列を使って指定することが出来ます。
`GROUP BY` が単純なカラム名だけを含む場合は、生の SQL を書くときにするように、文字列を使って指定することが出来ます。
例えば、
```php
<<<<<<< HEAD
<<<<<<< HEAD
$query->groupBy('id, status']);
=======
$query->groupBy('id, status');
>>>>>>> yiichina/master
=======
$query->groupBy('id, status');
>>>>>>> master
```
> Note|注意: `GROUP BY` が何らかの DB 式を含む場合は、配列形式を使わなければなりません。
> Note: `GROUP BY` が何らかの DB 式を含む場合は、配列形式を使わなければなりません。
[[yii\db\Query::addGroupBy()|addGroupBy()]] を呼んで、`GROUP BY` 句にカラムを追加することが出来ます。
例えば、
@ -387,7 +425,7 @@ $query->groupBy(['id', 'status'])
### [[yii\db\Query::having()|having()]] <span id="having"></span>
[[yii\db\Query::having()|having()]] メソッドは SQL の `HAVING` 句を指定します。
[[yii\db\Query::having()|having()]] メソッドは SQL クエリの `HAVING` 句を指定します。
このメソッドが取る条件は、[where()](#where) と同じ方法で指定することが出来ます。
例えば、
@ -410,7 +448,7 @@ $query->having(['status' => 1])
### [[yii\db\Query::limit()|limit()]] と [[yii\db\Query::offset()|offset()]] <span id="limit-offset"></span>
[[yii\db\Query::limit()|limit()]] と [[yii\db\Query::offset()|offset()]] のメソッドは、SQL の `LIMIT` と `OFFSET` 句を指定します。
[[yii\db\Query::limit()|limit()]] と [[yii\db\Query::offset()|offset()]] のメソッドは、SQL クエリの `LIMIT` と `OFFSET` 句を指定します。
例えば、
```php
@ -420,12 +458,12 @@ $query->limit(10)->offset(20);
無効な上限やオフセット (例えば、負の数) を指定した場合は、無視されます。
> Info|情報: `LIMIT` と `OFFSET` をサポートしていない DBMS (例えば MSSQL) に対しては、クエリビルダが `LIMIT`/`OFFSET` の振る舞いをエミュレートする SQL 文を生成します。
> Info: `LIMIT` と `OFFSET` をサポートしていない DBMS (例えば MSSQL) に対しては、クエリビルダが `LIMIT`/`OFFSET` の振る舞いをエミュレートする SQL 文を生成します。
### [[yii\db\Query::join()|join()]] <span id="join"></span>
[[yii\db\Query::join()|join()]] メソッドは SQL の `JOIN` 句を指定します。例えば、
[[yii\db\Query::join()|join()]] メソッドは SQL クエリの `JOIN` 句を指定します。例えば、
```php
// ... LEFT JOIN `post` ON `post`.`user_id` = `user`.`id`
@ -438,6 +476,9 @@ $query->join('LEFT JOIN', 'post', 'post.user_id = user.id');
- `$table`: 結合されるテーブルの名前。
- `$on`: オプション。結合条件、すなわち、`ON` 句。
条件の指定方法の詳細については、[where()](#where) を参照してください。
カラムに基づく条件を指定する場合は、配列記法は**使えない**ことに注意してください。
例えば、`['user.id' => 'comment.userId']` は、user の id が `'comment.userId'` という文字列でなければならない、という条件に帰結します。
配列記法ではなく文字列記法を使って、`'user.id = comment.userId'` という条件を指定しなければなりません。
- `$params`: オプション。結合条件にバインドされるパラメータ。
`INNER JOIN`、`LEFT JOIN` および `RIGHT JOIN` を指定するためには、それぞれ、次のショートカットメソッドを使うことが出来ます。
@ -468,7 +509,7 @@ $query->leftJoin(['u' => $subQuery], 'u.id = author_id');
### [[yii\db\Query::union()|union()]] <span id="union"></span>
[[yii\db\Query::union()|union()]] メソッドは SQL の `UNION` 句を指定します。例えば、
[[yii\db\Query::union()|union()]] メソッドは SQL クエリの `UNION` 句を指定します。例えば、
```php
$query1 = (new \yii\db\Query())
@ -503,11 +544,16 @@ $query1->union($query2);
上記のメソッドの全ては、オプションで、DB クエリの実行に使用されるべき [[yii\db\Connection|DB 接続]] を表す `$db` パラメータを取ることが出来ます。
<<<<<<< HEAD
<<<<<<< HEAD
このパラメータを省略した場合は、DB 接続として `db` アプリケーションコンポーネントが使用されます。
=======
このパラメータを省略した場合は、DB 接続として `db` [アプリケーションコンポーネント](structure-application-components.md) が使用されます。
>>>>>>> yiichina/master
次に `count()` クエリメソッドを使う例をもう一つ挙げます。
=======
このパラメータを省略した場合は、DB 接続として `db` [アプリケーションコンポーネント](structure-application-components.md) が使用されます。
次に [[yii\db\Query::count()|count()]] クエリメソッドを使う例をもう一つ挙げます。
>>>>>>> master
```php
// 実行される SQL: SELECT COUNT(*) FROM `user` WHERE `last_name`=:last_name
@ -521,7 +567,7 @@ $count = (new \yii\db\Query())
* [[yii\db\QueryBuilder]] を呼んで、[[yii\db\Query]] の現在の構成に基づいた SQL 文を生成する。
* 生成された SQL 文で [[yii\db\Command]] オブジェクトを作成する。
* [[yii\db\Command]] のクエリメソッド (例えば `queryAll()`) を呼んで、SQL 文を実行し、データを取得する。
* [[yii\db\Command]] のクエリメソッド (例えば [[yii\db\Command::queryAll()|queryAll()]]) を呼んで、SQL 文を実行し、データを取得する。
場合によっては、[[yii\db\Query]] オブジェクトから構築された SQL 文を調べたり使ったりしたいことがあるでしょう。
次のコードを使って、その目的を達することが出来ます。
@ -573,6 +619,13 @@ $query = (new \yii\db\Query())
この無名関数は、現在の行データを含む `$row` というパラメータを取り、現在の行のインデックス値として使われるスカラ値を返さなくてはなりません。
> Note: [[yii\db\Query::groupBy()|groupBy()]] や [[yii\db\Query::orderBy()|orderBy()]]
> のようなクエリメソッドが SQL に変換されてクエリの一部となるのとは対照的に、
> このメソッドはデータベースからデータが取得された後で動作します。
> このことは、クエリの SELECT に含まれるカラム名だけを使うことが出来る、ということを意味します。
> また、テーブルプレフィックスを付けてカラムを選択した場合、例えば `customer.id` を選択した場合は、
> リザルトセットのカラム名は `id` しか含みませんので、テーブルプレフィックス無しで `->indexBy('id')` と呼ぶ必要があります。
## バッチクエリ <span id="batch-query"></span>
@ -622,5 +675,6 @@ foreach ($query->batch() as $users) {
}
foreach ($query->each() as $username => $user) {
// ...
}
```