2017-04-06 7 views
0

私は、タスクとテストというActiveRecordモデルを持っています。タスクにはいくつかのテスト(またはゼロ)が含まれている場合があります。 TaskモデルでYii2 - 最新のhasMany関係で検索

関係:

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モデル:SQLクエリーを結果の

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; 
} 

は次のとおりです。

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 

このクエリは、のすべてのタスクが少なくとも1つのテストのステータスが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' (tbl_task'.status' = 3)AND( 'lt'.'status' <> 4)ORDER BY' task_num' DESC、 'test_num'は 'tbl_task'で' 「DESC LIMIT 10」 – Exerion