如何将含SELECT子查询的指定SQL转换为Yii2 ActiveRecord查询?
当然可以!根据你提供的模型关联和原SQL语句,我们可以轻松把它转换成Yii2 ActiveRecord查询,下面提供几种不同的实现方案,你可以根据自己的场景选择:
方案一:直接对齐原SQL的子查询写法(性能最优,推荐)
这个方案完全复刻你原SQL的逻辑,通过addSelect添加两个计数子查询,全程只执行一次SQL语句,性能和原SQL一致:
use yii\db\Expression; use yii\db\Query; // 构建查询 $prodiQuery = ProdiPenerima::find() ->select('*') // 选中prodi_penerima表的所有字段 ->alias('a') // 和原SQL保持一致的表别名 ->addSelect([ 'jum1' => (new Query()) ->select('count(*)') ->from('pendaftar') ->where(['prodi_pilihan_1' => new Expression('a.id_prodi_penerima')]), 'jum2' => (new Query()) ->select('count(*)') ->from('pendaftar') ->where(['prodi_pilihan_2' => new Expression('a.id_prodi_penerima')]) ]); // 获取结果集 $prodiList = $prodiQuery->all(); // 访问数据示例 foreach ($prodiList as $prodi) { echo "专业ID:{$prodi->id_prodi_penerima} | 第一志愿人数:{$prodi->jum1} | 第二志愿人数:{$prodi->jum2}\n"; }
方案二:利用现有关联关系简化代码
你的ProdiPenerima模型已经定义了pendaftars(对应第一志愿关联)和pendaftars0(对应第二志愿关联),我们可以基于这些关联来构建计数子查询,代码更贴合Yii2的ActiveRecord风格:
use yii\db\Expression; $prodiQuery = ProdiPenerima::find() ->select('*') ->addSelect([ 'jum1' => Pendaftar::find() ->select('count(*)') ->where(['prodi_pilihan_1' => new Expression(ProdiPenerima::tableName() . '.id_prodi_penerima')]), 'jum2' => Pendaftar::find() ->select('count(*)') ->where(['prodi_pilihan_2' => new Expression(ProdiPenerima::tableName() . '.id_prodi_penerima')]) ]); // 获取结果和访问方式和方案一完全一致 $prodiList = $prodiQuery->all();
方案三:模型内添加Getter方法(小数据量场景适用)
如果你的数据量不大,可以在ProdiPenerima模型中添加两个Getter方法,直接通过已有的关联关系获取计数,代码最简洁,但会产生N+1查询问题(每个Prodi模型会单独执行一次count查询),数据量大时性能会受影响:
// 在ProdiPenerima模型类中添加以下方法 public function getJum1() { // 直接利用已定义的pendaftars关联统计数量 return $this->getPendaftars()->count(); } public function getJum2() { // 利用pendaftars0关联统计第二志愿数量 return $this->getPendaftars0()->count(); }
使用时直接访问模型属性即可:
$prodiList = ProdiPenerima::find()->all(); foreach ($prodiList as $prodi) { echo "专业ID:{$prodi->id_prodi_penerima} | 第一志愿人数:{$prodi->jum1} | 第二志愿人数:{$prodi->jum2}\n"; }
额外提示
- 如果需要对
jum1或jum2进行排序,直接在查询中添加orderBy即可,比如$prodiQuery->orderBy('jum1 DESC'); - 方案一和方案二都支持分页,直接调用
->offset($offset)->limit($limit)就能实现分页查询;
内容的提问来源于stack exchange,提问作者eniac05
相关产品推荐
相关产品推荐

