Я получаю все ответы пользователя. Но мне нужен только последний ответ / ответ пользователя (Использование идентификатора ответа). Я запускаю приведенный ниже запрос.
$users_all_answers=$this->SurveySectionAnswers->find('all')
->where(['survey_response_id IN'=>$response_ids])
->order(['survey_response_id'=>'desc'])
->group(['survey_question_id'])
->hydrate(false)
->toArray();
Но я получаю ответ пользователя, а не по последнему ответу из-за выполнения в Группе до, до Заказ по. Так есть ли какое-либо решение, чтобы я мог получить все ответы по последнему ответу пользователя.
Получение массива вот так
[0] => Array
(
[id] => 527
[survey_response_id] => 74
[survey_question_id] => 84
[survey_answer] =>
[survey_score] => 0
[survey_section_id] => 50
[survey_answer_id] => 138
[completed] => 1
)
[1] => Array
(
[id] => 528
[survey_response_id] => 74
[survey_question_id] => 85
[survey_answer] =>
[survey_score] => 0
[survey_section_id] => 48
[survey_answer_id] => 142
[completed] => 1
)
Но я хочу как
[0] => Array
(
[id] => 527
[survey_response_id] => 76
[survey_question_id] => 84
[survey_answer] =>
[survey_score] => 0
[survey_section_id] => 50
[survey_answer_id] => 138
[completed] => 1
)
[1] => Array
(
[id] => 528
[survey_response_id] => 76
[survey_question_id] => 85
[survey_answer] =>
[survey_score] => 0
[survey_section_id] => 48
[survey_answer_id] => 142
[completed] => 1
)
В MySQL GROUP BY выполняется перед ORDER BY. GROUP BY всегда выбирает верхнюю строку в наборе результатов, поэтому ORDER BY не влияет на нее, пока эта группа не будет выполнена.
Есть число из методы делать то, что вы описываете в MySQL. Я предпочитаю использовать метод, в котором вы присоединяете таблицу к себе таким образом, чтобы гарантировать, что последняя строка будет фактически выбранной.
В CakePHP это будет выглядеть примерно так:
$users_all_answers = $this->SurveySectionAnswers->find()
->join([
'SurveySectionAnswers_2' => [
'table' => 'survey_section_answers',
'type' => 'LEFT',
'conditions' => [
'SurveySectionAnswers_2.survey_question_id' => new \Cake\Database\Expression\IdentifierExpression('SurveySectionAnswers_2.survey_question_id'),
'SurveySectionAnswers.id <' => 'SurveySectionAnswers_2.id'
]
]
])
->where([
'SurveySectionAnswers.survey_response_id IN' => $response_ids,
'SurveySectionAnswers_2 IS ' => null
])
->hydrate(false)
->toArray();
Это работает, потому что LEFT JOIN перечисляет все возможные комбинации строк по порядку, но предложение WHERE фильтрует все, кроме самой последней (той, у которой нет объединенной строки) в наборе результатов.
Другой альтернативой является использование Коллекции indexBy или groupBy.
Это будет иметь последствия для производительности но может быть более понятным в коде.
Получите ваш список ответов. Это вернет объект с интерфейсом коллекции.
$users_all_answers = $this->SurveySectionAnswers->find('all')
->where(['survey_response_id IN'=>$response_ids])
->order(['survey_response_id'=>'asc'])
->hydrate(false);
Очень важно отметить, что вы должны упорядочить свой запрос в обратном порядке, так как indexBy и groupBy вернут последний элемент в группе.
В приведенном выше запросе я изменил порядок survey_response_id
от desc
в asc
чтобы сделать это.
Затем вы можете вызвать groupBy или indexBy по вашему заказанному запросу. Это немедленно вызовет ваш запрос.
$users_grouped_by_id = $users_all_answers->groupBy('survey_question_id')
Или если вы хотите только 1 результат на группу
$users_indexed_by_id = $users_all_answers->indexBy('survey_question_id')
groupBy
а также indexBy
являются функциями интерфейса коллекции. Не путать с group
которая является функцией построителя запросов. Каждый запрос является коллекцией, но коллекции не являются запросами.