Подведение итогов в группе по запросу по одной таблице - PullRequest
0 голосов
/ 01 апреля 2012

У меня есть модель задачи с атрибутами, такими как созданный_каталог, часы и различные состояния, которые я хочу показать агрегированными по месяцам и суммировать различные состояния.

| Month   | Count | Hours | States
| 2012-01 | 22    | 26.5  | new(3), closed(4), others(15)
| 2012-02 | 12    | 16.5  | new(0), approved(2), closed(9), others(1)
...

В настоящее время я использую этот запрос, который группирует по месяцам и дает мне счет + часов.

@tasks = Task.select("date(created_at), count(id), sum(hours) AS hours")
             .group("MONTH(created_at)") 
             .order('created_at')

Как я могу добавить сумму по всем различным штатам?

Я читал о group_by, но не думаю, что это хорошо с большим количеством результатов.

Обновление

С таким запросом я получил почти то, что хотел.

@tasks = Tasks.select("date(created_at), state, count(state), sum(hours) AS hours")
          .group("MONTH(created_at)") 
          .group("state")
          .order('created_at')

| Month   | Count | Hours | State
| 2012-01 | 3     | 26.5  | new
| 2012-01 | 4     | 16.5  | approved
| 2012-01 | 15    | 22.5  | others
| 2012-02 | 2     | 16.5  | approved
| 2012-02 | 9     | 16.5  | closed
...

Update2

У меня есть SQL-запрос, который дает мне нужный мне результат.

@tasks = Task.select("
  DATE( created_at ) AS month, 
  COUNT( state ), 
  SUM( hours ) AS hours,
  COUNT( case when `state` = 'new' then `state` else NULL end ) AS state_new,
  SUM( case when `state` = 'new' then `hours` else NULL end ) AS state_new_hours,
  COUNT( case when `state` = 'approved' then `state` else NULL end ) AS state_approved,
  SUM( case when `state` = 'approved' then `hours` else NULL end ) AS state_approved_hours,
  COUNT( case when `state` = 'closed' then `state` else NULL end ) AS state_closed,
  SUM( case when `state` = 'closed' then `hours` else NULL end ) AS state_closed_hours,
  COUNT( case when `state` != 'new' AND `state` != 'approved' AND `state` != 'closed' then `state` else NULL end ) AS state_misc")
.group("MONTH(created_at)") 
.order('created_at')

Можно ли это сделать через соединение? Как сделать это более распространенным способом и использовать динамическое состояние?

1 Ответ

1 голос
/ 01 апреля 2012

Итак, я предполагаю, что вы используете MySQL, и у вас есть отдельная таблица states, а на состояния в других столбцах ссылается идентификатор, например:

| ID | Name   |
| 1  | new    |
| 2  | closed |
| 3  | open   |

Таким образом, выполняя эту инструкцию SQL в MySQL

SELECT states.name AS state, DATE_FORMAT(tasks.created_at, '%Y-%m') AS month,
       COUNT(tasks.id) AS count, SUM(tasks.hours) AS hours
  FROM states JOIN tasks ON states.id = tasks.state_id
GROUP BY state, month
ORDER BY month

вы должны получить такой результат

| state  | month   | count | hours |
| open   | 2012-03 | 22    | 38.5  |
| open   | 2012-04 | 17    | 40.0  |
| closed | 2012-03 | 45    | 0.5   |

Итак, вам просто нужно перенести этот запрос в запрос ActiveRelation, или вы можете использовать Task.find_by_sql. Это не совсем то, как вы описали, как вы хотите, чтобы ваш результат выглядел, но с помощью этого набора вы можете изменить его, используя обычный ruby, после выполнения ...

...