cakephp结合find()查询

时间:2013-05-23 09:53:04

标签: cakephp

我仍然是Cakephp的新手我有3个查找相同模型的查询,我试图将它们组合成一个。通过访问数据的蛋糕方式很难找到它。特别是他们有不同的发现条件。也许它无法完成。

Cakephp版本2.3.5

    // Count Total Members
    $totalMemebers = $this->Member->find('count');
    $this->set('totalMemebers', $totalMemebers);

    // SUM total points gained for the last 7 days  (positive values)   
    $this->Member->Point->virtualFields['gainedTotal'] = 'SUM(Point.points)';
    $gainedTotal = $this->Member->Point->find('all', array(
        'recursive'=> -1, 
        'fields' => array('gainedTotal'), 
        'conditions'=>array(
                'Point.points >'=>0, 
                'Point.date >' => date('Y-m-d', strtotime("-1 weeks")))
        )
    );
    $this->set('gainedTotal', $gainedTotal);

    // SUM total points redeemed for the last 7 days (negative values)
    $this->Member->Point->virtualFields['redeemedTotal'] = 'SUM(Point.points)';
    $redeemedTotal = $this->Member->Point->find('all', array(
        'recursive'=> -1,   
        'fields' => array('redeemedTotal'), 
        'conditions'=>array(
                'Point.points <'=>0), 
                'Point.date >' => date('Y-m-d', strtotime("-1 weeks"))
        )
    );
    $this->set('redeemedTotal', $redeemedTotal);

1 个答案:

答案 0 :(得分:3)

由于所有查询都使用不同的条件,因此无法将它们组合到单个查询中。这不是CakePHP的限制,使用常规SQL也不允许你这样做,除非你打算使用子查询或某些calculated fieldsSELECT CASE WHEN points > 0 AND date > .... THEN points ELSE 0 END CASE AS gainedPoint),但这将提供没有好处(表现明智)

优化

为了优化(并清理)您的代码, 可以进行一些改进;

首先,要获取单个字段的值,您可以使用Model::field()。这将只返回字段的普通,而不是包含该值的数组

例如:

$this->Member->Point->virtualFields['gainedTotal'] = 'SUM(Point.points)';

$gainedTotal = $this->Member->Point->field('gainedTotal', array(
    'Point.points >'=>0, 
    'Point.date >' => date('Y-m-d', strtotime("-1 weeks"))
));
$this->set('gainedTotal', $gainedTotal);

将与数据相关的代码移至您的模型

这是你应该做的一般事情。将这些查询移动到您的模型。这将使您的代码更清洁并且更好地维护。此外,您的查询将更容易重复使用,最后,您将能够单元测试查询。

class Point extends AppModel
{
    // general stuff/properties here

    /**
     * Returns the SUM total points gained for 
     * the last 7 days  (positive values)
     *
     * @return int  Gained total for all members
     */
    public function gainedTotal()
    {
        this->virtualFields['gainedTotal'] = 'SUM(points)';

        $gainedTotal = $this->field('gainedTotal', array(
            'points >'=>0, 
            'date >'  => date('Y-m-d', strtotime("-1 weeks"))
        ));

        // remove the virtualField to prevent it being used
        // in subsequent queries
        unset($this->virtualFields['gainedTotal']);

        return (int)$gainedTotal;
    }

}

而且,在你的控制器中,只需这样做:

$this->set('gainedTotal', $this->Member->Point->gainedTotal());

这显然会减少控制器内部的代码量(“瘦控制器,胖模型”),这总是很好的做法。

将相关索引添加到数据库

如果 重要,则可以通过向数据库添加正确的索引来大规模提高这些查询的性能,尤其是在计算大量记录的总计时。

详细描述这个问题超出了这个问题的范围,但这里有一些指示; How MySQL uses indexesCREATE INDEX SYNTAX