Reputation: 1799
I have a Person
that can receive many types of Income
. I want to be able to return the SUM
income earned, broken down by each Income Type
.
+---------------+-----------------+
| INCOME TYPE | SUM AMOUNT |
+---------------+-----------------+
| Salary | $934.33 |
| Gambling | $27.99 |
| Tips | $584.00 |
+---------------+-----------------+
I've been able to get a self::STAT
relational query to provide the overall Income received ($1546.32), but not broken-down by Income Type
.
As a result, I'm trying to do it as a self::HAS_MANY
relational query within the Person
model, like so:
public function relations() {
return array(
'incomes_total' => array(
self::HAS_MANY,
'Income',
'person_id',
'select' => array('income_type_id', 'SUM(amount) AS total'),
'group' => "income_type_id"
));
}
This results in the following SQL being generated:
SELECT
"incomes_total"."income_type_id" AS "t1_c5"
, SUM(amount) AS total
, "incomes_total"."id" AS "t1_c0"
FROM "stwd_income" "incomes_total"
WHERE ("incomes_total"."person_id"=:ypl0)
GROUP BY income_type_id
This gets very close to the query needed.
What I can't figure out is why the line , "incomes_total"."id" AS "t1_c0"
has been added in there. I don't want that. It's causing a CDbException
error:
CDbCommand failed to execute the SQL statement:
SQLSTATE[42803]: Grouping error: 7 ERROR: column "incomes_total.id" must
appear in the GROUP BY clause or be used in an aggregate function.
How can I achieve the type of query that I need to?
UPDATE 1: The difference between Active Record and custom SQL queries is starting to become clear, and that Active Record may not be appropriate for such a task.
Upvotes: 2
Views: 879
Reputation: 335
Personally I wouldn't use ActiveRecord for anything else than very basic queries and CRUD. Even if STAT relations exist they are better used for simple counts or sums. And a HAS_MANY relationship is wrong in any way as you are not expecting an array of models, are you? You only want a simple array of ids and sums, so in your case I would simply create a method in the Person model like this
private $_salaryInfo;
public function getSalaryInfo()
{
//cache the value if possible to save unnecessary queries
if(isset($this->_salaryInfo))
return $this->_salaryInfo;
//query database
$command = Yii::app()->db->createCommand();
$command->select('income_type_id, SUM(amount)')->where('person_id = '.$this->id)->groupBy('income_type_id');
return $this->_salaryInfo = $command->queryAll();
}
You should now be able to do
foreach($person->salaryInfo as $type_id => $sum)
Upvotes: 1