Это немного сложно, поэтому позвольте мне провести вас через него. Во-первых, вам нужен список компаний, в том числе компаний, у которых нет покупок. Вы можете получить, что с:
SELECT DISTINCT company
FROM fruit_paid;
И вы могли бы просто использовать, чтобы получить краткую информацию для всех компаний, и все время что-то вроде этого:
WITH
company_names as
(SELECT DISTINCT company
FROM fruit_paid)
SELECT company_names.company, sum(fruit_paid.qty) as total_fruit_purchased
FROM company_names
LEFT OUTER JOIN fruit_paid
ON company_names.company = fruit_paid.company
GROUP BY company_names.company;
Две вещи происходит там: 1- Я беру предыдущий запрос («SELECT DISTINCT ...
») и делаю его чем-то, называемым общим табличным выражением - это просто означает, что я могу использовать этот запрос, например таблицу. 2- Я использую LEFT OUTER JOIN
, который будет использовать левую таблицу, чтобы определить строки, и присоединиться ко всему из правой таблицы, где это возможно.
Это основа того, что необходимо для этого. Вы можете получить список лет с функцией generate_series
. Что-то вроде:
SELECT extract(YEAR from generate_series) as year
FROM generate_series('2015-01-01'::date,
'2016-01-01'::date,
'1 year');
Что вы можете развернуться и добавить к предыдущему запросу:
WITH
company_names as
(SELECT DISTINCT company
FROM fruit_paid),
years as
(SELECT extract(YEAR from generate_series) as year
FROM generate_series('2015-01-01'::date,
'2016-01-01'::date,
'1 year'))
SELECT company_names.company,
years.year,
sum(fruit_paid.qty) as total_fruit_purchased
FROM company_names
CROSS JOIN years
LEFT OUTER JOIN fruit_paid
ON company_names.company = fruit_paid.company
AND extract(YEAR from fruit_paid.date) = years.year
GROUP BY company_names.company, years.year;
Использование CROSS JOIN
там получает вас один ряд в сочетании с левой таблицы (company_names
) и правую таблицу (years
). Другими словами, один ряд для каждой компании и года, независимо от покупок. Чтобы вы получили данные о покупке, вы снова присоединились к fruit_paid.
Последний кусок квартала. Там простой способ, чтобы получить список всех кварталов:
VALUES ('Q1'), ('Q2'), ('Q3'), ('Q4');
Так давайте добавим, что в:
WITH
company_names as
(SELECT DISTINCT company
FROM fruit_paid),
years as
(SELECT extract(YEAR from generate_series) as year
FROM generate_series('2015-01-01'::date,
'2016-01-01'::date,
'1 year')),
quarters (quarter) as
(VALUES ('Q1'), ('Q2'), ('Q3'), ('Q4'))
SELECT company_names.company,
years.year,
quarters.quarter,
sum(fruit_paid.qty) as total_fruit_purchased
FROM company_names
CROSS JOIN years
CROSS JOIN quarters
LEFT OUTER JOIN fruit_paid
ON company_names.company = fruit_paid.company
AND extract(YEAR from fruit_paid.date) = years.year
AND quarters.quarter = case
WHEN extract(MONTH FROM date) <= 3
THEN 'Q1'
WHEN extract(MONTH FROM date) BETWEEN 4 AND 6
THEN 'Q2'
WHEN extract(MONTH FROM date) BETWEEN 7 AND 9
THEN 'Q3'
WHEN extract(MONTH FROM date) BETWEEN 10 AND 12
THEN 'Q4'
ELSE 'UNKNOWN'
END
GROUP BY company_names.company, years.year, quarters.quarter;
только новые модные вещи мы сделали здесь было дать немного больше определение для quarters
общего table - мы добавили имя столбца. Для псевдо-запросов, таких как VALUES
, может быть удобно определить имена для возвращаемых столбцов, и это делает запрос более понятным позже (иначе мы будем присоединяться к quarters.column
, что просто сложно понять) ,
Надеюсь, что это поможет.
Вот некоторые из соответствующей документации:
- Table Expressions, переходящий с использованием результатов запроса в виде таблиц, а также затрагивает различные типы объединений.
- WITH queries, в котором конкретно говорится об общих табличных выражениях.
- VALUES, который я включаю для полноты.
- Set-Returning Functions, который описывает все способы использования
generate_series
.