數據庫之Query Builder

Yii的查詢構造器提供了一個用面向對象的方法來構造SQL語句。他讓開發人員可以用類的方法,屬性來作爲SQL語句的一部分。然後把不同部分組裝到一個正確的SQL語句中,調用DAO的方法來執行。下面的例子演示如何用QB來構造SQL語句

  1. $user = Yii::app()->db->createCommand()  
  2. ->select('id, username, profile')  
  3. ->from('tbl_user u')  
  4. ->join('tbl_profile p''u.id=p.user_id')  
  5. ->where('id=:id'array(':id'=>$id))  
  6. ->queryRow(); 

如果你是在程序裏拼裝SQL,或者是基於你的程序邏輯來拼裝,那麼QB就是最合適的。用QB的好處諸多:

●可以程序化的編寫負責的SQL語句
●自動引用表名,列名,避免跟其他的關鍵詞衝突
●引用參數banding的方法,防止SQL注入
●提供了抽象數據庫,這可以讓數據庫遷移變得很簡單。

QB的使用並非強制性的,實際上,如果你的查詢非常的簡單,那麼直接寫SQL語句更簡單,也更快,沒必要非得用QB。但是需要特別注意的一定,不要把QB跟純的SQL混用。

1.1 準備QB

Yii QB 是在CDbCommand的選項裏提供的。主要的查詢類是在DAO裏。

