#mysql #sql #left-join
#mysql #sql #левое соединение
Вопрос:
Я пытаюсь создать простой запрос MySQL, чтобы получить данные о продажах за каждый месяц года, сгруппированные по monthname
и SalesName
.
CREATE TEMPORARY TABLE Cal (monthid INT, monthname VARCHAR(50));
INSERT INTO Cal (monthid, monthname) VALUES
(1, 'January'),
(2, 'February'),
(3, 'March'),
(4, 'April'),
(5, 'May'),
(6, 'June'),
(7, 'July'),
(8, 'August'),
(9, 'September'),
(10, 'October'),
(11, 'November'),
(12, 'December');
CREATE TEMPORARY TABLE Sales AS SELECT SalesName FROM `Opportunity`;
SELECT concat(c.monthname, ' ', YEAR(CURDATE())) As `Period`,
s.SalesName,
IFNULL(CONVERT(AVG(o.GeneratedRevenue__c), SIGNED INTEGER), 0) As `AverageMonthlyRevenue`,
sum(CASE
WHEN c.monthid = Month(o.CloseDate)
THEN o.Won
ELSE 0
END) As `ClosedDeals`
FROM `Cal` c
join `Sales` s
left join `Opportunity` as o
on o.SalesName=s.SalesName and c.monthid=month(o.CloseDate)
GROUP By c.monthid, s.SalesName
Результаты верны для AverageMonthlyRevenue
, но возвращают полную бессмыслицу для ClosedDeals
.
Исходная база данных:
| Id | AccountName | SalesName | CloseDate | o.GeneratedRevenue__c | Won | Premium |
| -- | ------ | ------ | ------ | ------ | ------ | ------ |
|1|Mirazur|Grégoire|2020-05-19|1548|1|0
|2|Apicius|Edouard|2020-02-04|1344|1|1
|3|Arpège|Camille|2020-05-23|1456|1|1
|4|Les Apothicaires|Grégoire|2020-04-29|1635|1|0
|5|Le Bouillon|Camille|2020-12-10|1456|0|0
|6|Pink Mama|Edouard|2020-02-14|666|1|1
Результат:
|Period | SalesName | AverageMonthlyRevenue| ClosedDeals |
| ------ | ------ | ------ | ------ |
|January 2020 | Camille | 0 | 0
|January 2020 | Edouard | 0 | 0
|January 2020 | Grégoire | 0 | 0
|February 2020 | Camille | 0 | 0
|February 2020 | Edouard | 1005 | 4
|February 2020 | Grégoire | 0 | 0
|March 2020 | Camille | 0 | 0
|March 2020 | Edouard | 0 | 0
|March 2020 | Grégoire | 0 | 0
|April 2020 | Camille | 0 | 0
|April 2020 | Edouard | 0 | 0
|April 2020 | Grégoire | 1635 | 0
|May 2020 | Camille | 1456 | 2
|May 2020 | Edouard | 0 | 0
|May 2020 | Grégoire | 1548 | 0
|June 2020 | Camille | 0 | 0
|June 2020 | Edouard | 0 | 0
|June 2020 | Grégoire | 0 | 0
|July 2020 | Camille | 0 | 0
|July 2020 | Edouard | 0 | 0
|July 2020 | Grégoire | 0 | 0
|August 2020 | Camille | 0 | 0
|August 2020 | Edouard | 0 | 0
|August 2020 | Grégoire | 0 | 0
|September 2020 | Camille | 0 | 0
Ответ №1:
Ошибка в вашей временной таблице продаж. Без добавления DISTINCT вы просто дублируете записи. Вам нужно сделать :
CREATE TEMPORARY TABLE Sales AS SELECT DISTINCT SalesName FROM `Opportunity`;
Комментарии:
1. Спасибо @Marshall, это действительно объясняет, почему все было дублировано, кроме средних данных 🙂
Ответ №2:
Для этого вам не нужны временные таблицы. Просто используйте:
SELECT CONCAT(c.monthname, ' ', YEAR(CURDATE())) As Period,
s.SalesName,
COALESCE(AVG(o.GeneratedRevenue__c), 0) As AverageMonthlyRevenue,
COALESCE(SUM(o.won), 0) as ClosedDeals
FROM Cal c CROSS JOIN
(SELECT DISTINCT SalesName
FROM Opportunity s
) LEFT JOIN
Opportunity o
ON o.SalesName = s.SalesName AND
c.monthid = MONTH(o.CloseDate)
GROUP BY c.monthid, s.SalesName;
Примечания:
- Ваш запрос не учитывает год. Это кажется довольно опасным.
- Вы можете использовать
SELECT DISTINCT
во временной таблице, хотяsales
в этом нет необходимости. - Для
ClosedDetails
этого не требуетсяCASE
выражение. JOIN
всегда должно бытьON
предложение — даже если MySQL допускает такой нестандартный и запутанный синтаксис. ИспользуйтеCROSS JOIN
, когда это то, что вы намереваетесь.
Комментарии:
1. Спасибо @Gordon Linoff, ваше объяснение и подробности очень помогли, я выбрал ответ Маршалла, поскольку он был первым, кто решил проблему, но ваша помощь более чем ценна!
2. @YannickHelmut . , , Решение без временной таблицы — гораздо лучшее решение, поэтому я предоставил ответ. Это также решает проблему отсутствия фильтрации по «году» и предоставляет правильный код для
ClosedDeals
.