动态查询简介
动态查询是指由 Drupal 动态创建的查询,而不是以显式查询字符串的形式提供的查询。所有插入、更新、删除和合并查询都必须是动态的。选择查询既可以是静态的,也可以是动态的。因此,「动态查询」通常是指动态的 Select 查询。
注意:在 90% 的 select 查询用例中,你会使用静态查询。如果在性能关键路径上,应出于性能考虑使用 query() 而不是 select()。仅当查询的部分内容不同(例如:根据上下文动态添加 WHERE 条件),或者查询必须可被更改时,才应使用动态查询。
所有动态创建的查询都是通过从相应的数据库连接对象请求查询对象来生成的。与静态查询类似,在绝大多数情况下都可以使用过程式封装来生成查询对象。但后续的查询指令则以调用查询对象的方法的形式存在。
动态选择查询通过 select() 方法启动,如下所示:
$database = \Drupal::database();
$query = $database->select('mytable', 'mt', $options);
在这种情况下,mytable 是查询的基础表;即 FROM 子句后的第一张表。请注意,这里不需要加大括号,查询构建器会自动处理。第二个参数是表的别名。如果未指定,则默认使用表名。$options 数组是可选的,和静态查询中的 $options 数组相同。
$database->select() 的返回值是一个 Select 类型的对象。因此在调用之后,变量 $query 的值就是一个 Select 类型的对象。该对象包含完整的方法列表,比如 fields()、joins() 和 group(),可用于进一步定义查询。
动态选择查询可以非常简单,也可以非常复杂。下面我们将先介绍构成简单查询的各个部分,接着在后续部分介绍更复杂的方法,比如表连接。
整体概念
下面是一个相对简单的用户表查询。
假设我们要创建一个动态查询,大致等同于下面的静态查询:
$result = $database->query("SELECT uid, name, status, created, access FROM {users} u WHERE uid <> 0 LIMIT 50 OFFSET 0");
动态等价形式如下:
// 创建一个 Select 类型的对象。
$database = \Drupal::database();
$query = $database->select('users', 'u');
// 向查询对象添加条件、字段和范围。
$query->condition('u.uid', 0, '<>');
$query->fields('u', ['uid', 'name', 'status', 'created', 'access']);
$query->range(0, 50);
通常,这段代码会写成链式语法,将多个方法调用合并在一起。因此上面的代码通常写成:
// 创建一个 Select 类型的对象。
$query = $database->select('users', 'u');
// 向查询对象添加条件、字段和范围。
$query->condition('u.uid', 0, '<>')
->fields('u', ['uid', 'name', 'status', 'created', 'access'])
->range(0, 50);
事实上,代码还可以进一步简化,将 $database->select() 与方法调用直接链式连接。这将得到:
// 创建一个 Select 类型的对象,并直接向查询对象添加条件、字段和范围。
$query = $database->select('users', 'u')
->condition('u.uid', 0, '<>')
->fields('u', ['uid', 'name', 'status', 'created', 'access'])
->range(0, 50);
这是用户管理页面使用的简化查询形式,可以参考它进一步学习。
执行查询
一旦查询构建完成,调用 execute() 方法来编译并执行查询。
$result = $query->execute();
execute() 方法会返回一个结果集 / 语句对象,与 $database->query() 返回的对象相同,可以用相同的方式遍历或提取:
$result = $query->execute();
foreach ($result as $record) {
// 对每条 $record 执行操作。
}
注意:当在多列动态查询中使用以下方法时要小心:
这些方法目前要求使用列的数字索引(0、1、2 等),而不是表的别名。然而查询构建器并不保证返回字段的顺序,因此数据列可能不是你期望的顺序。尤其是表达式总是会在字段之后添加,即使你在查询中先添加了它们。(这个问题不适用于静态查询,静态查询总是按你指定的顺序返回字段。)
调试
要查看查询对象在某一时刻使用的 SQL 查询,可以打印查询对象。要检查参数,可以查看 arguments() 方法返回的数组:
echo $query; print_r($query->__toString()); print_r($query->arguments());