logo

额外区块类型 (EBT) - 全新的布局构建器体验❗

额外区块类型 (EBT) - 样式化、可定制的区块类型:幻灯片、标签页、卡片、手风琴等更多类型。内置背景、DOM Box、JavaScript 插件的设置。立即体验布局构建的未来。

演示 EBT 模块 下载 EBT 模块

❗额外段落类型 (EPT) - 全新的 Paragraphs 体验

额外段落类型 (EPT) - 类似的基于 Paragraph 的模块集合。

演示 EPT 模块 滚动

滚动
01/10/2025, by Ivan

动态查询是指由 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());