MySQL: Sum values in subqueries

2019-02-27 00:36发布

I have information on school athletics, with tables for school, season, cashflow, and cashflow_group. I'm trying to query for all schools with cashflow in one or more given cashflow_groups within a user-specified range. I need to query multiple different categories in the same query. I'm having trouble.

My query is below. The reason I did it this way is that I can sum multiple cashflow groups, and I thought it worked until I looked closely and saw that it sums the cashflow amount for all schools as total_cashflow_amount, when each school should have a different total, the sum of its associated cashflow rows.

SELECT distinct schools.*, 
  (SELECT sum(`cashflows`.amount) AS cf FROM `schools` 
  INNER JOIN `seasons` ON seasons.school_id = schools.id 
  INNER JOIN `cashflows` ON cashflows.season_id = seasons.id 
  INNER JOIN `cashflow_groups` ON `cashflow_groups`.id = `cashflows`.cashflow_group_id 
  WHERE ((`cashflow_groups`.id = 12) AND (`seasons`.`year` = 2010))) AS total_branding_cashflow 
FROM `schools` 

INNER JOIN `seasons` ON seasons.school_id = schools.id 
INNER JOIN `cashflows` ON cashflows.season_id = seasons.id 
INNER JOIN `cashflow_groups` ON `cashflow_groups`.id = `cashflows`.cashflow_group_id 
INNER JOIN `seasons` seasons_schools ON seasons_schools.school_id = schools.id 
WHERE (`seasons`.`year` = 2010) 
GROUP BY schools.id 
HAVING (total_branding_cashflow BETWEEN 50000000 AND 100000000) 
ORDER BY schools.name ASC LIMIT 0, 50

In this query, total_branding_cashflow is the total for all schools. I can't figure out how to get the total for each school individually in the subquery.

As it stands, I get a result like

| school.id | … | total_branding_cashflow |
|     2     |   |       900000            |
|     5     |   |       900000            |

when what I want is

| school.id | … | total_branding_cashflow |
|     2     |   |       500000            |
|     5     |   |       400000            |

Adding a GROUP BY to the subquery gives me the sum of each school's cashflow in a separate row, but subqueries only work when they give a single row, so this doesn't help me.

What am I missing? The reason I though to use subqueries is that I want to be able to look up multiple different cashflow_groups at the same time, like this:

SELECT distinct schools.*, 
  (SELECT sum(`cashflows`.amount) AS cf FROM `schools` 
  INNER JOIN `seasons` ON seasons.school_id = schools.id 
  INNER JOIN `cashflows` ON cashflows.season_id = seasons.id 
  INNER JOIN `cashflow_groups` ON `cashflow_groups`.id = `cashflows`.cashflow_group_id 
WHERE ((`cashflow_groups`.id = 12) AND (`seasons`.`year` = 2010)) ) AS total_branding_cashflow, 
  (SELECT sum(`cashflows`.amount) AS cf FROM `schools` 
  INNER JOIN `seasons` ON seasons.school_id = schools.id 
  INNER JOIN `cashflows` ON cashflows.season_id = seasons.id 
  INNER JOIN `cashflow_groups` ON `cashflow_groups`.id = `cashflows`.cashflow_group_id 
WHERE ((`cashflow_groups`.id = 1) AND (`seasons`.`year` = 2010)) ) AS total_ticket_sales_cashflow,
  (SELECT sum(`cashflows`.amount) AS cf FROM `schools` 
  INNER JOIN `seasons` ON seasons.school_id = schools.id 
  INNER JOIN `cashflows` ON cashflows.season_id = seasons.id 
  INNER JOIN `cashflow_groups` ON `cashflow_groups`.id = `cashflows`.cashflow_group_id 
WHERE ((`cashflow_groups`.id = 7) AND (`seasons`.`year` = 2010)) ) AS total_university_cashflow 
FROM `schools` 
INNER JOIN `seasons` ON seasons.school_id = schools.id 
INNER JOIN `cashflows` ON cashflows.season_id = seasons.id 
INNER JOIN `cashflow_groups` ON `cashflow_groups`.id = `cashflows`.cashflow_group_id 
INNER JOIN `seasons` seasons_schools ON seasons_schools.school_id = schools.id 
WHERE (`seasons`.`year` = 2010) 
GROUP BY schools.id 
HAVING (total_branding_cashflow BETWEEN 50000000 AND 100000000) AND 
       (total_ticket_sales_cashflow BETWEEN 50000000 AND 100000000) AND 
       (total_university_cashflow BETWEEN 0 AND 10000000) 
ORDER BY schools.name ASC LIMIT 0, 50

I didn't think I could do this with a SUM that isn't in its own subquery. I'm working on a rails app, and could probably come up with a way to do this via ruby code. But that doesn't seem right and I'd prefer to get it down in SQL if possible. Thanks!

1条回答
在下西门庆
2楼-- · 2019-02-27 00:47

Some suggestions:

  • Join on seasons once. A join causes rows from the left table to be duplicated, so they can be summed twice by the sum aggregate. When in doubt, run the query without group by for an example school.
  • You'd have to relate the subquery to the outer query with something like inner_schools.id = outer_schools.id
  • But as far as I can see, you don't need a subquery at all

For example:

SELECT  schools.*
,       sum(cashflows.amount) total_branding_cashflow
FROM    schools
JOIN    seasons
ON      seasons.school_id = schools.id 
        and seasons.year = 2010
JOIN    cashflows
ON      cashflows.season_id = seasons.id 
        and cashflow_group_id = 12
GROUP BY 
        schools.id 
HAVING  total_branding_cashflow BETWEEN 50000000 AND 100000000

For multiple categories, you could use a case:

SELECT  schools.*
,       sum(case when cashflow_group_id = 1 then cashflows.amount end) total1
,       sum(case when cashflow_group_id = 12 then cashflows.amount end) total12
FROM    schools
JOIN    seasons
ON      seasons.school_id = schools.id 
        and seasons.year = 2010
JOIN    cashflows
ON      cashflows.season_id = seasons.id 
GROUP BY 
        schools.id 
查看更多
登录 后发表回答