Yii2文档–查询生成器

查询构建器建立在DAO(Database Access Objects)基础之上,可让你创建程序化的、DBMS无关的SQL语句。相比于原生的SQL语句,查询构建器可以帮你写出可读性更强的SQL相关的代码,并生成安全性更强的SQL语句。

查询生成器使用步骤:

  1. 创建一个yii\db\Query对象来代表一条SELECT SQL语句的不同子句(例如SELECT ,FROM).
  2. 执行yii\db\Query的一个查询方法(例如:all())从数据库当中检索数据.

典型代码样例:

$rows = (new \yii\db\Query())
    ->select(['id', 'email'])
    ->from('user')
    ->where(['last_name' => 'Smith'])
    ->limit(10)
    ->all();
  • select()
$query->select(['user_id' => 'user.id1', 'email']); //其中user.id1表示别名

如果在组建查询时没有调用select()方法,则默认选择*;

  • distinct()
$query->select('user_id')->distinct();  //去除重复行
  • where()
  1. 字符串格式,例如:'status=1'
  2. 哈希格式,例如: ['status' => 1, 'type' => 2]
  3. 操作符格式,例如:['like', 'name', 'test']

filterWhere()与where() 唯一的不同就在于,前者将忽略在条件当中的hash format的空值。所以如果 $email 为空而 $username 不为空,那么上面的代码最终将生产如下 SQL ...WHERE username=:username

  • orderBy()
$query->orderBy([
    'id' => SORT_ASC,
    'name' => SORT_DESC,
]);
  • groupBy()
// ... GROUP BY `id`, `status`
$query->groupBy(['id', 'status']);
  • having()
// ... HAVING `status` = 1
$query->having(['status' => 1]);
  • limit()和offset()
// ... LIMIT 10 OFFSET 20
$query->limit(10)->offset(20); //从第20条数据开始获取10条数据
  • join()
// ... LEFT JOIN `post` ON `post`.`user_id` = `user`.`id`
$query->join('LEFT JOIN', 'post', 'post.user_id = user.id');
  • union()
$query1 = (new \yii\db\Query())
    ->select("id, category_id AS type, name")
    ->from('post')
    ->limit(10);
$query2 = (new \yii\db\Query())
    ->select('id, type, name')
    ->from('user')
    ->limit(10);
$query1->union($query2);
  • 查询方法
  1. yii\db\Query::all(): 将返回一个由行组成的数组,每一行是一个由名称和值构成的关联数组(译者注:省略键的数组称为索引数组)。
  2. yii\db\Query::one(): 返回结果集的第一行。
  3. yii\db\Query::column(): 返回结果集的第一列。
  4. yii\db\Query::scalar(): 返回结果集的第一行第一列的标量值。
  5. yii\db\Query::exists(): 返回一个表示该查询是否包结果集的值。
  6. yii\db\Query::count(): 返回 COUNT 查询的结果。
  7. 其它集合查询方法: 包括 yii\db\Query::sum(), yii\db\Query::average(), yii\db\Query::max(), yii\db\Query::min() 等. $q 是一个必选参数, 既可以是一个字段名称,又可以是一个 DB 表达式。

当你调用 yii\db\Query 当中的一个查询方法的时候,实际上内在的运作机制如下:

  1. 在当前 yii\db\Query 的构造基础之上,调用 yii\db\QueryBuilder 来生成一条 SQL 语句;
  2. 利用生成的 SQL 语句创建一个 yii\db\Command 对象;
  3. 调用 yii\db\Command 的查询方法(例如,queryAll())来执行这条 SQL 语句,并检索数据。
$command = (new \yii\db\Query())
    ->select(['id', 'email'])
    ->from('user')
    ->where(['last_name' => 'Smith'])
    ->limit(10)
    ->createCommand();
// 打印 SQL 语句
echo $command->sql;
// 打印被绑定的参数
print_r($command->params);
// 返回查询结果的所有行
$rows = $command->queryAll();
  • 索引查询结果

当你在调用 yii\db\Query::all() 方法时,它将返回一个以连续的整型数值为索引的数组。 而有时候你可能希望使用一个特定的字段或者表达式的值来作为索引结果集数组。那么你可以在调用 yii\db\Query::all() 之前使用 yii\db\Query::indexBy() 方法来达到这个目的。 例如,

// 返回 [100 => ['id' => 100, 'username' => '...', ...], 101 => [...], 103 => [...], ...]
$query = (new \yii\db\Query())
    ->from('user')
    ->limit(10)
    ->indexBy('id')
    ->all()

如需使用表达式的值做为索引,那么只需要传递一个匿名函数给 yii\db\Query::indexBy() 方法即可:

$query = (new \yii\db\Query())
    ->from('user')
    ->indexBy(function ($row) {
        return $row['id'] . $row['username'];
    })->all();
  • 批处理查询

当需要处理大数据的时候,像 yii\db\Query::all() 这样的方法就不太合适了, 因为它们会把所有数据都读取到内存上。为了保持较低的内存需求, Yii 提供了一个 所谓的批处理查询的支持。批处理查询会利用数据游标 将数据以批为单位取出来。

批处理查询的用法如下:

use yii\db\Query;
$query = (new Query())
    ->from('user')
    ->orderBy('id');
foreach ($query->batch() as $users) {
    // $users 是一个包含100条或小于100条用户表数据的数组
}
// or if you want to iterate the row one by one
foreach ($query->each() as $user) {
    // $user 指代的是用户表当中的其中一行数据
}
}

yii\db\Query::batch() 和 yii\db\Query::each() 方法将会返回一个实现了Iterator 接口 yii\db\BatchQueryResult 的对象,可以用在 foreach 结构当中使用。在第一次迭代取数据的时候, 数据库会执行一次 SQL 查询,然后在剩下的迭代中,将直接从结果集中批量获取数据。默认情况下, 一批的大小为 100,也就意味着一批获取的数据是 100 行。你可以通过给 batch() 或者 each() 方法的第一个参数传值来改变每批行数的大小。

相对于 yii\db\Query::all() 方法,批处理查询每次只读取 100 行的数据到内存。 如果你在处理完这些数据后及时丢弃这些数据,那么批处理查询可以很好的帮助降低内存的占用率。

发表在 yii

留下评论