博客 / 詳情

返回

Phalcon查詢語言

Phalcon查詢語言(Phalcon Query Language)

Phalcon查詢語言,簡稱PhalconQL或PHQL,是一種面向對象的高級SQL語言,允許用標準化的SQL編寫。PHQL實現了把操作語句解析為RDBMS目標語言的解析器(C語言編寫)。

為了達到最佳性能,Phalcon提供了與SQLite相同的解析器,其線程安全,內存佔用極低。

解析器先檢查傳遞的PHQL語句的語法,然後構建中間語句,最後將其轉換為RDBMS對應的SQL語句。

PHQL實現了一系列功能,可以更安全的操作數據庫。

  • 參數綁定是PHQL功能之一,使代碼更安全
  • PHQL每次只允許執行一條SQL語句,以防SQL注入
  • PHQL會忽略所有SQL注入中常用的SQL註釋
  • PHQL只允許數據操作語句,避免錯誤的或未經授權的更改、刪除數據庫和表
  • PHQL實現了高級抽象接口,允許以模型方式操作表,以類屬性方式操作表字段

使用示例(Usage Example)

為了更好的解釋PHQL工作原理,請參考下例。有CarsBrands兩個模型:

<?php

use Phalcon\Mvc\Model;

class Cars extends Model
{
    public $id;

    public $name;

    public $brand_id;

    public $price;

    public $year;

    public $style;

    // 模型Cars映射sample_cars表
    public function getSource()
    {
        return 'sample_cars';
    }

    // 一輛車屬於一個品牌,但一個品牌有多輛車
    public function initialize()
    {
        $this->belongsTo('brand_id', 'Brands', 'id');
    }
}

每輛車都屬於一個品牌,每個品牌有多輛車:

<?php

use Phalcon\Mvc\Model;

class Brands extends Model
{
    public $id;

    public $name;

    // 模型Brands映射表'sample_brands'
    public function getSource()
    {
        return 'sample_brands';
    }

    // 一個品牌有多輛車
    public function initialize()
    {
        $this->hasMany('id', 'Cars', 'brand_id');
    }
}

創建PHQL查詢(Creating PHQL Queries)

實例化Phalcon\Mvc\Model\Query類即可創建PHQL查詢:

<?php

use Phalcon\Mvc\Model\Query;

// 實例化Query
$query = new Query(
    "SELECT * FROM Cars",
    $this->getDI()
);

// 執行查詢,返回結果(如果有的話)
$cars = $query->execute();

控制器或視圖中,使用Phalcon\Mvc\Model\Manager可以很容易的創建、執行PHQL查詢:

<?php

// 執行簡單查詢
$query = $this->modelsManager->createQuery("SELECT * FROM Cars");
$cars  = $query->execute();

// 使用參數綁定
$query = $this->modelsManager->createQuery("SELECT * FROM Cars WHERE name = :name:");
$cars  = $query->execute(
    [
        'name' => 'Audi',
    ]
);

或者直接執行查詢:

<?php

// 執行簡單查詢
$cars = $this->modelsManager->executeQuery(
    "SELECT * FROM Cars"
);

// 使用參數綁定
$cars = $this->modelsManager->executeQuery(
    "SELECT * FROM Cars WHERE name = :name:",
    [
        'name' => 'Audi',
    ]
);

查詢記錄(Selecting Records)

PHQL允許使用我們熟知的SELECT語句查詢記錄,使用模型名字代替表名:

<?php

$query = $manager->createQuery(
    "SELECT * FROM Cars ORDER BY Cars.name"
);

$query = $manager->createQuery(
    "SELECT Cars.name FROM Cars ORDER BY Cars.name"
);

允許帶命名空間的模型名:

<?php

$phql  = "SELECT * FROM Formula\Cars ORDER BY Formula\Cars.name";
$query = $manager->createQuery($phql);

$phql  = "SELECT Formula\Cars.name FROM Formula\Cars ORDER BY Formula\Cars.name";
$query = $manager->createQuery($phql);

$phql  = "SELECT c.name FROM Formula\Cars c ORDER BY c.name";
$query = $manager->createQuery($phql);

PHQL支持大部分標準SQL語法,非標準的SQL語法也同樣支持,如LIMIT:

<?php

$phql = "SELECT c.name FROM Cars AS c WHERE c.brand_id = 21 ORDER BY c.name LIMIT 100";

$query = $manager->createQuery($phql);

