MySQL: сумма значений в подзапросах - PullRequest
2 голосов
/ 18 августа 2010

У меня есть информация о школьной легкой атлетике, с таблицами для школы, сезона, cashflow и cashflow_group. Я пытаюсь сделать запрос для всех школ с денежным потоком в одной или нескольких указанных cashflow_groups в указанном пользователем диапазоне. Мне нужно запросить несколько разных категорий в одном запросе. У меня проблемы.

Мой запрос ниже. Причина, по которой я сделал это таким образом, состоит в том, что я могу суммировать несколько групп денежных потоков, и я думал, что это сработало, пока я не посмотрел внимательно и не увидел, что сумма всех денежных потоков для всех школ суммируется как total_cashflow_amount, когда каждая школа должна иметь другая сумма, сумма связанных строк о движении денежных средств.

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

В этом запросе total_branding_cashflow - это общее количество всех школ . Я не могу понять, как получить общее количество для каждой школы отдельно в подзапросе.

В таком виде я получаю результат, подобный

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

когда я хочу

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

Добавление GROUP BY к подзапросу дает мне сумму денежного потока каждой школы в отдельной строке, но подзапросы работают только тогда, когда они дают одну строку, поэтому это не помогает мне.

Что мне не хватает? Причина, по которой я предпочитаю использовать подзапросы, заключается в том, что я хочу иметь возможность искать несколько разных cashflow_groups одновременно, например:

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

Я не думал, что смогу сделать это с SUM, который не находится в его собственном подзапросе. Я работаю над приложением rails и, возможно, смогу придумать способ сделать это через код ruby. Но это кажется неправильным, и я бы предпочел записать его на SQL, если это возможно. Спасибо!

1 Ответ

3 голосов
/ 18 августа 2010

Несколько предложений:

  • Присоединяйтесь к seasons один раз.Объединение приводит к дублированию строк из левой таблицы, поэтому их можно суммировать дважды с помощью совокупности sum.Если вы сомневаетесь, запустите запрос без group by для примера школы.
  • Вы должны связать подзапрос с внешним запросом с помощью чего-то вроде inner_schools.id = outer_schools.id
  • Но насколькоЯ вижу, вам вообще не нужен подзапрос

Например:

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

Для нескольких категорий вы можете использовать регистр:

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 
...