2017-04-06 35 views
0

的我有一个名为任务和测试ActiveRecord的模式搜索。任务可能包含多个测试(或零)。Yii2 - 通过最新的hasMany关系

关系在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或W根本没有测试。

如何定义必要的关系,建立了搜索方法?

编辑:

通过试错我发现正确的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:

我错了,这个查询也不起作用。

回答

1

通过子查询终于得到它。

我的解决办法是:

$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))'); 

不是很干净的解决方案,但它的工作原理。

0

试试这个:

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); 
+0

一切都没变,查询仍然是完全一样的。 – Exerion

+0

试试我的更新答案 – gmc

+0

最后一行给出错误,因为参数必须是数组。更改为$ query-> andFilterWhere(['<>','lt.status',TEST_COMPLETE])会清除错误,但结果查询是:'SELECT'tbl_task'。* FROM'tbl_task' LEFT JOIN'tbl_test'' lt' ON'tbl_task'.'task_num' ='lt'.'task_num' WHERE('tbl_task'.'status' = 3)AND('lt'.'status' <> 4)ORDER BY'task_num' DESC,'test_num 'DESC极限10' – Exerion