結果集類型(Result Types)

結果集類型根據我們查詢字段的不同而不同,如果檢索單個完整對象,則返回Phalcon\Mvc\Model\Resultset\Simple對象。這種結果集是一組完整的模型對象:

<?php

$phql = "SELECT c.* FROM Cars AS c ORDER BY c.name";

$cars = $manager->executeQuery($phql);

foreach ($cars as $car) {
    echo 'Name: ', $car->name, "\n";
}

下面這種方式也一樣:

<?php

$cars = Cars::find(
    [
        'order' => 'name',
    ]
);

foreach ($cars as $car) {
    echo 'Name: ', $car->name, "\n";
}

完整模型對象中的數據能夠被修改,並重新保存到數據庫中,因為它們代表關聯表的完整記錄。下面這種查詢方式不會返回完整模型對象:

<?php

$phql = "SELECT c.id, c.name FROM Cars AS c ORDER BY c.name";

$cars = $manager->executeQuery($phql);

foreach ($cars as $car) {
    echo 'Name: ', $car->name, "\n";
}

我們僅僅查詢了表中的某些字段,雖然返回的結果集仍然是Phalcon\Mvc\Model\Resultset\Simple對象,但不能當成完整模型對象。該對象的每個成員都是一個包含所查詢字段的標準對象。

這些不表示完整對象的值就是我們所説的標量,PHQL允許查詢所有類型的標量:字段,函數,字面兩,表達式等:

<?php

$phql = "SELECT CONCAT(c.id, ' ', c.name) AS id_name FROM Cars AS c ORDER BY c.name";

$cars = $manager->execute($phql);

foreach ($cars as $car) {
    echo $car->id_name, "\n";
}

我們可以查詢完整對象或標量,也可以同時查詢它們:

<?php

$phql = "SELECT c.price*0.16 AS taxes, c.* FROM Cars AS c ORDER BY c.name";

$result = $manager->executeQuery($phql);

這種情況下的結果集是一個Phalcon\Mvc\Model\Resultset\Complex對象,可以同時訪問完整對象和標量:

<?php

foreach ($result as $row) {
    echo 'Name: ', $row->cars->name, "\n";
    echo 'Price: ', $row->cars->price, "\n";
    echo 'Taxes: ', $row->taxes, "\n";
}

連接(Joins)

使用PHQL可以很容易的從多個模型請求記錄,支持大部分的JOIN方式。我們在模型中定義關係之後,PHQL會自動添加這些條件:

<?php

$phql = "SELECT Cars.name AS car_name, Brands.name AS brand_name FROM Cars JOIN Brands";

$rows = $manager->executeQuery($phql);

foreach ($rows as $row) {
    echo $row->car_name, "\n";
    echo $row->brand_name, "\n";
}

默認使用INNER JOIN,可以指定JOIN類型:

<?php

$phql = "SELECT Cars.*, Brands.* FROM Cars INNER JOIN Brands";
$rows = $manager->executeQuery($phql);

$phql = "SELECT Cars.*, Brands.* FROM Cars LEFT JOIN Brands";
$rows = $manager->executeQuery($phql);

$phql = "SELECT Cars.*, Brands.* FROM Cars LEFT OUTER JOIN Brands";
$rows = $manager->executeQuery($phql);

$phql = "SELECT Cars.*, Brands.* FROM Cars CROSS JOIN Brands";
$rows = $manager->executeQuery($phql);

也可以手動設置JOIN條件:

<?php

$phql = "SELECT Cars.*, Brands.* FROM Cars INNER JOIN Brands ON Brands.id = Cars.brands_id";

$rows = $manager->executeQuery($phql);

如果查詢中為模型定義別名,則將使用別名為結果集中的每一條記錄命名:

<?php

$phql = "SELECT c.*, b.* FROM Cars c, Brands b WHERE b.id = c.brands_id";

$rows = $manager->executeQuery($phql);

foreach ($rows as $row) {
    echo 'Car: ', $row->c->name, "\n";
    echo 'Brand: ', $row->b->name, "\n";
}

如果連接模型與from之後的模型具有多對多關係時,中間模型將隱式的添加到查詢中:

<?php

$phql = "SELECT Artists.name, Songs.name FROM Artists JOIN Songs WHERE Artists.genre = 'Trip-Hop'";

$result = $this->modelsManager->executeQuery($phql);

上述代碼在MySQL中執行下列SQL:

