Yii2 - 按最新的 hasMany 关系搜索
Yii2 - search by latest of hasMany relation
我有名为 Task 和 Test 的 ActiveRecord 模型。任务可能包含多个测试(或零个)。
Task
模型中的关系:
public function getTests(){
return $this->hasMany(Test::className(), ['task_num' => 'task_num']);
}
public function getLastTest(){
return $this->hasOne(Test::className(), ['task_num' => 'task_num'])->addOrderBy(['test_num' => SORT_DESC])->limit(1);
}
不出所料,lastTest
关系无法正常工作。我需要这种关系来进行搜索。我需要过滤所有状态等于 3 且有测试的任务,而最新的任务状态不等于 4。
TaskSearch
型号:
public function search($params)
{
$query = Task::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
]);
// standart search content
// ...
// ...
// TASK_COMPLETE is 3
// TEST_COMPLETE is 4
$query->andFilterWhere(['tbl_task.status' => TASK_COMPLETE]);
$query->joinWith(['lastTest' => function($q){
$q->where('tbl_test.status <> ' . TEST_COMPLETE);
}]);
return $dataProvider;
}
结果 sql 查询是:
SELECT `tbl_task`.*
FROM `tbl_task`
LEFT JOIN `tbl_test` ON `tbl_task`.`task_num` = `tbl_test`.`task_num`
WHERE (`tbl_task`.`status`=3) AND (tbl_test.status <> 4)
ORDER BY `task_num` DESC, `test_num` DESC
LIMIT 10
此查询查找具有 至少一项测试 且状态不等于 4 的所有任务,但我只需要查找具有 仅最后一次测试状态的任务不等于 4 或根本没有测试。
如何定义必要的关系并设置搜索方法?
编辑:
通过反复试验,我找到了正确的 sql 查询:
SELECT t1.*
FROM tbl_task t1
LEFT JOIN tbl_test t2 ON t1.task_num = t2.task_num
WHERE
(t1.status = 3) AND
(t2.status <> 4) AND
(t2.test_num = (SELECT MAX(t3.test_num) FROM tbl_test t3 LEFT JOIN tbl_task t4 ON t3.task_num = t4.task_num))
如何从 search
方法进行查询?
编辑 2:
我错了,这个查询也不行。
试试这个:
public function getLastTest(){
return $this->getTests()->addOrderBy(['test_num' => SORT_DESC])->limit(1);
}
然后是这个:
$query = Task::find();
$query->joinWith('lastTest as lt');
$query->andFilterWhere(['tbl_task.status' => TASK_COMPLETE]);
$query->andFilterWhere('lt.status <> ' . TEST_COMPLETE);
终于通过子查询搞定了。
我的解决方案是:
$query->andFilterWhere(['tbl_task.status' => TASK_COMPLETE]);
$query->joinWith(['lastTest' => function($q){
$q->where('tbl_test.status <> ' . TEST_COMPLETE);
}]);
$query->andWhere('(tbl_test.test_num = (SELECT MAX(t1.test_num) FROM tbl_test t1 LEFT JOIN tbl_task t2 ON t1.task_num = t2.task_num WHERE t2.task_num = tbl_task.task_num GROUP BY t2.task_num))');
这不是一个非常干净的解决方案,但它确实有效。
我有名为 Task 和 Test 的 ActiveRecord 模型。任务可能包含多个测试(或零个)。
Task
模型中的关系:
public function getTests(){
return $this->hasMany(Test::className(), ['task_num' => 'task_num']);
}
public function getLastTest(){
return $this->hasOne(Test::className(), ['task_num' => 'task_num'])->addOrderBy(['test_num' => SORT_DESC])->limit(1);
}
不出所料,lastTest
关系无法正常工作。我需要这种关系来进行搜索。我需要过滤所有状态等于 3 且有测试的任务,而最新的任务状态不等于 4。
TaskSearch
型号:
public function search($params)
{
$query = Task::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
]);
// standart search content
// ...
// ...
// TASK_COMPLETE is 3
// TEST_COMPLETE is 4
$query->andFilterWhere(['tbl_task.status' => TASK_COMPLETE]);
$query->joinWith(['lastTest' => function($q){
$q->where('tbl_test.status <> ' . TEST_COMPLETE);
}]);
return $dataProvider;
}
结果 sql 查询是:
SELECT `tbl_task`.*
FROM `tbl_task`
LEFT JOIN `tbl_test` ON `tbl_task`.`task_num` = `tbl_test`.`task_num`
WHERE (`tbl_task`.`status`=3) AND (tbl_test.status <> 4)
ORDER BY `task_num` DESC, `test_num` DESC
LIMIT 10
此查询查找具有 至少一项测试 且状态不等于 4 的所有任务,但我只需要查找具有 仅最后一次测试状态的任务不等于 4 或根本没有测试。
如何定义必要的关系并设置搜索方法?
编辑:
通过反复试验,我找到了正确的 sql 查询:
SELECT t1.*
FROM tbl_task t1
LEFT JOIN tbl_test t2 ON t1.task_num = t2.task_num
WHERE
(t1.status = 3) AND
(t2.status <> 4) AND
(t2.test_num = (SELECT MAX(t3.test_num) FROM tbl_test t3 LEFT JOIN tbl_task t4 ON t3.task_num = t4.task_num))
如何从 search
方法进行查询?
编辑 2:
我错了,这个查询也不行。
试试这个:
public function getLastTest(){
return $this->getTests()->addOrderBy(['test_num' => SORT_DESC])->limit(1);
}
然后是这个:
$query = Task::find();
$query->joinWith('lastTest as lt');
$query->andFilterWhere(['tbl_task.status' => TASK_COMPLETE]);
$query->andFilterWhere('lt.status <> ' . TEST_COMPLETE);
终于通过子查询搞定了。
我的解决方案是:
$query->andFilterWhere(['tbl_task.status' => TASK_COMPLETE]);
$query->joinWith(['lastTest' => function($q){
$q->where('tbl_test.status <> ' . TEST_COMPLETE);
}]);
$query->andWhere('(tbl_test.test_num = (SELECT MAX(t1.test_num) FROM tbl_test t1 LEFT JOIN tbl_task t2 ON t1.task_num = t2.task_num WHERE t2.task_num = tbl_task.task_num GROUP BY t2.task_num))');
这不是一个非常干净的解决方案,但它确实有效。