首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

Yii Framework 教程 (25):Query Builder 實戰範例 - 程式化構建複雜 SQL 查詢

     編輯:PHP 綜合知識

Query Builder 優勢

  • 動態構建複雜查詢 (條件可選、JOIN 可選、排序可選)。
  • 自動引用表/欄位名 (雙引號/反引號),跨資料庫相容。
  • 自動參數綁定,防 SQL 注入。
  • 提供資料庫抽象層,便於切換資料庫類型。

範例場景:多表關聯查詢

Chinook 資料庫:查詢 EmployeeId=4 負責的所有客戶聯繫資訊。

對應 SQL:


SELECT c.FirstName, c.LastName, c.Address, c.Email
FROM Customer c
INNER JOIN Employee e ON c.SupportRepId = e.EmployeeId
WHERE e.EmployeeId = 4

Query Builder 實作


public function actionIndex() {
    $model = [];
    $connection = Yii::app()->db;
    
    // 流式介面構建查詢
    $command = $connection->createCommand()
        ->select('c.FirstName, c.LastName, c.Address, c.Email')
        ->from('Customer c')
        ->join('Employee e', 'c.SupportRepId = e.EmployeeId')
        ->where('e.EmployeeId = :eid', [':eid' => 4]);
    
    // 執行查詢
    $dataReader = $command->query();
    
    // 映射至模型
    foreach ($dataReader as $row) {
        $customer = new DataModel();
        $customer->firstName = $row['FirstName'];
        $customer->lastName = $row['LastName'];
        $customer->address = $row['Address'];
        $customer->email = $row['Email'];
        $model[] = $customer;
    }
    
    $this->render('index', ['model' => $model]);
}

Query Builder 核心方法完整列表

方法說明範例
select($columns)SELECT 欄位,支援陣列、字串、別名select(['id', 'name AS n'])
selectDistinct($columns)SELECT DISTINCTselectDistinct('category')
from($tables)FROM 表,支援別名、子查詢from('User u')
where($conditions, $params)WHERE 條件,支援字串、陣列、運算子where(['status'=>1, 'type'=>'post'])
andWhere / orWhere追加 AND/OR 條件andWhere('age>18')
join($table, $condition, $params)INNER JOINjoin('Profile p', 'p.user_id=user.id')
leftJoin / rightJoin / crossJoin / naturalJoin其他 JOIN 類型leftJoin('Post p', 'p.author_id=user.id')
group($columns)GROUP BYgroup('category_id')
having($conditions, $params)HAVINGhaving('COUNT(*) > 5')
order($columns)ORDER BYorder('create_time DESC')
limit($limit)LIMITlimit(10)
offset($offset)OFFSEToffset(20)
union($sql)UNION 合併查詢union($otherCommand)

進階用法

1. 動態條件構建


$command = $connection->createCommand()->from('Post');
if ($keyword) $command->andWhere(['like', 'title', $keyword]);
if ($category) $command->andWhere(['category_id' => $category]);
if ($dateFrom) $command->andWhere(['>=', 'create_time', $dateFrom]);
if ($dateTo) $command->andWhere(['<=', 'create_time', $dateTo]);
$posts = $command->queryAll();

2. 子查詢


$subQuery = $connection->createCommand()
    ->select('author_id')
    ->from('Post')
    ->where('status=1')
    ->group('author_id')
    ->having('COUNT(*) > 5');

$command = $connection->createCommand()
    ->select('*')
    ->from('User')
    ->where(['in', 'id', $subQuery]);

3. 批次插入/更新


// 批次 INSERT
$command = $connection->createCommand();
$command->batchInsert('Log', ['level', 'message', 'time'], [
    ['error', 'Disk full', time()],
    ['warning', 'High memory', time()],
    ['info', 'Backup done', time()],
])->execute();

// 批次 UPDATE (Yii 1.1 需自行迴圈或用 DAO)

4. 取得原生 SQL (除錯用)


$sql = $command->getText(); // 含參數佔位符
$params = $command->params; // 參數陣列
// 實際執行 SQL 可用 CDbConnection::getLastQuery() 或啟用 profiling

對比:DAO vs Query Builder vs ActiveRecord

場景推薦理由
簡單 CRUD、關聯導航ActiveRecord程式碼最少、可讀性最高、內建驗證
動態查詢條件、部分欄位、無模型Query Builder程式化構建、自動引用、防注入
複雜報表、批次操作、存儲過程、鎖表DAO完全控制 SQL、效能最高

常見錯誤與解決

  1. 欄位名稱保留字衝突:Query Builder 自動引用,但手寫 SQL 片段需自行加反引號 `column`。
  2. 參數陣列鍵名不匹配:命名參數 :name 需與 bindValues 鍵名一致 (含冒號)。
  3. JOIN 條件字串注入風險:join() 第二參數若為字串不自動參數化,建議用陣列 ['c.SupportRepId = e.EmployeeId'] 或確保可信來源。
  4. 忘記執行 query():createCommand() 只建構,必須呼叫 queryAll()/queryRow()/query()/execute() 才會發送 SQL。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved