查询

查询基础知识

备注

CodeIgniter 不支持数据库、表格和列名称中的点(.)。

常规查询

要提交查询,请使用 query 函数:

<?php

$db = db_connect();
$db->query('YOUR QUERY HERE');

当运行“读取”类型查询时, query() 函数会返回一个可以用来 显示结果 的数据库结果**对象**。当运行“写入”类型查询时,它根据成功或失败简单地返回 true 或 false。检索数据时,你通常会将查询分配给自己的变量,如下所示:

<?php

$query = $db->query('YOUR QUERY HERE');

备注

如果使用 OCI8 驱动程序,SQL 语句不应以分号 (;) 结尾。PL/SQL 语句应以分号 (;) 结尾。

简化的查询

simpleQuery() 方法是 $db->query() 方法的简化版本。 它不会返回数据库结果集,也不会设置查询计时器或编译绑定数据或存储调试查询。它只是让你提交一个查询。大多数用户很少使用此功能。

它返回数据库驱动程序的 “execute” 函数返回的任何内容。对于写入类型的查询(如 INSERT、DELETE 或 UPDATE 语句),这通常在成功或失败时返回 true/false(这确实是应该使用它的地方),并在具有可获取结果的查询成功时返回资源/对象。

<?php

if ($db->simpleQuery('YOUR QUERY')) {
    echo 'Success!';
} else {
    echo 'Query failed!';
}

备注

例如,PostgreSQL 的 pg_exec() 函数总是在成功时返回资源,即使对于写入类型的查询也是如此。所以如果你正在查找布尔值,请记住这一点。

手动使用数据库前缀

$db->prefixTable()

如果你已经配置了数据库前缀,并希望在本机 SQL 查询(例如)中将其添加到表名前,那么可以使用以下代码:

<?php

$db->prefixTable('tablename'); // outputs prefix_tablename

$db->setPrefix()

如果由于任何原因你想以编程方式更改前缀,而不需要创建新的连接,则可以使用此方法:

<?php

$db->setPrefix('newprefix_');
$db->prefixTable('tablename'); // outputs newprefix_tablename

$db->getPrefix()

你可以使用此方法随时获取当前前缀:

<?php

$DBPrefix = $db->getPrefix();

保护标识符

$db->protectIdentifiers()

在许多数据库中,保护表格和字段名称(例如在 MySQL 中使用反引号)是可取的。查询构建器查询会自动受保护,但是如果你需要手动保护一个标识符,可以使用:

<?php

$db->protectIdentifiers('table_name');

重要

尽管查询构建器会尽最大努力适当引用你提供给它的任何字段和表格名称。请注意,它并不是设计用于任意用户输入。不要向它输入未经 sanitize 的用户数据。

如果在数据库配置文件中指定了前缀,此函数也会将**表前缀**添加到表格名,以启用前缀,请通过第二个参数设置 true (布尔值):

<?php

$db->protectIdentifiers('table_name', true);

转义值

在将数据提交到数据库之前对其进行转义是非常好的安全实践。CodeIgniter 提供了三种帮助你实现这一点的方法:

1. $db->escape()

此函数确定数据类型,以便它只能转义字符串数据。它还会自动在数据周围添加单引号,所以你不必这样做:

<?php

$sql = 'INSERT INTO table (title) VALUES(' . $db->escape($title) . ')';

2. $db->escapeString()

此函数转义传入的数据,而不考虑类型。大多数时间你会使用上面的函数而不是这个。像这样使用该函数:

<?php

$sql = "INSERT INTO table (title) VALUES('" . $db->escapeString($title) . "')";

3. $db->escapeLikeString()

当字符串将在 LIKE 条件中使用时,应使用此方法, 以便字符串中的 LIKE 通配符 (%_) 也适当转义。

<?php

$search = '20% raise';
$sql    = "SELECT id FROM table WHERE column LIKE '%" . $db->escapeLikeString($search) . "%' ESCAPE '!'";

重要

escapeLikeString() 方法使用 '!' (感叹号)来转义 LIKE 条件的特殊字符。因为此方法转义了你自己要用引号括起来的部分字符串,所以它无法自动为你添加 ESCAPE '!' 条件,因此你必须手动完成这一操作。

查询绑定

绑定使你可以通过让系统为你组装查询来简化查询语法。考虑以下示例:

<?php

$sql = 'SELECT * FROM some_table WHERE id = ? AND status = ? AND author = ?';
$db->query($sql, [3, 'live', 'Rick']);

查询中的问号自动替换为查询函数第二个参数数组中的值。

绑定也适用于数组,它将转换为 IN 集:

<?php

$sql = 'SELECT * FROM some_table WHERE id IN ? AND status = ? AND author = ?';
$db->query($sql, [[3, 6], 'live', 'Rick']);

生成的查询将是:

SELECT * FROM some_table WHERE id IN (3,6) AND status = 'live' AND author = 'Rick'

使用绑定的次要好处是值会自动转义,从而产生更安全的查询。 你不必记住手动转义数据 - 引擎会自动为你完成这一操作。

命名绑定

除了使用问号标记绑定值的位置外,你还可以命名绑定,允许传入值的键与查询中的占位符匹配:

<?php

$sql = 'SELECT * FROM some_table WHERE id = :id: AND status = :status: AND author = :name:';
$db->query($sql, [
    'id'     => 3,
    'status' => 'live',
    'name'   => 'Rick',
]);

备注

查询中的每个名称必须用冒号括起来。

处理错误

$db->error()

如果你需要获取最后发生的错误, error() 方法将返回包含代码和消息的数组。这是一个快速示例:

<?php

if (! $db->simpleQuery('SELECT `example_field` FROM `example_table`')) {
    $error = $db->error(); // Has keys 'code' and 'message'
}

预处理查询

大多数数据库引擎都支持某种形式的预编译语句,允许你预先准备一次查询,然后使用新的数据集多次运行该查询。这消除了 SQL 注入的可能性,因为数据采用不同于查询本身的格式传递给数据库。当需要多次运行相同的查询时,它也可以快得多。但是,对每个查询都这样做可能会大大降低性能,因为调用数据库的频率加倍。由于查询生成器和数据库连接已经为你处理了数据的转义,所以安全方面已经为你照顾好了。但是,有时候你需要通过运行预编译语句或预处理查询来优化查询。

准备查询

这可以通过 prepare() 方法轻松完成。它接受一个参数,该参数是一个返回查询对象的闭包。查询对象由任何“final”类型的查询自动生成,包括 insertupdatedeletereplaceget。通过使用查询构建器运行查询来实现这一点最简单。查询实际上不会运行,值也不重要,因为它们从未应用,而是充当占位符。这将返回一个 PreparedQuery 对象:

<?php

$pQuery = $db->prepare(static function ($db) {
    return $db->table('user')->insert([
        'name'    => 'x',
        'email'   => 'y',
        'country' => 'US',
    ]);
});

如果不想使用查询构建器,可以使用问号作为值占位符手动创建查询对象:

<?php

use CodeIgniter\Database\Query;

$pQuery = $db->prepare(static function ($db) {
    $sql = 'INSERT INTO user (name, email, country) VALUES (?, ?, ?)';

    return (new Query($db))->setQuery($sql);
});

如果数据库在预编译语句阶段需要一个选项数组传递给它,则可以在第二个参数中传递该数组:

<?php

use CodeIgniter\Database\Query;

$pQuery = $db->prepare(static function ($db) {
    $sql = 'INSERT INTO user (name, email, country) VALUES (?, ?, ?)';

    return (new Query($db))->setQuery($sql);
}, $options);

执行查询

一旦你有了预处理的查询,就可以使用 execute() 方法实际运行查询。你可以根据查询中的占位符数量传递任意多个变量。必须传入的参数数目必须与查询中的占位符数目匹配。它们还必须以在原始查询中出现的占位符的顺序传递:

<?php

// Prepare the Query
$pQuery = $db->prepare(static function ($db) {
    return $db->table('user')->insert([
        'name'    => 'x',
        'email'   => 'y',
        'country' => 'US',
    ]);
});

// Collect the Data
$name    = 'John Doe';
$email   = 'j.doe@example.com';
$country = 'US';

// Run the Query
$results = $pQuery->execute($name, $email, $country);

对于“写入”类型的查询,它返回 true 或 false,指示查询的成功或失败。对于“读取”类型的查询,它返回一个标准的 结果集

其他方法

除了这两个主要方法之外,预处理查询对象还有以下方法:

close()

虽然 PHP 在数据库关闭所有打开的语句方面做得很好,但是当不需要预处理语句时关闭它总是一个好主意:

<?php

if ($pQuery->close()) {
    echo 'Success!';
} else {
    echo 'Deallocation of prepared statements failed!';
}

备注

从 v4.3.0 开始, close() 方法在所有 DBMS 中释放预编译语句。以前,它们在 Postgre、SQLSRV 和 OCI8 中没有被释放。

getQueryString()

这将返回预处理查询的字符串。

hasError()

如果最后一个 execute() 调用产生任何错误,则返回布尔值 true/false。

getErrorCode()

getErrorMessage()

如果遇到任何错误,可以使用这些方法检索错误代码和字符串。

使用查询对象

在内部,所有查询都作为 CodeIgniter\Database\Query 的实例进行处理和存储。此类负责绑定参数,否则准备查询,并存储有关其查询的性能数据。

$db->getLastQuery()

当你只需要检索最后一个查询对象时,使用 getLastQuery() 方法:

<?php

$query = $db->getLastQuery();
echo (string) $query;

查询类

每个查询对象都存储与查询本身相关的几个信息片段。这在一定程度上由时间线功能使用,但也可供你使用。

getQuery()

在所有处理完成后返回最终查询。这是发送到数据库的确切查询:

<?php

$sql = $query->getQuery();

通过将查询对象转换为字符串,也可以检索相同的值:

<?php

$sql = (string) $query;

getOriginalQuery()

返回传入对象的原始 SQL。其中不会有任何绑定,也不会替换前缀等:

<?php

$sql = $query->getOriginalQuery();

hasError()

如果在执行此查询期间遇到错误,则此方法将返回 true:

<?php

if ($query->hasError()) {
    echo 'Code: ' . $query->getErrorCode();
    echo 'Error: ' . $query->getErrorMessage();
}

isWriteType()

如果查询被确定为写入类型查询(即 INSERT、UPDATE、DELETE 等),则返回 true:

<?php

if ($query->isWriteType()) {
    // ... do something
}

swapPrefix()

用另一个值替换 SQL 中的一个表前缀。第一个参数是要替换的原始前缀,第二个参数是要替换的值:

<?php

$sql = $query->swapPrefix('ci3_', 'ci4_');

getStartTime()

以秒(含微秒)为单位获取查询执行的时间:

<?php

$microtime = $query->getStartTime();

getDuration()

以秒(含微秒)为单位返回查询持续时间的浮点数:

<?php

$microtime = $query->getDuration();