SELECT `artists`.`name`, `songs`.`name` FROM `artists`
INNER JOIN `albums` ON `albums`.`artists_id` = `artists`.`id`
INNER JOIN 'songs' ON `albums`.`songs_id` = `songs`.`id`
WHERE `artists`.`genre` = 'Trip-Hop'

聚合(Aggregations)

下面例子展示了PHQL中如何使用聚合:

<?php

// 所有汽車的總價值
$phql = "SELECT SUM(price) AS summatory FROM Cars";
$row  = $manager->executeQuery($phql)->getFirst();
echo $row['summatory'];

// 每個品牌下的汽車總數
$phql = "SELECT Cars.brand_id, COUNT(*) FROM Cars GROUP BY Cars.brand_id";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo $row->brand_id, ' ', $row['1'], "\n";
}

// 每個品牌下的汽車總數
$phql = "SELECT Brands.name, COUNT(*) FROM Cars JOIN Brands GROUP BY 1";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo $row->name, ' ', $row['1'], "\n";
}

$phql = "SELECT MAX(price) AS maximum, MIN(price) AS minimum FROM Cars";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo $row['maximum'], ' ', $row['minimum'], "\n";
}

// 統計品牌數量
$phql = "SELECT COUNT(DISTINCT brand_id) AS brandId FROM Cars";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo $row->brandId, "\n";
}

條件(Conditions)

條件能讓我們過濾想要查詢的記錄,WHERE子句允許這樣:

<?php

// 簡單條件
$phql = "SELECT * FROM Cars WHERE Cars.name = 'Lamborghini Espada'";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.price > 10000";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE TRIM(Cars.name) = 'Audi R8'";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.name LIKE 'Ferrari%'";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.name NOT LIKE 'Ferrari%'";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.price IS NULL";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.id IN (120, 121, 122)";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.id NOT IN(430, 431)";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.id BETWEEN 1 AND 100";
$cars = $manager->executeQuery($phql);

此外,作為PHQL的一部分,參數綁定會自動轉義輸入數據,安全性更高:

<?php

$phql = "SELECT * FROM Cars WHERE Cars.name = :name:";
$cars = $manager->executeQuery(
    $phql,
    [
        'name' => 'Lamborghini Espada',
    ]
);

$phql = "SELECT * FROM Cars WHERE Cars.name = ?0";
$cars = $manager->executeQuery(
    $phql,
    [
        0 => 'Lamborghini Espada',
    ]
);

插入數據(Inserting Data)

通過PHQL,可以使用我們非常熟悉的INSERT語句插入數據:

<?php

// 插入數據,不指定字段
$phql = "INSERT INTO Cars VALUES (NULL, 'Lamborghini Espada', 7, 10000.00, 1969, 'Grand Tourer')";
$manager->executeQuery($phql);

// 插入數據,指定字段
$phql = "INSERT INTO Cars (name, brand_id, year, style) VALUES ('Lamborghini Espada', 7, 1969, 'Grand Tourer')";
$manager->executeQuery($phql);

// 插入數據,使用佔位符
$phql = "INSERT INTO Cars (name, brand_id, year, style) VALUES (:name:, :brand_id:, :year:, :style:)";
$manager->executeQuery(
    $phql,
    [
        'name'     => 'Lamborghini Espada',
        'brand_id' => 7,
        'year'     => 1969,
        'style'    => 'Grand Tourer',
    ]
);

Phalcon不只是單純的將PHQL語句轉化成SQL,模型中定義的所有事件和業務規則都會執行,就像我們手動創建對象那樣。我們為模型Cars創建一條規則,車的價格不能低於$ 10,000:

<?php

use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Message;

class Cars extends Model
{
    public function beforeCreate()
    {
        if ($this->price < 10000) {
            $this->appendMessage(
                new Message('A car cannot cost less than $ 10,000')
            );

            return false;
        }
    }
}

如果我們在模型Cars中執行下面的INSERT語句,操作將會失敗,因為price不滿足我們制定的規則。通過檢查插入狀態,我們可以打印任何內部生成的驗證消息:

<?php

$phql = "INSERT INTO Cars VALUES (NULL, 'Nissan Versa', 7, 9999.00, 2015, 'Sedan')";

$result = $manager->executeQuery($phql);

if ($result->success() === false) {
    foreach ($result->getMessages() as $message) {
        echo $message->getMessage();
    }
}

更新數據(Updating Data)

更新記錄與插入記錄非常相似,更新記錄使用UPDATE命令。更新記錄時,將為每條記錄執行與更新操作相關的事件。

<?php

// 更新一個字段
$phql = "UPDATE Cars SET price = 15000.00 WHERE id = 101";
$manager->executeQuery($phql);

// 更新多個字段
$phql = "UPDATE Cars SET price = 15000.00, type = 'Sedan' WHERE id = 101";
$manager->executeQuery($phql);

// 更新多條記錄
$phql = "UPDATE Cars SET price = 7000.00, type = 'Sedan' WHERE brands_id > 5";
$manager->executeQuery($phql);

// 使用佔位符
$phql = "UPDATE Cars SET price = ?0, type = ?1 WHERE brands_id > ?2";
$manager->executeQuery(
    $phql,
    [
        0 => 7000.00,
        1 => 'Sedan',
        2 => 5,
    ]
);

UPDATE語句執行更新分兩步進行:

  • 首先,如果UPDATE包含WHERE子句,將檢索符合條件的所有對象
  • 其次,基於查詢對象更新字段並保存

這種操作方式允許事件、虛擬外鍵和驗證參與更新過程。

<?php

$phql = "UPDATE Cars SET price = 15000.00 WHERE id > 101";

$result = $manager->executeQuery($phql);

if ($result->success() === false) {
    $messages = $result->getMessages();

    foreach ($messages as $message) {
        echo $message->getMessage();
    }
}

上面代碼相當於:

<?php

$messages = null;

$process = function () use (&$messages) {
    $cars = Cars::find('id > 101');

    foreach ($cars as $car) {
        $car->price = 15000;

        if ($car->save() === false) {
            $messages = $car->getMessages();

            return false;
        }
    }

    return true;
};

$success = $process();

刪除數據(Deleting Data)

刪除記錄時,與刪除操作相關的事件將逐一執行:

<?php

// 刪除一條記錄
$phql = "DELETE FROM Cars WHERE id = 101";
$manager->executeQuery($phql);

// 刪除多條記錄
$phql = "DELETE FROM Cars WHERE id > 100";
$manager->executeQuery($phql);

// 使用佔位符
$phql = "DELETE FROM Cars WHERE id BETWEEN :initial: AND :final:";
$manager->executeQuery(
    $phql,
    [
        'initial' => 1,
        'final'   => 100,
    ]
);

UPDATE一樣,DELETE操作也分兩步執行,要檢查刪除操作是否產生驗證消息,你可以檢查返回的狀態:

<?php

// 刪除多條記錄
$phql = "DELETE FROM Cars WHERE id > 100";

$result = $manager->executeQuery($phql);

if ($result->success() === false) {
    $messages = $result->getMessages();

    foreach ($messages as $message) {
        echo $message->getMessage();
    }
}

使用查詢構造器創建查詢(Creating queries using the Query Builder)

查詢構造器可用於創建PHQL查詢,無需編寫PHQL語句:

<?php

// 獲取所有記錄
$robots = $this->modelsManager->createBuilder()
    ->from('Robots')
    ->join('RobotsParts')
    ->orderBy('Robots.name')
    ->getQuery()
    ->execute();

// 獲取第一條記錄
$robots = $this->modelsManager->createBuilder()
    ->from('Robots')
    ->join('RobotsParts')
    ->orderBy('Robots.name')
    ->getQuery()
    ->getSingleResult();

同下列操作:

<?php

$phql = "SELECT Robots.* FROM Robots JOIN RobotsParts p ORDER BY Robots.name LIMIT 20";

$result = $manager->executeQuery($phql);

查詢構造器更多示例:

<?php

// "SELECT Robots.* FROM Robots";
$builder->from('Robots');

// "SELECT Robots.*, RobotsParts.* FROM Robots, RobotsParts";
$builder->from(
    [
        'Robots',
        'RobotsParts',
    ]
);

// "SELECT * FROM Robots";
$phql = $builder->columns('*')
    ->from('Robots');

// "SELECT id FROM Robots";
$builder->columns('id')
    ->from('Robots');

// "SELECT id, name FROM Robots";
$builder->columns(['id', 'name'])
    ->from('Robots');

// "SELECT Robots.* FROM Robots WHERE Robots.name = 'Voltron'";
$builder->from('Robots')
    ->where('Robots.name = "Voltron"');

// "SELECT Robots.* FROM Robots WHERE Robots.id = 100";
$builder->from('Robots')
    ->where(100);

