Yii的查詢構造器提供了一個用面向對象的方法來構造SQL語句。他讓開發人員可以用類的方法,屬性來作爲SQL語句的一部分。然後把不同部分組裝到一個正確的SQL語句中,調用DAO的方法來執行。下面的例子演示如何用QB來構造SQL語句
- $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();
如果你是在程序裏拼裝SQL,或者是基於你的程序邏輯來拼裝,那麼QB就是最合適的。用QB的好處諸多:
●可以程序化的編寫負責的SQL語句
●自動引用表名,列名,避免跟其他的關鍵詞衝突
●引用參數banding的方法,防止SQL注入
●提供了抽象數據庫,這可以讓數據庫遷移變得很簡單。
QB的使用並非強制性的,實際上,如果你的查詢非常的簡單,那麼直接寫SQL語句更簡單,也更快,沒必要非得用QB。但是需要特別注意的一定,不要把QB跟純的SQL混用。
1.1 準備QB
Yii QB 是在CDbCommand的選項裏提供的。主要的查詢類是在DAO裏。
用QB之前,我們先實例化一個CDbCommand:
- $command = Yii::app()->db->createCommand();
這行代碼裏,我們用Yii::app()->db獲取數據庫連接,然後調用createCommand()創建所需要的命名對象。注意到上面我們調用createCommand時,參數是空的。之前DAO的時候是直接把SQL語句初始化進去。現在這裏留空,是因爲我們要用QB來構造SQL語句。
1.2 創建查詢SQL
查詢語句涉及到SELECT的語句,QB提供了一整套的方法來構造SELECT的每個部分。由於這些方法都返回的是CDbCommand句柄,所以我們在用的時候,可以用串鏈的方式來做,就像本節開篇的那樣作法。具體的方法就不翻譯了,節約時間
接下來,我們一一解釋如何使用這些構造器的方法。爲了簡便,默認底層數據庫是Mysql,如果你使用的是其他數據庫,table/column/value 這些在接下來的例子中或許會有所不同。
select()
- function select($columns='*')
這個不解釋了,列出一些例子。
- // 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()
- function selectDistinct($columns)
這個就是在選擇的時候,去掉重複的值。例如,selectDistinct('id, username') 就等同於SELECT DISTINCT `id`, `username`
from()
- function from($tables)
from這個方法用來指定查詢的FROM部分。變量$tables指定了那些表將是用來選擇的。這些表名可以用“,”隔開。表明也可以攜帶schema的前綴。
- // 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()
- function where($conditions, $params=array())
where這個方法,指定了查詢中的WHERE這個部分。變量$conditions指定了查詢條件,$params 指定了所有用到的變量。$conditions可以是一個簡單的字符串(如id=1),也可以是一個數組的形式:
- array(operator, operand1, operand2, ...)
在上面的數組中,operator可以是以下的幾種類型:
● 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: 同上
● in:第一項表示數據庫的字段,第二項表示一個範圍的數組。例如:array('in', 'id', array(1,2,3)) 等同於id IN (1,2,3)。
● not in:同上
● like:array('like', 'name', '%tester%')等同於nameLIKE '%tester%'
● not like:同上
● or like:跟like一致,只是爲了連接多個like語句,加了一個or的操作符。
● or not like:同上
以下是一些具體的實例:
- // 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%')))
注意,例如我們在用%或者是_這些特殊字符集的時候,要特別注意。如果這些模式是用戶輸入的,我們要用以下的方法來對待特殊字符:
- $keyword=$ GET['q'];
- // escape % and characters
- $keyword=strtr($keyword, array('%'=>'n%', ' '=>'n '));
- $command->where(array('like', 'title', '%'.$keyword.'%'));
order()
- function order($columns)
這些命令如果懂SQL的,都不需要解釋了,不懂的去補習。後面的開始只給例子了。
- // 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 o set()
- function limit($limit, $offset=null)
- function offset($offset)
例子:
- // LIMIT 10
- limit(10)
- // LIMIT 10 OFFSET 20
- limit(10, 20)
- // OFFSET 20
- offset(20)
join() and its variants
- function join($table, $conditions, $params=array())
- function leftJoin($table, $conditions, $params=array())
- function rightJoin($table, $conditions, $params=array())
- function crossJoin($table)
- function naturalJoin($table)
例子
- // 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=1
- leftJoin('pub.tbl profile p', 'p.user id=id AND type=:type', array(':type'=>1))
group()
- function group($columns)
例子
- // GROUP BY `name`, `id`
- group('name, id')
- // GROUP BY `tbl profile`.`name`, `id`
- group(array('tbl profile.name', 'id')
having()
- function having($conditions, $params=array())
例子
- // 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()
- function union($sql)
例子
- // UNION (select * from tbl profile)
- union('select * from tbl profile')
執行語句
在用上面的這些構造器方法,構造好SQL後,我們可以調用DAO來執行語句了。例如我們可以調用CDbCommand::queryRow()獲取第一個符合結果的記錄,也可以用CDbCommand::queryAll()來一次性獲取所有的查詢結果。例如:
- $users = Yii::app()->db->createCommand()
- ->select('*')
- ->from('tbl user')
- ->queryAll();
訪問SQL
除了執行構造器組裝的SQL語句外,我們也可以調用CDbCommand::getText()來獲取當前的SQL語句:
- $sql = Yii::app()->db->createCommand()
- ->select('*')
- ->from('tbl user')
- ->text;
如果查詢中有用到變量,可以使用CDbCommand::params來讀取屬性。
QB的語法替換
有時候,用QB的方法鏈構造語句並不是最好的方法。Yii 的QB提供了用簡單對象賦值的方法。特別是在每個查詢構造方法中都有相同名字的時候。給屬性值就跟調用方法是一樣的。例如,下面的兩個例子效果是一樣的。
- $command->select(array('id', 'username'));
- $command->select = array('id', 'username');
甚至說,CDbConnection::createCommand()都可以用數組來做參數!這意味着我們可以按照下面的方法來執行(本人覺得不是很好的習慣,不知道什麼特定的情況需要這樣搞)
- $row = Yii::app()->db->createCommand(array(
- 'select' => array('id', 'username'),
- 'from' => 'tbl user',
- 'where' => 'id=:id',
- 'params' => array(':id'=>1),
- ))->queryRow();
創建多次查詢
一個CDbCommand的對象,可以用來多次執行查詢動作。在執行新的查詢語句之前,必須要調用CDbCommand::reset()先清除之前的查詢語句。
- $command = Yii::app()->db->createCommand();
- $users = $command->select('*')->from('tbl users')->queryAll();
- $command->reset(); // clean up the previous query
- $posts = $command->select('*')->from('tbl posts')->queryAll();
1.3 創建數據操作語句
操作語句就是增刪改,會對數據庫的數據進行更改的操作。具體就不介紹太多了
● insert(): inserts a row into a table
● update(): updates the data in a table
● delete(): deletes the data from a table
insert()
- function insert($table, $columns)
- // build and execute the following SQL:
- // INSERT INTO `tbl user` (`name`, `email`) VALUES (:name, :email)
- $command->insert('tbl user', array(
- 'name'=>'Tester',
- 'email'=>'[email protected]',
- ));
update()
- function update($table, $columns, $conditions='', $params=array())
- // build and execute the following SQL:
- // UPDATE `tbl user` SET `name`=:name WHERE id=:id
- $command->update('tbl user', array(
- 'name'=>'Tester',
- ), 'id=:id', array(':id'=>1));
delete()
- function delete($table, $conditions='', $params=array())
- // build and execute the following SQL:
- // DELETE FROM `tbl user` WHERE id=:id
- $command->delete('tbl user', 'id=:id', array(':id'=>1));
1.4 創建SML查詢(好像按照常規的分應該是屬於DDL)
除了DML的操作以外,QB也提供了一些操作數據庫架構的方法。主要有以下幾種
- ● createTable(): creates a table
- ● renameTable(): renames a table
- ● dropTable(): drops a table
- ● truncateTable(): truncates a table
- ● addColumn(): adds a table column
- ● renameColumn(): renames a table column
- ● alterColumn(): alters a table column
- ● dropColumn(): drops a table column
- ● createIndex(): creates an index
- ● dropIndex(): drops an index
抽象數據類型
Yii QB 提供了一些抽象數據類型,可以用來定義表的字段類型。不像傳統的底層數據庫系統類型,這些抽象數據類型是獨立於底層數據庫的。當用抽象數據類型來定義字段類型的時候,QB在執行的時候,會自動轉換爲底層數據庫的物理類型。
QB提供的數據類型包括
- pk: a generic primary key type, will be converted into int(11) NOT NULL AUTO
- INCREMENT PRIMARY KEY for MySQL;
- string: string type, will be converted into varchar(255) for MySQL;
- text: text type (long string), will be converted into text for MySQL;
- integer: integer type, will be converted into int(11) for MySQL;
- float:
- oating number type, will be converted into float for MySQL;
- decimal: decimal number type, will be converted into decimal for MySQL;
- datetime: datetime type, will be converted into datetime for MySQL;
- timestamp: timestamp type, will be converted into timestamp for MySQL;
- time: time type, will be converted into time for MySQL;
- date: date type, will be converted into date for MySQL;
- binary: binary data type, will be converted into blob for MySQL;
- boolean: boolean type, will be converted into tinyint(1) for MySQL;
- money: money/currency type, will be converted into decimal(19,4) for MySQL. This
- type has been available since version 1.1.8.
題外話,這些都是基本的SQL,用的時候翻一下手冊就可以了。都是很好理解的。
createTable()
- function createTable($table, $columns, $options=null)
- // CREATE TABLE `tbl user` (
- // `id` int(11) NOT NULL AUTO INCREMENT PRIMARY KEY,
- // `username` varchar(255) NOT NULL,
- // `location` point
- // ) ENGINE=InnoDB
- createTable('tbl user', array(
- 'id' => 'pk',
- 'username' => 'string NOT NULL',
- 'location' => 'point',
- ), 'ENGINE=InnoDB')
renameTable()
- function renameTable($table, $newName)
- // RENAME TABLE `tbl users` TO `tbl user`
- renameTable('tbl users', 'tbl user')
dropTable()
- function dropTable($table)
- // DROP TABLE `tbl user`
- dropTable('tbl user')
truncateTable()
- function truncateTable($table)
- // TRUNCATE TABLE `tbl user`
- truncateTable('tbl user')
addColumn()
- function addColumn($table, $column, $type)
- // ALTER TABLE `tbl user` ADD `email` varchar(255) NOT NULL
- addColumn('tbl user', 'email', 'string NOT NULL')
dropColumn()
- function dropColumn($table, $column)
- // ALTER TABLE `tbl user` DROP COLUMN `location`
- dropColumn('tbl user', 'location')
renameColumn()
- function renameColumn($table, $name, $newName)
- // ALTER TABLE `tbl users` CHANGE `name` `username` varchar(255) NOT NULL
- renameColumn('tbl user', 'name', 'username')
alterColumn()
- function alterColumn($table, $column, $type)
- // ALTER TABLE `tbl user` CHANGE `username` `username` varchar(255) NOT NULL
- alterColumn('tbl user', 'username', 'string NOT NULL')
addForeignKey()
- function addForeignKey($name, $table, $columns,
- $refTable, $refColumns, $delete=null, $update=null)
- // ALTER TABLE `tbl profile` ADD CONSTRAINT `fk profile user id`
- // FOREIGN KEY (`user id`) REFERENCES `tbl user` (`id`)
- // ON DELETE CASCADE ON UPDATE CASCADE
- addForeignKey('fk profile user id', 'tbl profile', 'user id',
- 'tbl user', 'id', 'CASCADE', 'CASCADE')
dropForeignKey()
- function dropForeignKey($name, $table)
- // ALTER TABLE `tbl profile` DROP FOREIGN KEY `fk profile user id`
- dropForeignKey('fk profile user id', 'tbl profile')
createIndex()
- function createIndex($name, $table, $column, $unique=false)
- // CREATE INDEX `idx username` ON `tbl user` (`username`)
- createIndex('idx username', 'tbl user')
dropIndex()
- function dropIndex($name, $table)
- // DROP INDEX `idx username` ON `tbl user`
- dropIndex('idx username', 'tbl user')