cake Как выполнить Order by перед Группой by cake php 3?

Я получаю все ответы пользователя. Но мне нужен только последний ответ / ответ пользователя (Использование идентификатора ответа). Я запускаю приведенный ниже запрос.

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

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 фильтрует все, кроме самой последней (той, у которой нет объединенной строки) в наборе результатов.

1

Другие решения

Другой альтернативой является использование Коллекции 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 которая является функцией построителя запросов. Каждый запрос является коллекцией, но коллекции не являются запросами.

0

По вопросам рекламы [email protected]