1. Yii2 的复杂条件 SQL 语句一共有哪些?
(1) 常见的复杂条件
-
AND
和OR
条件:- 使用
andWhere()
和orWhere()
方法动态组合条件。
- 使用
-
嵌套条件:
- 使用数组或闭包构建嵌套的
AND
和OR
条件。
- 使用数组或闭包构建嵌套的
-
IN
和NOT IN
条件:- 使用
in()
和notIn()
方法处理范围查询。
- 使用
-
LIKE
和ILIKE
条件:- 使用
like()
和ilike()
方法处理模糊查询。
- 使用
-
比较条件:
- 使用
>
、<
、>=
、<=
等操作符进行比较。
- 使用
-
BETWEEN
条件:- 使用
between()
方法处理区间查询。
- 使用
-
EXISTS
子查询:- 使用子查询判断记录是否存在。
-
联表查询:
- 使用
join()
、innerJoin()
、leftJoin()
等方法执行联表操作。
- 使用
2. 使用场景
(1) 动态查询
- 示例:
$query = (new Query()) ->from('user') ->where(['status' => 1]) ->andWhere(['age' => 30]);
- 场景:
- 根据用户输入或其他动态条件构建查询。
(2) 复杂业务逻辑
- 示例:
$query = (new Query()) ->from('user') ->where(['or', ['status' => 1], ['age' => 30]]);
- 场景:
- 需要处理复杂的条件组合(如
AND
和OR
混合)。
- 需要处理复杂的条件组合(如
(3) 范围查询
- 示例:
$query = (new Query()) ->from('user') ->where(['in', 'id', [1, 2, 3]]);
- 场景:
- 查询满足特定范围的数据。
(4) 模糊查询
- 示例:
$query = (new Query()) ->from('user') ->where(['like', 'name', 'John']);
- 场景:
- 搜索包含特定关键字的记录。
(5) 区间查询
- 示例:
$query = (new Query()) ->from('user') ->where(['between', 'age', 20, 30]);
- 场景:
- 查询满足某个区间的记录。
(6) 子查询
- 示例:
$subQuery = (new Query())->select('id')->from('post'); $query = (new Query()) ->from('user') ->where(['exists', $subQuery]);
- 场景:
- 判断记录是否存在于另一个表中。
(7) 联表查询
- 示例:
$query = (new Query()) ->from('user') ->innerJoin('profile', 'user.id = profile.user_id');
- 场景:
- 查询多个表之间的关联数据。
3. 底层原理
(1) 数据存储
- 数据库表:
- 查询的目标数据通常存储在数据库中。
(2) 程序流
当构建复杂条件的 SQL 语句时,系统会执行以下步骤:
-
解析条件:
- 将传入的条件解析为 SQL 表达式。
-
合并条件:
- 将新条件与现有条件合并(通过
AND
或OR
连接)。
- 将新条件与现有条件合并(通过
-
生成 SQL:
- 将所有条件转换为最终的 SQL 查询语句。
-
执行查询:
- 调用底层的数据库驱动执行查询。
-
返回结果:
- 返回查询结果。
(3) 数据流
-
写入数据:
- 查询条件被动态构建并传递给数据库。
-
读取数据:
- 数据库返回查询结果,供调用者使用。
4. 示例代码及详细注释
以下是一个完整的示例,展示如何使用 Yii2 构建复杂条件的 SQL 查询,并附上详细注释。
<?php
namespace app\controllers;
use yii\web\Controller;
use yii\db\Query;
class UserController extends Controller
{
public function actionIndex()
{
// 创建 Query 对象
// 作用:初始化一个查询对象,用于构建 SQL 查询。
// 原因:Query 类提供了一种链式调用的方式,便于动态构建查询。
// 知识点:Yii2 的 Query 类,用于构建数据库查询。
$query = new Query();
// 指定查询的表
// 作用:定义查询的目标表(如 user 表)。
// 原因:明确查询的数据来源。
// 知识点:Query 类的 from() 方法,用于指定查询表。
$query->from('user');
// 添加初始条件
// 作用:筛选状态为 1 的用户。
// 原因:确保查询结果符合业务需求。
// 知识点:Query 类的 where() 方法,用于添加查询条件。
$query->where(['status' => 1]);
// 动态添加 AND 条件
// 作用:进一步筛选年龄为 30 的用户。
// 原因:支持动态构建复杂的查询条件。
// 知识点:Query 类的 andWhere() 方法,用于动态添加 AND 条件。
$query->andWhere(['age' => 30]);
// 动态添加 OR 条件
// 作用:筛选状态为 2 的用户(或条件)。
// 原因:支持复杂的条件组合。
// 知识点:Query 类的 orWhere() 方法,用于动态添加 OR 条件。
$query->orWhere(['status' => 2]);
// 添加范围查询
// 作用:筛选 ID 在 [1, 2, 3] 范围内的用户。
// 原因:支持范围查询。
// 知识点:Query 类的 in() 方法,用于处理范围查询。
$query->andWhere(['in', 'id', [1, 2, 3]]);
// 添加模糊查询
// 作用:筛选名字包含 "John" 的用户。
// 原因:支持模糊匹配。
// 知识点:Query 类的 like() 方法,用于处理模糊查询。
$query->andWhere(['like', 'name', 'John']);
// 添加区间查询
// 作用:筛选年龄在 20 到 30 之间的用户。
// 原因:支持区间查询。
// 知识点:Query 类的 between() 方法,用于处理区间查询。
$query->andWhere(['between', 'age', 20, 30]);
// 添加子查询
// 作用:筛选存在对应记录的用户。
// 原因:支持子查询。
// 知识点:Query 类的 exists() 方法,用于处理子查询。
$subQuery = (new Query())->select('id')->from('post');
$query->andWhere(['exists', $subQuery]);
// 执行查询并获取结果
// 作用:从数据库中加载符合条件的记录。
// 原因:将查询结果返回给调用者。
// 知识点:Query 类的 all() 方法,用于返回所有记录。
$users = $query->all();
// 渲染视图并传递数据
// 作用:将查询结果传递给视图文件,用于展示。
// 原因:视图负责展示数据,控制器负责准备数据。
// 知识点:Yii2 的 render() 方法,用于渲染视图文件。
return $this->render('index', [
'users' => $users,
]);
}
}
5. 注意事项
(1) 条件顺序
- 确保
andWhere()
和orWhere()
的调用顺序正确,避免逻辑错误。
(2) 参数绑定
- 如果条件中包含用户输入,建议使用参数绑定防止 SQL 注入。
(3) 性能优化
- 如果查询涉及大量数据,建议对查询进行分页或缓存。
6. 程序流和数据流
(1) 程序流
-
创建查询对象:
- 初始化
Query
对象。
- 初始化
-
添加初始条件:
- 使用
where()
方法添加初始条件。
- 使用
-
动态添加条件:
- 使用
andWhere()
、orWhere()
、in()
、like()
等方法动态添加复杂条件。
- 使用
-
生成 SQL:
- 将所有条件转换为最终的 SQL 查询语句。
-
执行查询:
- 调用底层的数据库驱动执行查询。
-
返回结果:
- 返回查询结果。
(2) 数据流
-
写入数据:
- 查询条件被动态构建并传递给数据库。
-
读取数据:
- 数据库返回查询结果,供调用者使用。
7. 总结
-
组成部分:
AND
和OR
条件。- 嵌套条件。
IN
和NOT IN
条件。LIKE
和ILIKE
条件。- 比较条件。
BETWEEN
条件。EXISTS
子查询。- 联表查询。
-
使用场景:
- 动态查询。
- 复杂业务逻辑。
- 范围查询。
- 模糊查询。
- 区间查询。
- 子查询。
- 联表查询。
-
底层原理:
- 数据存储在数据库中。
- 使用链式调用动态构建查询条件。
-
程序流和数据流:
- 写入数据:查询条件被动态构建并传递给数据库。
- 读取数据:数据库返回查询结果,供调用者使用。