SQL-запрос, который делает два GROUP BY? - PullRequest
2 голосов
/ 10 мая 2011

У меня проблемы с получением SQL для отчета, который мне нужно сгенерировать. У меня есть (эквивалент) следующей настройки:

  • Таблица articles (такие поля, как имя, manufacturer_id и т. Д.).
  • Стол sales.
    • FK к статьям под названием article_id
    • Целое число, называемое amount
    • A date поле
    • Поле с именем type. Мы можем предположить, что это строка, и она может иметь 3 известных значения - 'morning', 'evening' и 'night'

Я хочу создать агрегированный отчет о продажах с учетом начальной и конечной даты:

 +--------------+---------------+--------------+-------------+
 | article_name | morning_sales | evening_sales| night_sales |
 +--------------+---------------+--------------+-------------+
 | article 1    |             0 |           12 |           2 |
 | article 2    |            80 |            3 |           0 |
...            ...             ...            ...           ...
 | article n    |            37 |           12 |           1 |
 +--------------+---------------+--------------+-------------+

Я бы хотел сделать это максимально эффективно. До сих пор я был в состоянии создать запрос, который даст мне один тип продажи (утром, вечером или ночью), но я не могу сделать это для нескольких типов одновременно. Это вообще возможно?

Это то, что я имею до сих пор; это даст мне название статьи и утренние продажи всех статей за определенный период - другими словами, первые два столбца отчета:

SELECT articles.name as article_name,
       SUM(sales.amount) as morning_sales,
FROM "sales"
INNER JOIN articles ON articles.id = sales.articles_id
WHERE ( sales.date >= '2011-05-09'
    AND sales.end_date <= '2011-05-16'
    AND sales.type = 'morning'
)
GROUP BY sales.article_id

Полагаю, я мог бы сделать то же самое для вечера и ночи, но статьи будут другими; например, некоторые статьи могут продаваться утром, но не вечером.

  • Если мне нужно сделать 1 запрос на тип продажи, как мне «смешать и сопоставить» различные списки статей, которые я получу?
  • Есть ли лучший способ сделать это (возможно, с какими-то подзапросами)?

Точно так же я могу создать запрос, который дает мне все утренние, вечерние и ночные продажи, группируя по типу. Я предполагаю, что моя проблема в том, что мне нужно сделать два предложения BY BY, чтобы получить этот отчет. Я не знаю, как это сделать, если это вообще возможно.

Я использую PostgreSQL в качестве своей БД, но я бы хотел оставаться как можно более стандартным. Если это помогает, приложение, использующее это, является приложением Rails.

Ответы [ 2 ]

4 голосов
/ 10 мая 2011

К счастью, вам не нужно делать несколько запросов с форматом вашей базы данных. Это должно работать для вас:

SELECT
  articles.name AS article_name
  SUM(IF(sales.type = 'morning', sales.amount, 0.0)) AS morning_sales,
  SUM(IF(sales.type = 'evening', sales.amount, 0.0)) AS evening_sales,
  SUM(IF(sales.type = 'night', sales.amount, 0.0)) AS night_sales
FROM sales
  JOIN articles ON sales.article_id = articles.id
WHERE
  sales.date >= "2011-01-01 00:00:00"
  AND sales.date < "2011-02-01 00:00:00"
GROUP BY sales.article_id

А если есть другие типы, вам придется добавить туда больше столбцов, ИЛИ просто суммировать другие типы, добавив это в предложение SELECT:

SUM(
  IF(sales.type IS NULL OR sales.type NOT IN ('morning', 'evening', 'night'), 
    sales.amount, 0.0
  )
) AS other_sales

Вышеуказанное совместимо с MySQL. Чтобы использовать его в Postgres, я думаю, вам придется изменить выражения IF на CASE выражения , что должно выглядеть так (не проверено):

SELECT
  articles.name AS article_name,
  SUM(CASE WHEN sales.type = 'morning' THEN sales.amount ELSE 0.0 END) AS morning_sales,
  SUM(CASE WHEN sales.type = 'evening' THEN sales.amount ELSE 0.0 END) AS evening_sales,
  SUM(CASE WHEN sales.type = 'night' THEN sales.amount ELSE 0.0 END) AS night_sales
FROM sales
  JOIN articles ON sales.article_id = articles.id
WHERE
  sales.date >= "2011-01-01 00:00:00"
  AND sales.date < "2011-02-01 00:00:00"
GROUP BY sales.article_id
2 голосов
/ 10 мая 2011

Два варианта.

Вариант 1. Одиночное объединение с вычисленными столбцами для агрегирования

select article_name  = a.article_name ,
       morning_sales = sum( case when sales.type = 'morning' then sales.amount end ) ,
       evening_sales = sum( case when sales.type = 'evening' then sales.amount end ) ,
       night_sales   = sum( case when sales.type = 'night'   then sales.amount end ) ,
       other_sales   = sum( case when sales.type in ( 'morning','evening','night') then null else sales.amount end ) ,
       total_sales   = sum( sales.amount )
from articles a
join sales    s on s.articles_id = a.articles_id
where sales.date between @dtFrom and @dtThru
group by a.article_name

Вариант 2. несколько левых объединений

select article_name = a.article_name ,
       morning_sales = sum( morning.amount ) ,
       evening_sales = sum( evening.amount ) ,
       night_sales   = sum( night.amount   ) ,
       other_sales   = sum( other.amount   ) ,
       total_sales   = sum( total.amount   )
from      articles a
left join sales    morning on morning.articles_id = a.articles_id
                          and morning.type        = 'morning'
                          and morning.date between @dtFrom and @dtThru
left join sales    evening on evening.articles_id = a.articles_id
                          and evening.type        = 'evening'
                          and evening.date between @dtFrom and @dtThru
left join sales    night   on night.articles_id   = a.articles_id
                          and night.type          = 'evening'
                          and night.date between @dtFrom and @dtThru
left join sales    other   on other.articles_id = a.articles_id
                          and (    other.type is null
                                OR other.type not in ('morning','evening','night')
                              )
                          and other.date between @dtFrom and @dtThru
left join sales    total   on total.articles_id = a.articles_id
                          and total.date between @dtFrom and @dtThru
group by a.article_name
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...