1

我还是 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);
4

1 回答 1

3

因为所有查询都使用不同的条件,所以不可能将它们组合成一个查询。这不是 CakePHP 的限制,使用常规 SQL 也不允许您这样做,除非您要使用子查询或一些计算字段SELECT 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());

这将明显减少控制器中的代码量(“精益控制器,胖模型”),这始终是一个好习惯。

将相关索引添加到您的数据库

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

详细描述这一点超出了这个问题的范围,但这里有一些提示;MySQL 如何使用索引CREATE INDEX SYNTAX

于 2013-05-23T21:37:53.850 回答