// "SELECT Robots.* FROM Robots WHERE Robots.type = 'virtual' AND Robots.id > 50";
$builder->from('Robots')
    ->where('type = "virtual"')
    ->andWhere('id > 50');

// "SELECT Robots.* FROM Robots WHERE Robots.type = 'virtual' OR Robots.id > 50";
$builder->from('Robots')
    ->where('type = "virtual"')
    ->orWhere('id > 50');

// "SELECT Robots.* FROM Robots GROUP BY Robots.name";
$builder->from('Robots')
    ->groupBy('Robots.name');

// "SELECT Robots.* FROM Robots GROUP BY Robots.name, Robots.id";
$builder->from('Robots')
    ->groupBy(['Robots.name', 'Robots.id']);

// "SELECT Robots.name SUM(Robots.price) FROM Robots GROUP BY Robots.name";
$builder->columns(['Robots.name', 'SUM(Robots.price)'])
    ->from('Robots')
    ->groupBy('Robots.name');

// "SELECT Robots.name, SUM(Robots.price) FROM Robots GROUP BY Robots.name HAVING SUM(Robots.price) > 1000";
$builder->columns(['Robots.name', 'SUM(Robots.price)'])
    ->from('Robots')
    ->groupBy('Robots.name')
    ->having('SUM(Robots.price) > 1000');

// "SELECT Robots.* FROM Robots JOIN RobotsParts";
$builder->from('Robots')
    ->join('RobotsParts');

// "SELECT Robots.* FROM Robots JOIN RobotsParts AS p";
$builder->from('Robots')
    ->join('RobotsParts', null, 'p');

// "SELECT Robots.* FROM Robots JOIN RobotsParts ON Robots.id = RobotsParts.robots_id AS p";
$builder->from('Robots')
    ->join('RobotsParts', 'Robots.id = RobotsParts.robots_id', 'p');

// "SELECT Robots.* FROM robots JOIN RobotsParts ON Robots.id = RobotsParts.robots_id AS p JOIN Parts ON Parts.id = RobotsParts.parts_id AS t";
$builder->from('Robots')
    ->join('RobotsParts', 'Robots.id = RobotsParts.robots_id', 'p')
    ->join('RobotsParts', 'Parts.id = RobotsParts.parts_id', 't');

// "SELECT r.* FROM Robots AS r";
$builder->addFrom('Robots', 'r');

// "SELECT Robots.*, p.* FROM Robots, Parts AS p";
$builder->from('Robots')
    ->addFrom('Parts', 'p');

// "SELECT r.*, p.* FROM Robots AS r, Parts AS p";
$builder->from(['r' => 'Robots'])
    ->addFrom('Parts', 'p');

// "SELECT r.*, p.* FROM Robots AS r, Parts AS p";
$builder->from(['r' => 'Robots', 'p' => 'Parts']);

// "SELECT Robots.* FROM Robots LIMIT 10";
$builder->from('Robots')
    ->limit(10);

// "SELECT Robots.* FROM Robots LIMIT 10 OFFSET 5";
$builder->from('Robots')
    ->limit(10, 5);

// "SELECT Robots.* FROM Robots WHERE id BETWEEN 1 AND 100";
$builder->from('Robots')
    ->betweenWhere('id', 1, 10);

// "SELECT Robots.* FROM Robots WHERE id IN (1, 2, 3)";
$builder->from('Robots')
    ->inWhere('id', [1, 2, 3]);

// "SELECT Robots.* FROM Robots WHERE id NOT IN (1, 2, 3)";
$builder->from('Robots')
    ->notInWhere('id', [1, 2, 3]);

// "SELECT Robots.* FROM Robots WHERE name LIKE '%Art%'";
$builder->from('Robots')
    ->where('name LIKE :name:', ['name' => '%' . $name . '%']);

// "SELECT r.* FROM Store\Robots WHERE r.name LIKE '%Art%'";
$builder->from(['r' => 'Store\Robots'])
    ->where('r.name LIKE :name:', ['name' => '%' . $name . '%']);

參數綁定(Bound Parameters)

查詢構造器中的參數綁定可以在查詢構建時設置,也可以在查詢執行時設置:

<?php

// 構建查詢時傳遞參數
$robots = $this->modelsManager->createBuilder()
    ->from('Robots')
    ->where('name = :name:', ['name' => $name])
    ->andWhere('type = :type:', ['type' => $type])
    ->getQuery()
    ->execute();

