如何在Yii2模型中以Join形式编写指定MySQL关联查询
嘿,我来帮你搞定Yii2里的MySQL Join查询问题!下面分两部分说明:先讲通用的Join实现方法,再把你给出的原生SQL转换成Yii2模型中的标准写法。
在Yii2中编写Join查询的通用方法
Yii2的ActiveQuery提供了两种主流的Join实现方式,根据场景选择即可:
1. 手动指定Join条件(适合复杂自定义场景)
用innerJoin()、leftJoin()这类方法直接写关联逻辑,和原生SQL思路完全一致:
// 示例:从User模型关联Order表 $query = User::find() ->select(['user.id', 'user.name', 'order.order_no']) ->innerJoin('order', 'order.user_id = user.id');
2. 利用模型关联(推荐,符合ActiveRecord规范)
如果你的模型已经定义了hasOne/hasMany这类关联关系,用joinWith()可以自动处理Join条件,代码更简洁易维护:
// 假设User模型已定义getOrders()关联方法 $query = User::find() ->joinWith('orders') // 自动关联order表并应用预设条件 ->select(['user.*', 'order.order_no']);
针对你给出的SQL语句的转换方案
首先先明确模型与数据库表的对应关系(假设你已经创建了以下模型):
Student→students表StudentRegistration→student_registration表StudentPaperResult→student_paper_results表Paper→papers表
方式一:手动构建Inner Join(和原生SQL逻辑完全匹配)
直接把各个表的关联条件写进innerJoin(),和你原来的SQL逻辑一致:
use app\models\StudentPaperResult; $query = StudentPaperResult::find() ->select([ 'spr.id', 'spr.total_marks', 'spr.obtained_marks', 'p.paper_title', 'p.exam_id', 'p.subject_id', 'sr.reg_no', 'sr.student_id', 's.student_name' ]) ->alias('spr') // 给主表起别名,和原生SQL一致 ->innerJoin('students s', 's.id = spr.student_id') ->innerJoin('student_registration sr', 's.id = sr.student_id') ->innerJoin('papers p', 'p.id = spr.paper_id'); // 执行查询获取结果 $results = $query->all();
方式二:利用模型关联的joinWith(更推荐)
先给各个模型定义好关联关系:
- 在
StudentPaperResult模型中添加:
// 关联Student模型 public function getStudent() { return $this->hasOne(Student::class, ['id' => 'student_id']); } // 关联Paper模型 public function getPaper() { return $this->hasOne(Paper::class, ['id' => 'paper_id']); }
- 在
Student模型中添加:
// 关联StudentRegistration模型 public function getStudentRegistration() { return $this->hasOne(StudentRegistration::class, ['student_id' => 'id']); }
然后就可以用joinWith()优雅地构建查询:
use app\models\StudentPaperResult; $query = StudentPaperResult::find() ->select([ 'student_paper_results.id', 'student_paper_results.total_marks', 'student_paper_results.obtained_marks', 'papers.paper_title', 'papers.exam_id', 'papers.subject_id', 'student_registration.reg_no', 'student_registration.student_id', 'students.student_name' ]) // 链式关联:StudentPaperResult关联Student,Student再关联StudentRegistration,同时关联Paper ->joinWith(['student', 'student.studentRegistration', 'paper']); // 获取结果集 $results = $query->all();
额外提示
- 两种方式最终生成的SQL和你给出的原生SQL完全一致;
- 如果需要添加筛选条件,直接在查询链后追加
where()即可,比如:$query->where(['papers.exam_id' => 101]); // 筛选exam_id为101的结果 - 方式二更适合长期维护,后续修改关联逻辑只需要调整模型中的关联方法即可。
内容的提问来源于stack exchange,提问作者Sajid Mehmood
相关产品推荐
相关产品推荐

