从yii中的两个相关模型中检索两列的总和

时间:2012-10-31 11:27:02

标签: sql yii model yii-relations

我是一个很新的yii工作,但有很多PHP和SQL的经验。 我希望有更多经验的人可以指出我正确的方向。我有两个模型,项目和成本,它们通过project_cost表在多对多关系中相互关联。原因是项目之间可以共享成本。在project_cost表中,还有一个附加列,其中包含为特定项目分配的成本。

所以Project模型关系看起来像这样,它可以很好地获取所有细节:

class Project extends CActiveRecord
{

    /**
    * @return array relational rules.
    */
    public function relations()
    {
    return array(
        'projectcost'   => array(self::HAS_MANY,   'ProjectCost',    'project_id'),
        'cost'      => array(self::HAS_MANY, 'Cost', array('cost_id'=>'id'),'through'=>'projectcost'),
        //i.e. a many to many relation of cost through the projectcost model

        );
    }
    ...
}

在成本模型中有一个名为Value的列,在project_cost表中有列名称Percent。很容易构造一个包含sql查询的函数,它给出了项目成本的总和,如下所示:

select sum(project_cost.Percent*cost.Value) 
from project_cost join cost on project_cost.cost_id=cost.id 
where project_cost.project_id=1     

但有没有办法在yii中通过关系做同样的事情?我知道STAT关系,但我不清楚如何在这种情况下应用它们,因为我到目前为止所阅读的大部分内容都表明,如果关系中只有两个模型,那么关系效果最好。

3 个答案:

答案 0 :(得分:1)

您可以创建一个范围来获取此数据,在Project模型中创建一个方法,如:

public function withAdjustedCost()
{
    $this->getDbCriteria()->mergeWith(array(
        'with'=>array(
            'projectcost',
            'cost',
        ),
        'select'=>'*, sum(projectcost.Percent*cost.Value) as adjustedCost',
    ));

    return $this;
}

然后,当您抓住项目模型时,您应该能够使用它;

$models = Project::model->withAdjustedCost()->findAll();

我没有对它进行过测试,你可能需要对它进行一些修改,或者可能需要将$adjustedCost定义为模型的属性才能访问它(然后再次,也许不是)。 ..无论如何,可能是一个方向。

答案 1 :(得分:0)

您可能需要查看CDbCriteria类,它允许您使用Yii框架构建查询,因此“正确”。

另外,我认为您可以使用CActiveRecord->getRelated()方法提取数组中的所有ProjectCost模型,然后使用foreach循环以构建所需的总和。在Project模型中,您可以创建一个非常类似的方法:

class Project extends CActiveRecord
{
  ...
  /**
  * @return the sum of all weighed Costs corresponding to this Project.
  */
  public function getTotalCost()
  {
      $projectCosts = $this->getRelated('projectcost'); // fetches array of ProjectCost models, which you can iterate over
      $sum = 0;
      foreach($projectCosts as $projectCost)
      {
          $sum += $projectCost->Percent * $projectcost->getRelated('cost')->Value;
      }
      return $sum;
  }
  ...
}

这取决于以下想法:

$projectcost->getRelated('cost')->Value;

您的ProjectCost模型具有如下关系:

'cost'   => array(self::HAS_ONE,   'Cost',    'cost_id'), 

只要您需要访问它,getRelated()就可以获取相关的Cost模型。

所以你基本上可以简单地使用$model->getTotalCost()来获得你在查询中表达的成本之和,但实际上是在模型中构建的,我认为这是适当的MVC,而不是让数据库为你做计算使用查询。

编辑:getRelated()在使用相关记录时已被证明是真正的朋友,它会获取一组记录或一条记录,具体取决于它与之合作的关系的性质。

关于您对数据库访问的看似关注,您还可以查看CActiveRecord->afterFind(),您可以重载该文件以计算项目总和,并在加载模型后立即将其设置为公共变量。所以你会得到你的代码:

public $projectSum = 0;
public function afterFind(){
   //Fetch array of ProjectCost models, which you can iterate over
   foreach($this->getRelated('projectcost') as $projectCost)
   {
     $this->projectSum += $projectCost->Percent * $projectcost->getRelated('cost')->Value;
   }
}

答案 2 :(得分:0)

简单有效:

$sum = Yii::app()->db->createCommand("
    select sum(project_cost.Percent*cost.Value)
    from project_cost
    join cost on project_cost.cost_id=cost.id
    where project_cost.project_id=1
")->queryScalar();

$ sum === false如果出错了