// 執行查詢時傳遞參數
$robots = $this->modelsManager->createBuilder()
    ->from('Robots')
    ->where('name = :name:')
    ->andWhere('type = :type:')
    ->getQuery()
    ->execute(['name' => $name, 'type' => $type]);

禁用字面量(Disallow literals in PHQL)

PHQL中可以禁用字面量,這意味着如果禁用開啓,則不能在PHQL語句中直接使用PHP字符串、數字和布爾值。如果在PHQL語句中嵌入外部數據,可能導致潛在的注入攻擊:

<?php

$login  = 'voltron';
$phql   = "SELECT * FROM Models\Users WHERE login = '{$login}'";
$result = $manager->executeQuery($phql);

如果$login的值為' OR ' ' = ' ,將產生如下PHQL語句:

SELECT * FROM Models\Users WHERE login = '' OR '' = '';

無論存儲在數據庫中的login是何值,條件總是true

如果字面量被禁用,在PHQL中使用PHP字面量會拋出異常,以強制開發者使用參數綁定。上面的查詢這樣寫更安全:

<?php

$type   = 'virtual';
$phql   = "SELECT Robots.* FROM Robots WHERE Robots.type = :type:";
$result = $manager->executeQuery(
    $phql,
    [
        'type' => $type,
    ]
);

可以通過以下方式禁用字面量:

<?php

use Phalcon\Mvc\Model;

Model::setup(
    ['phqlLiterals' => false]
);

無論字面量是否禁用,參數綁定都可以正常使用。禁用只是開發人員能夠在web應用中採取的一項安全策略。

轉義保留字(Escaping Reserved Words)

PHQL有一些保留字,如果想將保留字作為模型名或字段名使用,則需要使用轉義分隔符[]來轉義關鍵字:

<?php

$phql   = "SELECT * FROM [Update]";
$result = $manager->executeQuery($phql);

$phql   = "SELECT id, [Like] FROM Posts";
$result = $manager->executeQuery($phql);

PHQL生命週期(PHQL Lifecycle)

作為高級語言,PHQL賦予了開發者個性化定製的能力,以滿足不同的需求。以下是PHQL語句的生命週期:

  • PHQL被解析並轉換為獨立於數據庫SQL之外的中間表示(IR)
  • 根據模型對應的數據庫系統,IR被轉換為有效的SQL
  • PHQL語句被解析並保存在內存中,再次執行相同語句時速度會更快

使用原生SQL(Using Raw SQL)

某些數據庫系統可能會提供PHQL不支持的特殊SQL擴展,這種情況適合使用原生SQL:

<?php

use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset\Simple as Resultset;

class Robots extends Model
{
    public static function findByCreateInterval()
    {
        // 原生SQL
        $sql = "SELECT * FROM robots WHERE id > 0";

        // 模型
        $robot = new Robots();

        // 執行查詢
        return new Resultset(
            null,
            $robot,
            $robot->getReadConnection()->query($sql)
        );
    }
}

如果原生SQL查詢在應用中很普遍,可以在模型中添加通用方法:

<?php

use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset\Simple as Resultset;

class Robots extends Model
{
    public static function findByRawSql($conditions, $params = null)
    {
        // 原生SQL
        $sql = "SELECT * FROM robots WHERE {$conditions}";

        // 模型
        $robot = new Robots();

        // 執行查詢
        return new Resultset(
            null,
            $robot,
            $robot->getReadConnection()->query($sql),
        );
    }
}

上述findByRawSQL可以如下使用:

<?php

$robots = Robots::findByRawSql(
    'id > ?',
    [
        10,
    ]
);

注意事項(Troubleshooting)

PHQL中的一些注意事項:

  • 類名稱區分大小寫,如果定義類時名稱和創建時的名稱不一致,在大小寫敏感的操作系統(如linux)中將導致不可預知行為
  • 為保證參數綁定成功,連接數據庫時必須指定正確的字符集
  • 指定別名的類不能用完整命名空間替換,因為這項操作發生在PHP代碼中,而非PHQL語句裏
  • 如果字段使用別名,應避免別名和字段名相同,不然查詢解析器容易混淆。
user avatar konstantinos-kouratoras 頭像 xiaoxiaocong_58ab02b3e5d1e 頭像 zuiyuesi 頭像 admim 頭像 andy-croxall 頭像 lofanmi 頭像
6 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.