嵌套集模型是管理树形结构数据的高效方案,在Yii2项目中处理分类、菜单等层级数据时经常用到,将原生SQL查询转换为Yii2适配的查询形式,能更好地利用框架的查询构建能力和缓存机制。

原生SQL查询与Yii2查询的差异
原生SQL查询直接操作数据库表,而Yii2的查询构建器提供了面向对象的查询方式,能自动处理参数绑定、表前缀等细节。以嵌套集模型的常用查询为例,原生SQL查询某个节点的所有子节点可能如下:
-- 查询左值大于2且右值小于10的所有节点,即某个父节点的子节点 SELECT * FROM category WHERE lft > 2 AND rgt < 10 ORDER BY lft ASC;
这段SQL直接操作category表,使用lft和rgt两个嵌套集核心字段筛选数据,在Yii2中可以通过Query构建器直接转换。
使用Query构建器转换SQL查询
Yii2的yiidbQuery类提供了和SQL语法对应的方法,能快速将原生SQL转换为框架查询对象,避免直接拼接SQL字符串带来的注入风险。
基础转换示例
将上面的子节点查询转换为Query构建器代码:
<?php
use yiidbQuery;
// 创建查询对象
$query = new Query();
// 对应SQL的SELECT * FROM category
$query->select('*')->from('category');
// 对应WHERE lft > 2 AND rgt < 10
$query->where(['>', 'lft', 2])->andWhere(['<', 'rgt', 10]);
// 对应ORDER BY lft ASC
$query->orderBy(['lft' => SORT_ASC]);
// 执行查询获取结果
$result = $query->all();
?>
这种方式转换后的查询会自动处理表前缀,如果category表配置了前缀,Query构建器会自动拼接,不需要手动修改表名。
处理复杂条件转换
如果原生SQL包含OR条件或者嵌套条件,可以使用andFilterWhere、orFilterWhere等方法转换,比如查询左值大于2或者右值小于5的节点:
<?php
$query = new Query();
$query->from('category')->select('*');
// 对应WHERE lft > 2 OR rgt < 5
$query->where(['>', 'lft', 2])->orWhere(['<', 'rgt', 5]);
$result = $query->all();
?>
结合ActiveRecord转换查询
如果使用嵌套集模型的ActiveRecord类,比如基于yii2-nested-sets扩展的模型类,转换查询会更简洁,还能直接使用模型自带的关联方法。
模型类基础转换
假设Category是嵌套集模型的ActiveRecord类,查询某个节点的子节点可以直接调用类方法:
<?php
use appmodelsCategory;
// 获取id为1的节点
$parentNode = Category::findOne(1);
if ($parentNode) {
// 调用嵌套集模型自带的获取子节点方法,内部已经封装了lft和rgt的查询逻辑
$children = $parentNode->children()->all();
}
?>
如果需要自定义条件,可以在ActiveRecord查询基础上追加条件,比如只获取状态为启用的子节点:
<?php
$parentNode = Category::findOne(1);
if ($parentNode) {
$children = $parentNode->children()
->where(['status' => 1]) // 追加状态筛选条件
->orderBy(['sort' => SORT_ASC]) // 追加排序条件
->all();
}
?>
转换过程中的注意事项
- 参数绑定:原生SQL如果使用变量拼接,转换时要使用参数绑定,避免SQL注入,比如原生SQL
WHERE id = $id要转换为where('id = :id', [':id' => $id])而不是where('id = ' . $id)。 - 字段转义:如果字段名是数据库关键字,比如
order,转换时要用引号包裹,Query构建器中可以通过quoteColumnName方法处理,或者直接写成['order' => SORT_ASC]让框架自动转义。 - 性能优化:转换后的查询如果数据量较大,可以添加缓存,比如
$query->cache(3600)缓存查询结果1小时,减少数据库查询次数。
常见场景转换对照表
| 原生SQL场景 | Yii2 Query构建器转换 | ActiveRecord转换 |
|---|---|---|
| SELECT * FROM category WHERE id IN (1,2,3) | where(['in', 'id', [1,2,3]]) | Category::find()->where(['in', 'id', [1,2,3]])->all() |
| SELECT name,lft FROM category LIMIT 10 | select(['name','lft'])->limit(10) | Category::find()->select(['name','lft'])->limit(10)->all() |
| SELECT * FROM category WHERE lft BETWEEN 2 AND 10 | where(['between', 'lft', 2, 10]) | Category::find()->where(['between', 'lft', 2, 10])->all() |
嵌套集模型的查询转换核心是先理解原生SQL的逻辑,再对应到Yii2查询构建器的方法,优先使用ActiveRecord自带的方法可以减少重复代码,提升开发效率。
Yii2嵌套集模型SQL查询转换ActiveRecord修改时间:2026-06-24 04:33:41