用QB之前,我們先實例化一個CDbCommand:

  1. $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()

  1. function select($columns='*'

這個不解釋了,列出一些例子。

  1. // SELECT *  
  2. select()  
  3. // SELECT `id`, `username`  
  4. select('id, username')  
  5. // SELECT `tbl user`.`id`, `username` AS `name`  
  6. select('tbl user.id, username as name')  
  7. // SELECT `id`, `username`  
  8. select(array('id''username'))  
  9. // SELECT `id`, count(*) as num  
  10. select(array('id''count(*) as num')) 

selectDistinct()

  1. function selectDistinct($columns

這個就是在選擇的時候,去掉重複的值。例如,selectDistinct('id, username') 就等同於SELECT DISTINCT `id`, `username`

from()

  1. function from($tables

from這個方法用來指定查詢的FROM部分。變量$tables指定了那些表將是用來選擇的。這些表名可以用“,”隔開。表明也可以攜帶schema的前綴。

  1. // FROM `tbl user`  
  2. from('tbl user')  
  3. // FROM `tbl user` `u`, `public`.`tbl profile` `p`  
  4. from('tbl user u, public.tbl profile p')  
  5. // FROM `tbl user`, `tbl profile`  
  6. from(array('tbl user''tbl profile'))  
  7. // FROM `tbl user`, (select * from tbl profile) p  
  8. from(array('tbl user''(select * from tbl profile) p')) 

where()

  1. function where($conditions$params=array()) 

where這個方法,指定了查詢中的WHERE這個部分。變量$conditions指定了查詢條件,$params 指定了所有用到的變量。$conditions可以是一個簡單的字符串(如id=1),也可以是一個數組的形式:

  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:同上

以下是一些具體的實例:

  1. // WHERE id=1 or id=2  
  2. where('id=1 or id=2')  
  3. // WHERE id=:id1 or id=:id2  
  4. where('id=:id1 or id=:id2'array(':id1'=>1, ':id2'=>2))  
  5. // WHERE id=1 OR id=2  
  6. where(array('or''id=1''id=2'))  
  7. // WHERE id=1 AND (type=2 OR type=3)  
  8. where(array('and''id=1'array('or''type=2''type=3')))  
  9. // WHERE `id` IN (1, 2)  
  10. where(array('in''id'array(1, 2))  
  11. // WHERE `id` NOT IN (1, 2)  
  12. where(array('not in''id'array(1,2)))  
  13. // WHERE `name` LIKE '%Qiang%'  
  14. where(array('like''name''%Qiang%'))  
  15. // WHERE `name` LIKE '%Qiang' AND `name` LIKE '%Xue'  
  16. where(array('like''name'array('%Qiang''%Xue')))  
  17. // WHERE `name` LIKE '%Qiang' OR `name` LIKE '%Xue'  
  18. where(array('or like''name'array('%Qiang''%Xue')))  
  19. // WHERE `name` NOT LIKE '%Qiang%'  
  20. where(array('not like''name''%Qiang%'))  
  21. // WHERE `name` NOT LIKE '%Qiang%' OR `name` NOT LIKE '%Xue%'  
  22. where(array('or not like''name'array('%Qiang%''%Xue%'))) 

注意,例如我們在用%或者是_這些特殊字符集的時候,要特別注意。如果這些模式是用戶輸入的,我們要用以下的方法來對待特殊字符:

  1. $keyword=$ GET['q'];  
  2. // escape % and characters  
  3. $keyword=strtr($keywordarray('%'=>'n%'' '=>'n '));  
  4. $command->where(array('like''title''%'.$keyword.'%')); 

order()

  1. function order($columns

這些命令如果懂SQL的,都不需要解釋了,不懂的去補習。後面的開始只給例子了。

  1. // ORDER BY `name`, `id` DESC  
  2. order('name, id desc')  
  3. // ORDER BY `tbl profile`.`name`, `id` DESC  
  4. order(array('tbl profile.name''id desc')) 

limit() and o set()

  1. function limit($limit$offset=null)  
  2. function offset($offset

例子:

  1. // LIMIT 10  
  2. limit(10)  
  3. // LIMIT 10 OFFSET 20  
  4. limit(10, 20)  
  5. // OFFSET 20  
  6. offset(20) 

join() and its variants

  1. function join($table$conditions$params=array())  
  2. function leftJoin($table$conditions$params=array())  
  3. function rightJoin($table$conditions$params=array())  
  4. function crossJoin($table)  
  5. function naturalJoin($table

例子

  1. // JOIN `tbl profile` ON user id=id  
  2. join('tbl profile''user id=id')  
  3. // LEFT JOIN `pub`.`tbl profile` `p` ON p.user id=id AND type=1  
  4. leftJoin('pub.tbl profile p''p.user id=id AND type=:type'array(':type'=>1)) 

group()

  1. function group($columns

例子

  1. // GROUP BY `name`, `id`  
  2. group('name, id')  
  3. // GROUP BY `tbl profile`.`name`, `id`  
  4. group(array('tbl profile.name''id'

having()

  1. function having($conditions$params=array()) 

例子

  1. // HAVING id=1 or id=2  
  2. having('id=1 or id=2')  
  3. // HAVING id=1 OR id=2  
  4. having(array('or''id=1''id=2')) 

union()

  1. function union($sql

例子

  1. // UNION (select * from tbl profile)  
  2. union('select * from tbl profile'

執行語句

在用上面的這些構造器方法,構造好SQL後,我們可以調用DAO來執行語句了。例如我們可以調用CDbCommand::queryRow()獲取第一個符合結果的記錄,也可以用CDbCommand::queryAll()來一次性獲取所有的查詢結果。例如:

  1. $users = Yii::app()->db->createCommand()  
  2. ->select('*')  
  3. ->from('tbl user')  
  4. ->queryAll(); 

訪問SQL

除了執行構造器組裝的SQL語句外,我們也可以調用CDbCommand::getText()來獲取當前的SQL語句:

  1. $sql = Yii::app()->db->createCommand()  
  2. ->select('*')  
  3. ->from('tbl user')  
  4. ->text; 

如果查詢中有用到變量,可以使用CDbCommand::params來讀取屬性。

QB的語法替換

有時候,用QB的方法鏈構造語句並不是最好的方法。Yii 的QB提供了用簡單對象賦值的方法。特別是在每個查詢構造方法中都有相同名字的時候。給屬性值就跟調用方法是一樣的。例如,下面的兩個例子效果是一樣的。

  1. $command->select(array('id''username'));  
  2. $command->select = array('id''username'); 

甚至說,CDbConnection::createCommand()都可以用數組來做參數!這意味着我們可以按照下面的方法來執行(本人覺得不是很好的習慣,不知道什麼特定的情況需要這樣搞)

  1. $row = Yii::app()->db->createCommand(array(  
  2. 'select' => array('id''username'),  
  3. 'from' => 'tbl user',  
  4. 'where' => 'id=:id',  
  5. 'params' => array(':id'=>1),  
  6. ))->queryRow(); 

創建多次查詢

一個CDbCommand的對象,可以用來多次執行查詢動作。在執行新的查詢語句之前,必須要調用CDbCommand::reset()先清除之前的查詢語句。

  1. $command = Yii::app()->db->createCommand();  
  2. $users = $command->select('*')->from('tbl users')->queryAll();  
  3. $command->reset(); // clean up the previous query  
  4. $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()

  1. function insert($table$columns
  1. // build and execute the following SQL:  
  2. // INSERT INTO `tbl user` (`name`, `email`) VALUES (:name, :email)  
  3. $command->insert('tbl user'array(  
  4.     'name'=>'Tester',  
  5.     'email'=>'[email protected]',  
  6. )); 

update()

  1. function update($table$columns$conditions=''$params=array()) 
  1. // build and execute the following SQL:  
  2. // UPDATE `tbl user` SET `name`=:name WHERE id=:id  
  3. $command->update('tbl user'array(  
  4.     'name'=>'Tester',  
  5. ), 'id=:id'array(':id'=>1)); 

delete()

  1. function delete($table$conditions=''$params=array()) 
  1. // build and execute the following SQL:  
  2. // DELETE FROM `tbl user` WHERE id=:id  
  3. $command->delete('tbl user''id=:id'array(':id'=>1)); 

1.4 創建SML查詢(好像按照常規的分應該是屬於DDL)

除了DML的操作以外,QB也提供了一些操作數據庫架構的方法。主要有以下幾種

  1. ● createTable(): creates a table  
  2. ● renameTable(): renames a table  
  3. ● dropTable(): drops a table  
  4. ● truncateTable(): truncates a table  
  5. ● addColumn(): adds a table column  
  6. ● renameColumn(): renames a table column  
  7. ● alterColumn(): alters a table column  
  8. ● dropColumn(): drops a table column  
  9. ● createIndex(): creates an index  
  10. ● dropIndex(): drops an index 

抽象數據類型

Yii QB 提供了一些抽象數據類型,可以用來定義表的字段類型。不像傳統的底層數據庫系統類型,這些抽象數據類型是獨立於底層數據庫的。當用抽象數據類型來定義字段類型的時候,QB在執行的時候,會自動轉換爲底層數據庫的物理類型。

QB提供的數據類型包括

  1.  pk: a generic primary key type, will be converted into int(11) NOT NULL AUTO  
  2. INCREMENT PRIMARY KEY for MySQL;  
  3.  string: string type, will be converted into varchar(255) for MySQL;  
  4.  text: text type (long string), will be converted into text for MySQL;  
  5.  integer: integer type, will be converted into int(11) for MySQL;  
  6.  float:   
  7. oating number type, will be converted into float for MySQL;  
  8.  decimal: decimal number type, will be converted into decimal for MySQL;  
  9.  datetime: datetime type, will be converted into datetime for MySQL;  
  10.  timestamp: timestamp type, will be converted into timestamp for MySQL;  
  11.  time: time type, will be converted into time for MySQL;  
  12.  datedate type, will be converted into date for MySQL;  
  13.  binary: binary data type, will be converted into blob for MySQL;  
  14.  boolean: boolean type, will be converted into tinyint(1) for MySQL;  
  15.  money: money/currency type, will be converted into decimal(19,4) for MySQL. This  
  16. type has been available since version 1.1.8. 

題外話,這些都是基本的SQL,用的時候翻一下手冊就可以了。都是很好理解的。

createTable()

  1. function createTable($table$columns$options=null) 
  1. // CREATE TABLE `tbl user` (  
  2. // `id` int(11) NOT NULL AUTO INCREMENT PRIMARY KEY,  
  3. // `username` varchar(255) NOT NULL,  
  4. // `location` point  
  5. // ) ENGINE=InnoDB  
  6. createTable('tbl user'array(  
  7.         'id' => 'pk',  
  8.         'username' => 'string NOT NULL',  
  9.         'location' => 'point',  
  10.     ), 'ENGINE=InnoDB'

renameTable()

  1. function renameTable($table$newName
  1. // RENAME TABLE `tbl users` TO `tbl user`  
  2. renameTable('tbl users''tbl user'

dropTable()

  1. function dropTable($table
  1. // DROP TABLE `tbl user`  
  2. dropTable('tbl user'

truncateTable()

  1. function truncateTable($table
  1. // TRUNCATE TABLE `tbl user`  
  2. truncateTable('tbl user'

addColumn()

  1. function addColumn($table$column$type
  1. // ALTER TABLE `tbl user` ADD `email` varchar(255) NOT NULL  
  2. addColumn('tbl user''email''string NOT NULL'

dropColumn()

  1. function dropColumn($table$column
  1. // ALTER TABLE `tbl user` DROP COLUMN `location`  
  2. dropColumn('tbl user''location'

renameColumn()

  1. function renameColumn($table$name$newName
  1. // ALTER TABLE `tbl users` CHANGE `name` `username` varchar(255) NOT NULL  
  2. renameColumn('tbl user''name''username'

alterColumn()

  1. function alterColumn($table$column$type
  1. // ALTER TABLE `tbl user` CHANGE `username` `username` varchar(255) NOT NULL  
  2. alterColumn('tbl user''username''string NOT NULL'

addForeignKey()

  1. function addForeignKey($name$table$columns,  
  2. $refTable$refColumns$delete=null, $update=null) 
  1. // ALTER TABLE `tbl profile` ADD CONSTRAINT `fk profile user id`  
  2. // FOREIGN KEY (`user id`) REFERENCES `tbl user` (`id`)  
  3. // ON DELETE CASCADE ON UPDATE CASCADE  
  4. addForeignKey('fk profile user id''tbl profile''user id',  
  5. 'tbl user''id''CASCADE''CASCADE'

dropForeignKey()

  1. function dropForeignKey($name$table
  1. // ALTER TABLE `tbl profile` DROP FOREIGN KEY `fk profile user id`  
  2. dropForeignKey('fk profile user id''tbl profile'

createIndex()

  1. function createIndex($name$table$column$unique=false) 
  1. // CREATE INDEX `idx username` ON `tbl user` (`username`)  
  2. createIndex('idx username''tbl user'

dropIndex()

  1. function dropIndex($name$table
  1. // DROP INDEX `idx username` ON `tbl user`  
  2. dropIndex('idx username''tbl user'

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章