クエリビルダ
Yii のクエリビルダはオブジェクト指向で SQL 文を書く方法を提供します。 開発者は SQL 文の個々の部分をクラスのメソッドやプロパティを使って書くことが出来ます。 そうすると、クエリビルダが異なる部分を一つの正しい SQL 文に組み上げます。 そして、さらに、組み上がった SQL 文は データアクセスオブジェクト で説明されている DAO メソッドを呼んで実行することが出来ます。 下記はクエリビルダの典型的な使用方法を示すもので、SELECT SQL 文をビルドするものです。
クエリビルダを使うのに最も適しているのは、SQL 文を手続き的に組み上げる必要があるとき、または、SQL 文をアプリケーションの何らかの条件ロジックに基づいて組み上げる必要があるときです。 クエリビルダを使用する主な便益は以下のものです。
複雑な SQL 文をプログラム的に組み上げることが出来る。
自動的にテーブル名とカラム名を引用符号で囲んで、SQL の予約語や特殊文字との衝突を防いでくれる。
パラメータ値も引用符号で囲み、可能なときにはパラメータバインディングを使用するので、SQL インジェクション攻撃の危険を軽減するのに役立つ。
DB について、ある程度の抽象化を提供してくれるので、異なる DB プラットフォームへの移行を単純化できる。
クエリビルダの使用は強制されていません。 実際のところ、クエリが単純な場合は、直接に SQL 文を書く方が簡単で高速です。
注意: クエリビルダは、SQL 文として定義された既存のクエリを修正するためには使うことが出来ません。 例えば、下記のコードは動作しません。
換言すると、素の SQL とクエリビルダを混用してはいけない、ということです。
クエリビルダを準備する
Yii のクエリビルダは CDbCommand、すなわち、データアクセスオブジェクト で説明されているメインの DB クエリクラスとして提供されています。
クエリビルダの使用を開始するためには、下記のように、CDbCommand の新しいインスタンスを作成します。
すなわち、Yii::app()->db
を使って DB 接続を取得し、次に CDbConnection::createCommand() を呼んで必要なコマンドのインスタンスを作成します。
データアクセスオブジェクト では createCommand()
の呼出しに SQL 文全体を渡しますが、ここではそうせず、空のままにしておくことに注意して下さい。
これは、下記で説明するクエリビルダのメソッドを使って、SQL 文の個々の部分を組み上げていくことになるからです。
データを読み出すクエリを組み上げる
データを読み出すクエリとは SELECT SQL 文のことです。 クエリビルダは SELECT 文の個々の部分を組み上げるための一連のメソッドを提供します。 これらのメソッドは全て CDbCommand のインスタンスを返しますので、この章の最初の例で示されているように、メソッドチェーンを使って呼び出すことが出来ます。
- select(): クエリの SELECT の部分を指定する
- selectDistinct(): クエリの SELECT の部分を指定すると共に DISTINCT フラグを立てる
- from(): クエリの FROM の部分を指定する
- where(): クエリの WHERE の部分を指定する
- andWhere(): クエリの WHERE の部分に
AND
演算子で条件を追加する - orWhere(): クエリの WHERE の部分に
OR
演算子で条件を追加する - join(): 内部結合のクエリ断片を追加する
- leftJoin(): 左外部結合のクエリ断片を追加する
- rightJoin(): 右外部結合のクエリ断片を追加する
- crossJoin(): 交差結合のクエリ断片を追加する
- naturalJoin(): 自然結合のクエリ断片を追加する
- group(): クエリの GROUP BY の部分を指定する
- having(): クエリの HAVING の部分を指定する
- order(): クエリの ORDER BY の部分を指定する
- limit(): クエリの LIMIT の部分を指定する
- offset(): クエリの OFFSET の部分を指定する
- union(): UNION のクエリ断片を追加する
以下に、これらのクエリビルダのメソッドの使用方法を説明します。 説明を単純にするために、基礎になっているデータベースは MySQL であると仮定します。 他の DBMS を使っている場合は、テーブル名・カラム名・値を囲む引用符号が、例で示されているものとは違うものになることがあります。
select()
select() メソッドは、クエリの SELECT
の部分を指定します。
$columns
パラメータが選択されるカラムを指定します。
これは、カンマで区切ったカラム名の文字列でも、カラム名の配列でも構いません。
カラム名はテーブルプレフィックス、および/あるいは、カラム名のエイリアスを含むことが出来ます。
カラムが括弧を含んでいる (すなわち、カラムが DB の式として与えられている) 場合を除いて、カラム名は自動的に引用符号で囲まれます。
以下にいくつかの例を示します。
selectDistinct()
selectDistinct() メソッドは、DISTINCT
フラグを立てることを除いて、select() メソッドと同一です。
例えば、selectDistinct('id, username')
は次の SQL 文を生成します。
from()
from() メソッドは、クエリの FROM
の部分を指定します。
$tables
パラメータが、どのテーブルからデータを読み出すかを指定します。
これは、カンマで区切ったテーブル名の文字列でも、テーブル名の配列でも構いません。
テーブル名はスキーマプレフィックス (例えば public.tbl_user
)、および/あるいは、テーブル名のエイリアス (例えば tbl_user u
) を含むことが出来ます。
テーブルが括弧を含んでいる (すなわち、テーブルがサブクエリあるいは DB の式として与えられている) 場合を除いて、テーブル名は自動的に引用符号で囲まれます。
以下にいくつかの例を示します。
where()
where() メソッドはクエリの WHERE
の部分を指定します。
$conditions
パラメータはクエリの条件を指定し、$params
はクエリ全体にバインドされるパラメータを指定します。
$conditions
パラメータは、文字列 (例えば id=1
) であるか、または、下記の形式の配列です。
ここで operator
としては、下記のどれかを指定する事が出来ます。
and
: オペランドがAND
を使って連結されます。 例えば、array('and', 'id=1', 'id=2')
はid=1 AND id=2
を生成します。 オペランドが配列である場合は、ここで説明しているのと同じ規則を使って文字列に変換されます。 例えば、array('and', 'type=1', array('or', 'id=1', 'id=2'))
はtype=1 AND (id=1 OR id=2)
を生成します。 このとき、メソッドによる自動的な引用符号の追加やエスケープは行われないことに注意して下さい。or
: オペランドがOR
を使って連結されることを除いて、and
オペレータと同一です。in
: 最初のオペランドはカラムまたは DB の式でなければなりません。 そして、第2のオペランドは、そのカラムまたは DB の式が取り得る値の候補を表す配列にします。 例えば、array('in', 'id', array(1,2,3))
はid IN (1,2,3)
を生成します。 メソッドが適切に、カラム名を引用符号で囲み、候補の値をエスケープしてくれます。not in
: 生成される条件においてIN
がNOT IN
で置き換えられることを除いて、in
オペレータと同一です。like
: 最初のオペランドはカラムまたは DB の式でなければなりません。 そして、第2のオペランドは、そのカラムまたは DB の式と比較される単一の文字列、または文字列の配列にします。 例えば、array('like', 'name', '%tester%')
はname LIKE '%tester%'
を生成します。 比較される文字列が配列で与えられた場合は、複数のLIKE
述語が生成されてAND
によって連結されます。 例えば、array('like', 'name', array('%test%', '%sample%'))
はname LIKE '%test%' AND name LIKE '%sample%'
を生成します。 メソッドが適切に、カラム名を引用符号で囲み、比較される文字列をエスケープしてくれます。not like
: 生成される条件においてLIKE
がNOT LIKE
で置き換えられることを除いて、like
オペレータと同一です。or like
: 複数のLIKE
述語をOR
によって連結することを除いて、like
オペレータと同一です。or not like
: 複数のNOT LIKE
述語をOR
によって連結することを除いて、not like
オペレータと同一です。
以下に where
の使い方の例をいくつか示します。
オペレータに like
を使う場合に、パターンの中で明示的にワイルドカード文字 (%
や _
) を指定する必要があることに注意して下さい。
さらに、パターンがユーザ入力から来る場合は、下記のコードを使って特殊文字をエスケープし、ワイルドカード文字として扱われることを防がなければなりません。
andWhere()
addWhere() メソッドは与えられた条件をクエリの WHERE
の部分に AND
演算子を使って追加します。
このメソッドの動作は、条件を置き換えるのでなく追加するという点を除いて、where() とほとんど同一です。
このメソッドのパラメータに関する詳細な情報は、where() のドキュメントを参照して下さい。
orWhere()
orWhere() メソッドは与えられた条件をクエリの WHERE
の部分に OR
演算子を使って追加します。
このメソッドの動作は、条件を置き換えるのでなく追加するという点を除いて、where() とほとんど同一です。
このメソッドのパラメータに関する詳細な情報は、where() のドキュメントを参照して下さい。
order()
order() メソッドは、クエリの ORDER BY
の部分を指定します。
$columns
パラメータがソートに使われるカラムを指定します。
これは、カンマで区切ったカラムと並び順 (ASC
または DESC
) の文字列、または、カラムと並び順の配列です。
カラム名はテーブルプレフィックスを含むことが出来ます。
カラムが括弧を含んでいる (すなわち、カラムが DB の式として与えられている) 場合を除いて、カラム名は自動的に引用符号で囲まれます。
以下にいくつかの例を示します。
limit() と offset()
limit() メソッドおよび offset() メソッドは、クエリの LIMIT
および OFFSET
の部分を指定します。
DBMS によっては、LIMIT
と OFFSET
の書式がサポートされていないことがあります。
その場合は、クエリビルダは SQL 文全体を書き換えて、limit や offset の機能をシミュレートします。
以下にいくつかの例を示します。
join() とその変種
join() メソッドとその変種は、INNER JOIN
、LEFT OUTER JOIN
、RIGHT OUTER JOIN
、CROSS JOIN
、または NATURAL JOIN
を使って他のテーブルを結合する方法を指定します。
$tables
パラメータが、どのテーブルを結合するかを指定します。
テーブル名はスキーマプレフィックス、および/あるいは、テーブル名のエイリアスを含むことが出来ます。
テーブルが括弧を含んでおり、DB の式またはサブクエリであることを示している場合を除いて、テーブル名は自動的に引用符号で囲まれます。
$condition
パラメータは結合条件を指定します。
その文法は where() の場合と同じです。
そして、$param
はクエリ全体にバインドされるパラメータを指定します。
他のクエリビルダのメソッドと違って、結合メソッドは、呼ばれるたびに前のものに追加されることに注意して下さい。
以下にいくつかの例を示します。
group()
group() メソッドは、クエリの GROUP BY
の部分を指定します。
$columns
パラメータがグループ化されるカラムを指定します。
これは、カンマで区切ったカラム名の文字列でも、カラム名の配列でも構いません。
カラム名はテーブルプレフィックスを含むことが出来ます。
カラムが括弧を含んでいる (すなわち、カラムが DB の式として与えられている) 場合を除いて、カラム名は自動的に引用符号で囲まれます。
以下にいくつかの例を示します。
having()
having() メソッドは、クエリの HAVING
の部分を指定します。
使用方法は、where() と同じです。
以下にいくつかの例を示します。
union()
union() メソッドは、クエリの UNION
の部分を指定します。
これは既存の SQL に UNION
演算子を使って $sql
を追加するものです。
union()
を複数回呼ぶと、複数の SQL が既存の SQL に追加されます。
以下に例を示します。
クエリを実行する
上記のクエリビルダのメソッドを呼んでクエリを組み上げた後、データアクセスオブジェクト で説明されている DAO メソッドを呼んでクエリを実行することが出来ます。 例えば、CDbCommand::queryRow() を呼んで結果を一行取得したり、CDbCommand::queryAll() を呼んで全ての行をまとめて取得したり出来ます。 例えば、
SQL を読み出す
クエリビルダによって組み上げられたクエリを実行する以外に、対応する SQL 文を読み出すことも出来ます。 そのためには CDbCommand::getText() を呼びます。
クエリにバインドされるべきパラメータがある場合は、CDbCommand::params プロパティによって読み出すことが出来ます。
クエリをビルドする代替の文法
時として、メソッドチェインを用いてクエリをビルドするのが最善の選択ではない場合もあります。
Yii のクエリビルダでは、単純なオブジェクトプロパティへの代入を使ってクエリをビルドすることも出来ます。
具体的に言うと、全てのクエリビルダのメソッドには、それに対応する同じ名前のプロパティがあります。
プロパティに値を代入することは、それに対応するメソッドを呼ぶことと等価です。
例えば、次の二つの文は等価です ($command
は CDbCommand オブジェクトを表すものとします)。
さらに加えて、CDbConnection::createCommand() メソッドはパラメータとして配列を取ることが出来ます。 配列内の "名前-値" のペアは、作成される CDbCommand インスタンスのプロパティを初期化するのに使われます。 すなわち、クエリをビルドするのに下記のコードを使うことが出来るという事です。
複数のクエリをビルドする
CDbCommand のインスタンスを複数回再利用して、複数のクエリをビルドすることが出来ます。 ただし、新しいクエリをビルドする前に、CDbCommand::reset() メソッドを呼び出して、前のクエリをクリーンアップしなければなりません。 例えば
データを操作するクエリをビルドする
データを操作するクエリとは、DB テーブルの中のデータを挿入、更新、および、削除する SQL 文を指すものです。
これらのクエリに対応するものとして、クエリビルダはそれぞれ insert
、update
、delete
というメソッドを提供しています。
上で説明した SELECT クエリのメソッドと違って、これらデータ操作クエリのメソッドは、どれも、完全な SQL 文をビルドして、それをただちに実行します。
以下で、これらのデータ操作クエリのメソッドについて説明します。
insert()
insert() メソッドは、INSERT
SQL 文をビルドして実行します。
$table
パラメータは、どのテーブルに挿入するかを指定し、$columns
は "名前-値" のペアの配列で、挿入されるカラムの値を指定するものです。
メソッドはテーブル名を引用符号で適切に囲み、挿入される値に対してパラメータバインディングを使用します。
下記がその例です。
update()
update() メソッドは、UPDATE
SQL 文をビルドして実行します。
$table
パラメータは、どのテーブルを更新するかを指定します。
$columns
は "名前-値" のペアの配列で、更新されるカラムの値を指定します。
$conditions
と $params
は、where() メソッドの場合と同じで、UPDATE
文の WHERE
句を指定するものです。
メソッドはテーブル名を引用符号で適切に囲み、更新される値に対してパラメータバインディングを使用します。
下記がその例です。
delete()
delete() メソッドは、DELETE
SQL 文をビルドして実行します。
$table
パラメータは、どのテーブルのデータを削除するかを指定します。
$conditions
と $params
は、where() メソッドの場合と同じで、DELETE
文の WHERE
句を指定するものです。
メソッドはテーブル名を引用符号で適切に囲みます。
下記がその例です。
スキーマを操作するクエリをビルドする
データを読み出したり操作したりする通常のクエリの他に、クエリビルダはデータベースのスキーマを操作するための SQL クエリをビルドして実行する一連のメソッドを提供します。 具体的には、下記のクエリをサポートしています。
- createTable(): テーブルを作成する
- renameTable(): テーブルの名前を変更する
- dropTable(): テーブルを削除する
- truncateTable(): テーブルの行をすべて削除する
- addColumn(): テーブルのカラムを追加する
- renameColumn(): テーブルのカラムの名前を変更する
- alterColumn(): テーブルのカラムを変更する
- addForeignKey(): 外部キーを追加する (1.1.6 以降で利用可能)
- dropForeignKey(): 外部キーを削除する (1.1.6 以降で利用可能)
- dropColumn(): テーブルのカラムを削除する
- createIndex(): インデックスを作成する
- dropIndex(): インデックスを削除する
情報: データベーススキーマを操作する実際の SQL 文は DBMS によって大きく異なりますが、クエリビルダはこれらのクエリをビルドするための統一されたインタフェースを提供しようと試みています。 これによって、データベースをある DBMS から別の DBMS に移行する作業が簡単になります。
抽象データ型
クエリビルダはテーブルのカラムの定義に使用出来る一連の抽象的なデータ型を導入しています。 特定の DBMS に固有で、DBMS ごとに全く異なる物理的データ型とは違って、抽象データ型は DBMS に依存しないものです。 抽象データ型がテーブルのカラムの定義に使用されると、クエリビルダはそれを対応する物理的データ型に変換します。
以下の抽象データ型がクエリビルダによってサポートされています。
pk
: 汎用的な主キーの型。MySQL ではint(11) NOT NULL AUTO_INCREMENT PRIMARY KEY
に変換されるstring
: 文字列。MySQL ではvarchar(255)
に変換される。text
: テキスト (長い文字列)。MySQL ではtext
に変換される。integer
: 整数。MySQL ではint(11)
に変換される。float
: 実数。MySQL ではfloat
に変換される。decimal
: デシマル。MySQL ではdecimal
に変換される。datetime
: 日付時刻。MySQL ではdatetime
に変換される。timestamp
: タイムスタンプ。MySQL ではtimestamp
に変換される。time
: 時刻。MySQL ではtime
に変換される。date
: 日付。MySQL ではdate
に変換される。binary
: バイナリデータ。MySQL ではblob
に変換される。boolean
: 真偽値。MySQL ではtinyint(1)
に変換される。money
: 金銭/貨幣。MySQL ではdecimal(19,4)
に返還される。この型はバージョン 1.1.8 以降で使用可能。
createTable()
createTable() メソッドは、テーブルを作成する SQL 文をビルドして実行します。
$table
パラメータは、作成されるテーブルの名前を指定します。
$columns
パラメータは、新しいテーブルのカラムを指定します。
これは 名前-定義 のペア (例えば 'username'=>'string'
) の配列として与えなければなりません。
$options
パラメータは、生成される SQL の後に追加される何らかの SQL 断片を指定するものです。
クエリビルダはテーブル名とカラム名を適切に引用符号で囲みます。
カラムの定義を指定するときに、上で述べた抽象データ型を使用することが出来ます。
クエリビルダは、現在使われている DBMS に従って、抽象データ型を対応する物理的データ型に変換します。
例えば、MySQL では、string
は varchar(255)
に変換されます。
カラムの定義は、抽象データ型でないデータ型や仕様を含むことも出来ます。
それらは何も変更を加えずに生成される SQL に入れられます。
例えば、point
は抽象データ型ではありませんので、カラムの定義で使われた場合は、結果として得られる SQL にそのままの形で出てきます。
string NOT NULL
は varchar(255) NOT NULL
に変換されます (つまり、抽象データ型である string
だけが変換されます)。
下記はテーブルを作成する方法を示す例です。
renameTable()
renameTable()メソッドは、テーブルの名前を変更する SQL 文をビルドして実行します。
$table
パラメータは、名前を変更されるテーブルの現在の名前を指定します。
$newName
パラメータは、テーブルの新しい名前を指定します。
クエリビルダはテーブル名を適切に引用符号で囲みます。
下記はテーブルの名前を変更する方法を示す例です。
dropTable()
dropTable()メソッドは、テーブルを削除する SQL 文をビルドして実行します。
$table
パラメータは、削除されるテーブルの名前を指定します。
クエリビルダはテーブル名を適切に引用符号で囲みます。
下記はテーブルを削除する方法を示す例です。
truncateTable()
truncateTable()メソッドは、テーブルの行をすべて削除する SQL 文をビルドして実行します。
$table
パラメータは、行をすべて削除するテーブルの名前を指定します。
クエリビルダはテーブル名を適切に引用符号で囲みます。
下記はテーブルの行をすべて削除する方法を示す例です。
addColumn()
addColumn() メソッドは、テーブルに新しいカラムを追加する SQL 文をビルドして実行します。
$table
パラメータは、新しいカラムを追加されるテーブルの名前を指定します。
$column
パラメータは、新しいカラムの名前を指定します。
そして $type
パラメータは、新しいカラムの定義を指定するものです。
カラムの定義は、"createTable" の節で説明したように、抽象データ型を含むことが出来ます。
クエリビルダはテーブル名とカラム名を適切に引用符号で囲みます。
下記はテーブルにカラムを追加する方法を示す例です。
dropColumn()
dropColumn() メソッドは、テーブルからカラムを削除する SQL 文をビルドして実行します。
$table
パラメータは、カラムを削除されるテーブルの名前を指定します。
$column
パラメータは、削除されるカラムの名前を指定します。
クエリビルダはテーブル名とカラム名を適切に引用符号で囲みます。
下記はテーブルからカラムを削除する方法を示す例です。
renameColumn()
renameColumn() メソッドは、テーブルのカラム名を変更する SQL 文をビルドして実行します。
$table
パラメータは、カラム名を変更されるテーブルの名前を指定します。
$name
パラメータは古いカラム名、$newName
パラメータは新しいカラム名を指定します。
クエリビルダはテーブル名とカラム名を適切に引用符号で囲みます。
下記はテーブルのカラム名を変更する方法を示す例です。
alterColumn()
alterColumn() メソッドは、テーブルのカラムを変更する SQL 文をビルドして実行します。
$table
パラメータは、カラムを変更されるテーブルの名前を指定します。
$column
パラメータは、変更されるカラムの名前を指定します。
そして $type
パラメータは、カラムの新しい定義を指定するものです。
カラムの定義は、"createTable" の節で説明したように、抽象データ型を含むことが出来ます。
クエリビルダはテーブル名とカラム名を適切に引用符号で囲みます。
下記はテーブルのカラムを変更する方法を示す例です。
addForeignKey()
addForeignKey() メソッドは、テーブルに外部キー制約を追加する SQL 文をビルドして実行します。
$name
パラメータは、外部キーの名前を指定します。
$table
パラメータと $columns
パラメータは、外部キーが関係するテーブルとカラムの名前を指定します。
複数のカラムがある場合は、カンマで区切らなければなりません。
$refTable
パラメータと $refColumns
パラメータは、外部キーが参照するテーブルとカラムの名前を指定します。
$delete
パラメータと $update
パラメータは、それぞれ、SQL 文における ON DELETE
オプションと ON UPDATE
オプションを指定します。
そして $type
パラメータは、カラムの新しい定義を指定するものです。
カラムの定義は、"createTable" の節で説明したように、抽象データ型を含むことが出来ます。
ほとんどの DBMS は以下のオプションをサポートしています。
すなわち、RESTRICT
、 CASCADE
、NO ACTION
、SET DEFAULT
、SET NULL
というオプションです。
クエリビルダはテーブル名、インデックス名、カラム名を適切に引用符号で囲みます。
下記は外部キー制約を追加する方法を示す例です。
dropForeignKey()
dropForeignKey() メソッドは、外部キー制約を削除する SQL 文をビルドして実行します。
$name
パラメータは、削除する外部キー制約の名前を指定します。
$table
パラメータは、その外部キー制約が課されているテーブルの名前を指定します。
クエリビルダはテーブル名と外部キー制約名を適切に引用符号で囲みます。
下記は外部キー制約を削除する方法を示す例です。
createIndex()
createIndex() メソッドは、インデックスを作成する SQL 文をビルドして実行します。
$name
パラメータは、作成されるインデックスの名前を指定します。
$table
パラメータは、インデックスを追加されるテーブルの名前を指定します。
$column
パラメータは、インデックスされるカラムの名前を指定します。
そして $unique
パラメータは、ユニークなインデックスを作成するかどうかを指定するものです。
インデックスが複数のカラムから構成される場合は、カラム名をコンマで区切らなければなりません。
クエリビルダはテーブル名、インデックス名、カラム名を適切に引用符号で囲みます。
下記はインデックスを作成する方法を示す例です。
dropIndex()
dropIndex() メソッドは、インデックスを削除する SQL 文をビルドして実行します。
$name
パラメータは、削除されるインデックスの名前を指定します。
$table
パラメータは、削除されるインデックスを持っているテーブルの名前を指定します。
クエリビルダはテーブル名とインデックス名を適切に引用符号で囲みます。
下記はインデックスを削除する方法を示す例です。