Files
yii/docs/guide/database.query-builder.txt
2010-11-17 19:56:48 +00:00

428 lines
16 KiB
Plaintext

Query Builder
=============
The Yii Query Builder provides an object-orient way of writing SQL statements. It allows developers to use class methods and properties to specify individual parts of a SQL statement. It then assembles different parts into a valid SQL statement that can be further executed by calling the DAO methods as described in [Data Access Objects](/doc/guide/database.dao). The following shows a typical usage of the Query Builder:
~~~
[php]
$user = Yii::app()->db->createCommand()
->select('id, username, profile')
->from('tbl_user u')
->join('tbl_profile p', 'u.id=p.user_id')
->where('id=:id', array(':id'=>$id))
->queryRow();
~~~
The Query Builder is best used when you need to assemble a SQL statement procedurally, or based on some conditional logic in your application. The main benefits of using the Query Builder include:
* It allows building complex SQL statements programmatically.
* It automatically quotes table names and column names to prevent conflict with SQL reserved words and special characters.
* It also quotes parameter values and uses parameter binding when possible, which helps reduce risk of SQL injection attacks.
* It offers certain degree of DB abstraction, which simplifies migration to different DB platforms.
It is not mandatory to use the Query Builder. In fact, if your queries are simple, it is easier and faster to directly write SQL statements.
Preparing Query Builder
-----------------------
The Yii Query Builder is provided in terms of [CDbCommand], the main DB query class described in [Data Access Objects](/doc/guide/database.dao).
To start using the Query Builder, we create a new instance of [CDbCommand] as follows,
~~~
[php]
$command = Yii::app()->db->createCommand();
~~~
That is, we use `Yii::app()->db` to get the DB connection, and then call [CDbConnection::createCommand()] to create the needed command instance.
Note that instead of passing a whole SQL statement to the `createCommand()` call as we do in [Data Access Objects](/doc/guide/database.dao), we leave it empty. This is because we will build individual parts of the SQL statement using the Query Builder methods explained in the following.
Building Queries
----------------
Building a SQL query involves calling different query builder methods to build individual parts of the query. Because all these methods return the [CDbCommand] instance, we can call them using method chaining, as shown in the previous example.
In the following, we explain how to use these query builder methods. We assume the underlying database is MySQL. Note that if you are using other DBMS, the table/column/value quoting shown in the examples may be different.
### select
~~~
[php]
function select($columns='*')
~~~
The [select|CDbCommand::select] method specifies the `SELECT` part of a query. The `$columns` parameter specifies the columns to be selected, which can be either a string representing comma-separated columns, or an array of column names. Column names can contain table prefixes and/or column aliases. The method will automatically quote the column names unless a column contains some parenthesis (which means the column is given as a DB expression).
Below are some examples:
~~~
[php]
// SELECT *
select()
// SELECT `id`, `username`
select('id, username')
// SELECT `tbl_user`.`id`, `username` AS `name`
select('tbl_user.id, username as name')
// SELECT `id`, `username`
select(array('id', 'username'))
// SELECT `id`, count(*) as num
select(array('id', 'count(*) as num'))
~~~
### selectDistinct
~~~
[php]
function selectDistinct($columns)
~~~
The [selectDistinct|CDbCommand::selectDistinct] method is similar as [select|CDbCommand::select] except that it turns on the `DISTINCT` flag. For example, `select('id, username')` will generate the following SQL:
~~~
SELECT DISTINCT `id`, `username`
~~~
### from
~~~
[php]
function from($tables)
~~~
The [from|CDbCommand::from] method specifies the `FROM` part of a query. The `$tables` parameter specifies which tables to be selected from. This can be either a string representing comma-separated table names, or an array of table names. Table names can contain schema prefixes (e.g. `public.tbl_user`) and/or table aliases (e.g. `tbl_user u`). The method will automatically quote the table names unless it contains some parenthesis (which means the table is given as a sub-query or DB expression).
Below are some examples:
~~~
[php]
// FROM `tbl_user`
from('tbl_user')
// FROM `tbl_user` `u`, `public`.`tbl_profile` `p`
from('tbl_user u, public.tbl_profile p')
// FROM `tbl_user`, `tbl_profile`
from(array('tbl_user', 'tbl_profile'))
// FROM `tbl_user`, (select * from tbl_profile) p
from(array('tbl_user', '(select * from tbl_profile) p'))
~~~
### where
~~~
[php]
function where($conditions, $params=array())
~~~
The [where|CDbCommand::where] method specifies the `WHERE` part of a query. The `$conditions` parameter specifies query conditions while `$params` specifies the parameters to be bound to the whole query. The `$conditions` parameter can be either a string (e.g. `id=1`) or an array of the format:
~~~
[php]
array(operator, operand1, operand2, ...)
~~~
where `operator` can be any of the following:
* `and`: the operands should be concatenated together using `AND`. For example, `array('and', 'id=1', 'id=2')` will generate `id=1 AND id=2`. If an operand is an array, it will be converted into a string using the same rules described here. For example, `array('and', 'type=1', array('or', 'id=1', 'id=2'))` will generate `type=1 AND (id=1 OR id=2)`. The method will NOT do any quoting or escaping.
* `or`: similar as the `and` operator except that the operands are concatenated using OR.
* `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing the range of the values that the column or DB expression should be in. For example, `array('in', 'id', array(1,2,3))` will generate `id IN (1,2,3)`. The method will properly quote the column name and escape values in the range.
* `not in`: similar as the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition.
* `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing the range of the values that the column or DB expression should be like. For example, `array('like', 'name', 'tester')` will generate `name LIKE '%tester%'`. When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated using `AND`. For example, `array('like', 'name', array('test', 'sample'))` will generate `name LIKE '%test%' AND name LIKE '%sample%'`. The method will properly quote the column name and escape values in the range.
* `not like`: similar as the `like` operator except that `LIKE` is replaced with `NOT LIKE` in the generated condition.
* `or like`: similar as the `like` operator except that `OR` is used to concatenated several `LIKE` predicates.
* `or not like`: similar as the `not like` operator except that `OR` is used to concatenated several `NOT LIKE` predicates.
Below are some examples of using `where`:
~~~
[php]
// WHERE id=1 or id=2
where('id=1 or id=2')
// WHERE id=:id1 or id=:id2
where('id=:id1 or id=:id2', array(':id1'=>1, ':id2'=>2))
// WHERE id=1 OR id=2
where(array('or', 'id=1', 'id=2'))
// WHERE id=1 AND (type=2 OR type=3)
where(array('and', id=1', array('or', 'type=2', 'type=3')))
// WHERE `id` IN (1, 2)
where(array('in', 'id', array(1, 2))
// WHERE `id` NOT IN (1, 2)
where(array('not in', 'id', array(1,2)))
// WHERE `name` LIKE '%Qiang%'
where(array('like', 'name', 'Qiang'))
// WHERE `name` LIKE '%Qiang%' AND `name` LIKE '%Xue%'
where(array('like', 'name', array('Qiang', 'Xue')))
// WHERE `name` LIKE '%Qiang%' OR `name` LIKE '%Xue%'
where(array('or like', 'name', array('Qiang', 'Xue')))
// WHERE `name` NOT LIKE '%Qiang%'
where(array('not like', 'name', 'Qiang'))
// WHERE `name` NOT LIKE '%Qiang%' OR `name` NOT LIKE '%Xue%'
where(array('or not like', 'name', array('Qiang', 'Xue')))
~~~
### order
~~~
[php]
function order($columns)
~~~
The [order|CDbCommand::order] method specifies the `ORDER BY` part of a query.
The `$columns` parameter specifies the columns to be ordered by, which can be either a string representing comma-separated columns and order directions (`ASC` or `DESC`), or an array of columns and order directions. Column names can contain table prefixes. The method will automatically quote the column names unless a column contains some parenthesis (which means the column is given as a DB expression).
Below are some examples:
~~~
[php]
// ORDER BY `name`, `id` DESC
order('name, id desc')
// ORDER BY `tbl_profile`.`name`, `id` DESC
order(array('tbl_profile.name', 'id desc')
~~~
### limit and `offset`
~~~
[php]
function limit($limit, $offset=null)
function offset($offset)
~~~
The [limit|CDbCommand::limit] and [offset|CDbCommand::offset] methods specify the `LIMIT` and `OFFSET` part of a query. Note that some DBMS may not support `LIMIT` and `OFFSET` syntax. In this case, the Query Builder will rewrite the whole SQL statement to simulate the function of limit and offset.
Below are some examples:
~~~
[php]
// LIMIT 10
limit(10)
// LIMIT 10 OFFSET 20
limit(10, 20)
// OFFSET 20
offset(20)
~~~
### join and its variants
~~~
[php]
function join($table, $conditions, $params=array())
function leftJoin($table, $conditions, $params=array())
function rightJoin($table, $conditions, $params=array())
function crossJoin($table)
function naturalJoin($table)
~~~
The [join|CDbCommand::join] method and its variants specify how to join with other tables using `INNER JOIN`, `LEFT OUTER JOIN`, `RIGHT OUTER JOIN`, `CROSS JOIN`, or `NATURAL JOIN`. The `$table` parameter specifies which table to be joined with. The table name can contain schema prefix and/or alias. The method will quote the table name unless it contains a parenthesis meaning it is either a DB expression or sub-query. The `$conditions` parameter specifies the join condition. Its syntax is the same as that in [where|CDbCommand::where]. And `$params` specifies the parameters to be bound to the whole query.
Note that unlike other query builder methods, each call of a join method will be appended to the previous ones.
Below are some examples:
~~~
[php]
// JOIN `tbl_profile` ON user_id=id
join('tbl_profile', 'user_id=id')
// LEFT JOIN `pub`.`tbl_profile` `p` ON p.user_id=id AND type=:type
leftJoin('pub.tbl_profile p', 'p.user_id=id AND type=:type', array(':type'=>1))
~~~
### group
~~~
[php]
function group($columns)
~~~
The [group|CDbCommand::group] method specifies the `GROUP BY` part of a query.
The `$columns` parameter specifies the columns to be grouped by, which can be either a string representing comma-separated columns, or an array of columns. Column names can contain table prefixes. The method will automatically quote the column names unless a column contains some parenthesis (which means the column is given as a DB expression).
Below are some examples:
~~~
[php]
// GROUP BY `name`, `id`
group('name, id')
// GROUP BY `tbl_profile`.`name`, `id`
group(array('tbl_profile.name', 'id')
~~~
### having
~~~
[php]
function having($conditions, $params=array())
~~~
The [having|CDbCommand::having] method specifies the `HAVING` part of a query. Its usage is the same as [where|CDbCommand::where].
Below are some examples:
~~~
[php]
// HAVING id=1 or id=2
having('id=1 or id=2')
// HAVING id=1 OR id=2
having(array('or', 'id=1', 'id=2'))
~~~
### union
~~~
[php]
function union($sql)
~~~
The [union|CDbCommand::union] method specifies the `UNION` part of a query. It appends `$sql` to the existing SQL using `UNION` operator. Calling `union()` multiple times will append multiple SQLs to the existing SQL.
Below are some examples:
~~~
[php]
// UNION (select * from tbl_profile)
union('select * from tbl_profile')
~~~
### insert
~~~
[php]
function insert($table, $columns)
~~~
The [insert|CDbCommand::insert] method specifies an `INSERT` SQL statement. The `$table` parameter specifies which table to be inserted into, while `$columns` is an array of name-value pairs specifying the column values to be inserted. The method will quote the table name properly and will use parameter-binding for the values to be inserted.
Noe that unlike the previous query methods which specify parts of a `SELECT` query, the `insert`, `update` and `delete` methods (the latter two are to be described shortly) specify a complete SQL statement.
Below are some examples:
~~~
[php]
// INSERT INTO `tbl_user` (`name`, `email`) VALUES (:name, :email)
insert('tbl_user', array('name'=>'Tester', 'email'=>'tester@example.com'))
~~~
### update
~~~
[php]
function update($table, $columns, $conditions='', $params=array())
~~~
The [update|CDbCommand::update] method specifies an `UPDATE` SQL statement. The `$table` parameter specifies which table to be updated; `$columns` is an array of name-value pairs specifying the column values to be updated; `$conditions` and `$params` are like in [where|CDbCommand::where], which specify the `WHERE` clause in the `UPDATE` statement. The method will quote the table name properly and will use parameter-binding for the values to be updated.
Below are some examples:
~~~
[php]
// UPDATE `tbl_user` SET `name`=:name WHERE id=:id
update('tbl_user', array('name'=>'Tester'), 'id=:id', array(':id'=>1))
~~~
### delete
~~~
[php]
function delete($table, $conditions='', $params=array())
~~~
The [delete|CDbCommand::delete] method specifies a `DELETE` SQL statement. The `$table` parameter specifies which table to be updated; `$conditions` and `$params` are like in [where|CDbCommand::where], which specify the `WHERE` clause in the `DELETE` statement. The method will quote the table name properly.
Below are some examples:
~~~
[php]
// DELETE FROM `tbl_user` WHERE id=:id
delete('tbl_user', 'id=:id', array(':id'=>1))
~~~
Executing Queries
-----------------
After calling the above query builder methods to build a query, we can call the DAO methods as described in [Data Access Objects](/doc/guide/database.dao) to execute the query. For example, we can call [CDbCommand::queryRow()] to obtain a row of result, or [CDbCommand::queryAll()] to get all rows at once. Note that for `INSERT`, `UPDATE` and `DELETE` queries, we must use [CDbCommand::execute()] to execute them.
Below are some examples:
~~~
[php]
$users = Yii::app()->db->createCommand()
->select('*')
->from('tbl_user')
->queryAll();
Yii::app()->db->createCommand()
->insert('tbl_user', array(
'username' => 'tester',
'email' => 'tester@example.com',
))->execute();
~~~
Retrieving SQLs
---------------
Besides executing a query built by the Query Builder, we can also retrieve the corresponding SQL statement. This can be done by calling [CDbCommand::getText()].
~~~
[php]
$sql = Yii::app()->db->createCommand()
->select('*')
->from('tbl_user')
->getText();
~~~
If there are any parameters to be bound to the query, they can be retrieved via the [CDbCommand::params] property.
Alternative Syntax
------------------
Sometimes, using method chaining to build a query may not be the optimal choice. The Yii Query Builder allows a query to be built using simple object property assignments. In particular, for each query builder method, there is a corresponding property that has the same name. Assigning a value to the property is equivalent to calling the corresponding method. For example, the following two statements are equivalent, assuming `$command` represents a [CDbCommand] object:
~~~
[php]
$command->select(array('id', 'username'));
$command->select = array('id', 'username');
~~~
Furthermore, the [CDbConnection::createCommand()] method can take an array as the parameter. The name-value pairs in the array will be used to initialize the properties of the created [CDbCommand] instance. This means, we can use the following code to build a query:
~~~
[php]
$row = Yii::app()->db->createCommand(array(
'select' => array('id', 'username'),
'from' => 'tbl_user',
'where' => 'id=:id',
'params' => array(':id'=>1),
))->queryRow();
~~~
<div class="revision">$Id$</div>