如何在蛋糕php 3之前按Group执行Order?

时间:2017-03-22 11:54:54

标签: php cakephp cakephp-3.0 greatest-n-per-group

我正在获取用户给出的所有答案。但我只需要用户的最新答案/响应(使用响应ID)。我正在运行下面的查询。

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

但是我得到的是用户答案,而不是最新的回复,因为在Order by之前执行了Group by。那么有任何解决方案,以便我可以通过用户的最新响应获得所有答案。

像这样获取数组

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

2 个答案:

答案 0 :(得分:1)

在MySQL中,GROUP BY在ORDER BY之前执行。 GROUP BY将始终选择结果集中的第一行,因此在执行该组之前,它不受ORDER BY的影响。

有一个number of techniques来执行您在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 :(得分:1)

另一种替代方法是使用Collections 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将返回组中的LAST项目

在上述查询中,我将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')

groupByindexBy是集合接口功能。不要与group混淆,后者是查询构建器函数。每个查询都是一个集合,但集合不是查询。