Reputation: 3411
I wrote the below query, which works, but it is incredibly inefficient and slow. What can I do to make it more efficient? I understand that it's basically "looping" over each ID in the system, there's about 500 of them, and running 13 select statements for each one - I just don't know a better way to get this information.
My date field is a DATE
field stored as YYYY-MM-DD
.
SELECT
id as name,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-01-01' AND '2017-01-31') and id = name) as January,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-02-01' AND '2017-02-31') and id = name) as February,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-03-01' AND '2017-03-31') and id = name) as March,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-04-01' AND '2017-04-31') and id = name) as April,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-05-01' AND '2017-05-31') and id = name) as May,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-06-01' AND '2017-06-31') and id = name) as June,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-07-01' AND '2017-07-31') and id = name) as July,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-08-01' AND '2017-08-31') and id = name) as August,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-09-01' AND '2017-09-31') and id = name) as September,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-10-01' AND '2017-10-31') and id = name) as October,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-11-01' AND '2017-11-31') and id = name) as November,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-12-01' AND '2017-12-31') and id = name) as December,
(SELECT sum(captured_profit) from me where (date BETWEEN '2017-11-01' AND '2017-12-31') and id = name) as Total,
from me
where id is not null
group by id;
Upvotes: 2
Views: 258
Reputation: 334
Bill Karwin beat me to it but I also added the sum rows grouped by year:
SELECT id as name, SUM(CASE WHEN MONTH(date) = 1 THEN captured_profit ELSE 0 END) AS January, SUM(CASE WHEN MONTH(date) = 2 THEN captured_profit ELSE 0 END) AS February, SUM(CASE WHEN MONTH(date) = 3 THEN captured_profit ELSE 0 END) AS March, SUM(CASE WHEN MONTH(date) = 4 THEN captured_profit ELSE 0 END) AS April, SUM(CASE WHEN MONTH(date) = 5 THEN captured_profit ELSE 0 END) AS May, SUM(CASE WHEN MONTH(date) = 6 THEN captured_profit ELSE 0 END) AS June, SUM(CASE WHEN MONTH(date) = 7 THEN captured_profit ELSE 0 END) AS July, SUM(CASE WHEN MONTH(date) = 8 THEN captured_profit ELSE 0 END) AS August, SUM(CASE WHEN MONTH(date) = 9 THEN captured_profit ELSE 0 END) AS September, SUM(CASE WHEN MONTH(date) = 10 THEN captured_profit ELSE 0 END) AS October, SUM(CASE WHEN MONTH(date) = 11 THEN captured_profit ELSE 0 END) AS November, SUM(CASE WHEN MONTH(date) = 12 THEN captured_profit ELSE 0 END) AS December, SUM(captured_profit) AS Total, YEAR(date) from me where id is not null group by id, YEAR(date) union SELECT NULL, SUM(CASE WHEN MONTH(date) = 1 THEN captured_profit ELSE 0 END) AS January, SUM(CASE WHEN MONTH(date) = 2 THEN captured_profit ELSE 0 END) AS February, SUM(CASE WHEN MONTH(date) = 3 THEN captured_profit ELSE 0 END) AS March, SUM(CASE WHEN MONTH(date) = 4 THEN captured_profit ELSE 0 END) AS April, SUM(CASE WHEN MONTH(date) = 5 THEN captured_profit ELSE 0 END) AS May, SUM(CASE WHEN MONTH(date) = 6 THEN captured_profit ELSE 0 END) AS June, SUM(CASE WHEN MONTH(date) = 7 THEN captured_profit ELSE 0 END) AS July, SUM(CASE WHEN MONTH(date) = 8 THEN captured_profit ELSE 0 END) AS August, SUM(CASE WHEN MONTH(date) = 9 THEN captured_profit ELSE 0 END) AS September, SUM(CASE WHEN MONTH(date) = 10 THEN captured_profit ELSE 0 END) AS October, SUM(CASE WHEN MONTH(date) = 11 THEN captured_profit ELSE 0 END) AS November, SUM(CASE WHEN MONTH(date) = 12 THEN captured_profit ELSE 0 END) AS December, SUM(captured_profit) AS Total, YEAR(date) from me where id is not null group by YEAR(date)
Upvotes: 1
Reputation: 562260
Aggregate functions like SUM() ignore NULLs. So use an expression to make the profit value NULL unless it falls within the range you want.
SELECT
id AS name,
SUM(CASE WHEN MONTH(date) = 1 THEN captured_profit END) AS January,
SUM(CASE WHEN MONTH(date) = 2 THEN captured_profit END) AS February,
SUM(CASE WHEN MONTH(date) = 3 THEN captured_profit END) AS March,
SUM(CASE WHEN MONTH(date) = 4 THEN captured_profit END) AS April,
SUM(CASE WHEN MONTH(date) = 5 THEN captured_profit END) AS May,
SUM(CASE WHEN MONTH(date) = 6 THEN captured_profit END) AS June,
SUM(CASE WHEN MONTH(date) = 7 THEN captured_profit END) AS July,
SUM(CASE WHEN MONTH(date) = 8 THEN captured_profit END) AS August,
SUM(CASE WHEN MONTH(date) = 9 THEN captured_profit END) AS September,
SUM(CASE WHEN MONTH(date) = 10 THEN captured_profit END) AS October,
SUM(CASE WHEN MONTH(date) = 11 THEN captured_profit END) AS November,
SUM(CASE WHEN MONTH(date) = 12 THEN captured_profit END) AS December,
SUM(captured_profit) AS Total
FROM me
WHERE id IS NOT NULL AND YEAR(date) = 2017
GROUP BY id;
The CASE
expression returns NULL if there's no match and no ELSE
clause. Read https://dev.mysql.com/doc/refman/5.7/en/case.html for more details.
This query eliminates all the correlated subqueries. The query will scan through the table just once.
I don't know what the meaning of your "Total" is in your query, but it appears to be just November + December. I'm not sure if that's what you intended.
Edit: I fixed the expression for Total.
Upvotes: 1
Reputation: 73221
Simply group by year, month and id
select id, sum(captured_profit), month( `date`)
from me
where id is not null and `date` > '2016-12-31'
group by year(`date`), month(`date`), id;
I guess you didn't use all the keywords (name, date) as your actual column names, if you did make sure to put them in backticks in every query.
Upvotes: 1
Reputation: 450
I think this is exactly what you are looking for
http://www.w3resource.com/mysql/date-and-time-functions/mysql-monthname-function.php
MySQL MONTHNAME() returns the full name of the month for a given date. The return value is within the range of 1 to 12 ( January to December). It Returns NULL when month part for the date is 0 or more than 12
Syntax :
MONTHNAME(date1)
Upvotes: 0