Aggregate MySQL Queries - mysql

Aggregate below queries
1.
SELECT business_id_fk,business_name,
IFNULL(count(orderid_customer),0) AS total,
IFNULL(sum(CASE WHEN order_status IN ('CRD') THEN 1 ELSE 0
END), 0) AS crude,
IFNULL(sum(CASE WHEN order_status IN ('UNA') THEN 1 ELSE 0
END), 0) AS unassigned,
IFNULL(sum(CASE WHEN order_status IN ('DEL' , 'MCP' , 'CMP')
THEN 1 ELSE 0 END), 0) AS delivered,
IFNULL(sum(CASE WHEN order_status IN ('CNL') THEN 1 ELSE 0
END), 0) AS cancelled,
IFNULL(sum(CASE WHEN order_status IN ( 'CAP' , 'CAD' , 'RSP' ,
'RSD') THEN 1 ELSE 0 END), 0) AS postponed,
IFNULL(SUM(total), 0) AS 'Estimated_Revenue',
IFNULL(SUM(CASE WHEN order_status IN ('DEL' , 'MCP', 'CMP')
THEN total ELSE 0 END), 0) AS 'Generated_Revenue'
FROM view_orders where order_datetime between '2017-08-01
00:00:00' and '2017-10-17 23:59:59' and parent_id IS NULL
GROUP BY business_id_fk ORDER BY total DESC;
2.
SELECT A.business_id_fk,A.business_name,ifnull(((A.TotalPrice /
A.TotalQuantity)*100),0) AS 'sla_adherence' FROM (SELECT
business_id_fk,business_name,
sum(sla_del_datetime > delivery_datetime) AS TotalPrice
,sum(order_status in('DEL','MCP','CMP')) AS TotalQuantity
FROM view_orders where parent_id is null and order_datetime between '2017-
08-01 00:00:00' and '2017-10-17 23:59:59'
GROUP BY business_id_fk) AS A;
3.
SELECT A.business_id_fk,A.business_name,ifnull(((A.Totaldelivered /
A.Totalorders)*100),0) AS 'strike_rate' FROM (SELECT
business_id_fk,business_name,
sum(order_status in('DEL','MCP','CMP')) AS Totaldelivered
, count(*) AS Totalorders
FROM view_orders where parent_id is null and order_datetime between '2017-
08-01 00:00:00' and '2017-10-17 23:59:59'
GROUP BY business_id_fk) AS A;
To get the result like
Business_id_fk BusinessName Total Delivered Unassigned Cancelled Postponed EstimatedRevenue GeneratedRevenue SLAadherance Strikerate
2 DEF 10 5 2 1 0 200 100 100 50
1 ABC 20 10 4 2 0 200 100 100 50
Null Null 10 10 0 0 0 100 100 100 100
Here business name having null is Individual customer Orders(non-business orders).
Thank you in advance :-)

Like this:
SELECT
business_id_fk,business_name,
total,
crude,
unassigned,
delivered,
cancelled,
postponed,
Estimated_Revenue,
Generated_Revenue,
TotalPrice,
Totaldelivered,
Totalorders,
ifnull(((TotalPrice / TotalQuantity)*100),0) AS 'sla_adherence',
ifnull(((Totaldelivered / Totalorders)*100),0) AS 'strike_rate'
FROM
(
SELECT
business_id_fk,business_name,
IFNULL(count(orderid_customer),0) AS total,
IFNULL(sum(CASE WHEN order_status IN ('CRD') THEN 1 ELSE 0 END), 0) AS crude,
IFNULL(sum(CASE WHEN order_status IN ('UNA') THEN 1 ELSE 0 END), 0) AS unassigned,
IFNULL(sum(CASE WHEN order_status IN ('DEL' , 'MCP' , 'CMP') THEN 1 ELSE 0 END), 0) AS delivered,
IFNULL(sum(CASE WHEN order_status IN ('CNL') THEN 1 ELSE 0 END), 0) AS cancelled,
IFNULL(sum(CASE WHEN order_status IN ( 'CAP' , 'CAD' , 'RSP' , 'RSD') THEN 1 ELSE 0 END), 0) AS postponed,
IFNULL(SUM(total), 0) AS 'Estimated_Revenue',
IFNULL(SUM(CASE WHEN order_status IN ('DEL' , 'MCP', 'CMP') THEN total ELSE 0 END), 0) AS 'Generated_Revenue',
sum(sla_del_datetime > delivery_datetime) AS TotalPrice,
sum(order_status in('DEL','MCP','CMP')) AS TotalQuantity,
sum(order_status in('DEL','MCP','CMP')) AS Totaldelivered,
count(*) AS Totalorders
FROM view_orders
where order_datetime between '2017-08-01 00:00:00' and '2017-10-17 23:59:59'
and parent_id IS NULL
GROUP BY business_id_fk
) AS A
ORDER BY total DESC;

Related

Can I optimize this UNION query? [duplicate]

This question already has answers here:
How do I create an SQL query that groups by value ranges
(7 answers)
Closed 1 year ago.
Hello I'm taking some data from my db and I want to get this output:
How many times I have an amount less then 100€ (inbound, outbound and inner)
How many times I have an amount between 100 and 500€ (inbound, outbound and inner)
How many times I have an amount between 500 and 2000€ (inbound, outbound and inner)
...
How many times I have an amount greater then 200000€ (inbound, outbound and inner)
I can obtain this with this query:
SELECT
'< 100 €' as amount,
SUM(CASE WHEN direction = 'inbound' AND to_address is null THEN 1 ELSE 0 END) AS inbound,
SUM(CASE WHEN direction = 'outbound' AND to_address is null THEN 1 ELSE 0 END) AS outbound,
SUM(CASE WHEN to_address is not null THEN 1 ELSE 0 END) AS inside
FROM user_wallet_movement
WHERE
(amount*base_rate) < 100
AND status = 'execute'
AND mov_date > '2020-01-07'
AND mov_date < '2021-06-30'
UNION
SELECT
'100 ... 500 €' as amount,
SUM(CASE WHEN direction = 'inbound' AND to_address is null THEN 1 ELSE 0 END) AS inbound,
SUM(CASE WHEN direction = 'outbound' AND to_address is null THEN 1 ELSE 0 END) AS outbound,
SUM(CASE WHEN to_address is not null THEN 1 ELSE 0 END) AS inside
FROM user_wallet_movement
WHERE
(amount*base_rate) > 100 AND (amount*base_rate) < 500
AND status = 'execute'
AND mov_date > '2020-01-07'
AND mov_date < '2021-06-30'
UNION
SELECT
'500 ... 2000 €' as amount,
SUM(CASE WHEN direction = 'inbound' AND to_address is null THEN 1 ELSE 0 END) AS inbound,
SUM(CASE WHEN direction = 'outbound' AND to_address is null THEN 1 ELSE 0 END) AS outbound,
SUM(CASE WHEN to_address is not null THEN 1 ELSE 0 END) AS inside
FROM user_wallet_movement
WHERE
(amount*base_rate) > 500 AND (amount*base_rate) < 2000
AND status = 'execute'
AND mov_date > '2020-01-07'
AND mov_date < '2021-06-30'
UNION
SELECT
'2000 ... 10000 €' as amount,
SUM(CASE WHEN direction = 'inbound' AND to_address is null THEN 1 ELSE 0 END) AS inbound,
SUM(CASE WHEN direction = 'outbound' AND to_address is null THEN 1 ELSE 0 END) AS outbound,
SUM(CASE WHEN to_address is not null THEN 1 ELSE 0 END) AS inside
FROM user_wallet_movement
WHERE
(amount*base_rate) > 2000 AND (amount*base_rate) < 10000
AND status = 'execute'
AND mov_date > '2020-01-07'
AND mov_date < '2021-06-30'
UNION
SELECT
'10000 ... 50000 €' as amount,
SUM(CASE WHEN direction = 'inbound' AND to_address is null THEN 1 ELSE 0 END) AS inbound,
SUM(CASE WHEN direction = 'outbound' AND to_address is null THEN 1 ELSE 0 END) AS outbound,
SUM(CASE WHEN to_address is not null THEN 1 ELSE 0 END) AS inside
FROM user_wallet_movement
WHERE
(amount*base_rate) > 10000 AND (amount*base_rate) < 50000
AND status = 'execute'
AND mov_date > '2020-01-07'
AND mov_date < '2021-06-30'
UNION
SELECT
'50000 ... 200000 €' as amount,
SUM(CASE WHEN direction = 'inbound' AND to_address is null THEN 1 ELSE 0 END) AS inbound,
SUM(CASE WHEN direction = 'outbound' AND to_address is null THEN 1 ELSE 0 END) AS outbound,
SUM(CASE WHEN to_address is not null THEN 1 ELSE 0 END) AS inside
FROM user_wallet_movement
WHERE
(amount*base_rate) > 50000 AND (amount*base_rate) < 200000
AND status = 'execute'
AND mov_date > '2020-01-07'
AND mov_date < '2021-06-30'
UNION
SELECT
'> 200000 €' as amount,
SUM(CASE WHEN direction = 'inbound' AND to_address is null THEN 1 ELSE 0 END) AS inbound,
SUM(CASE WHEN direction = 'outbound' AND to_address is null THEN 1 ELSE 0 END) AS outbound,
SUM(CASE WHEN to_address is not null THEN 1 ELSE 0 END) AS inside
FROM user_wallet_movement
WHERE
(amount*base_rate) > 200000
AND status = 'execute'
AND mov_date > '2020-01-07'
AND mov_date < '2021-06-30'
As you can see the conditions are all the same, the only thing that changes is the condition on (amount*base_rate).
Is there a way to optimize this?
Thank you
Thanks to #user202729's comment I got the solution
SELECT
Conds.Description,
SUM(CASE WHEN direction = 'inbound' AND to_address is null THEN 1 ELSE 0 END) AS inbound,
SUM(CASE WHEN direction = 'outbound' AND to_address is null THEN 1 ELSE 0 END) AS outbound,
SUM(CASE WHEN to_address is not null THEN 1 ELSE 0 END) AS inside
FROM user_wallet_movement uwm
JOIN (
SELECT '< 100' AS Description, 0 AS min, 100 AS max
UNION ALL
SELECT '100 ... 500' AS Description, 100 AS min, 500 AS max
UNION ALL
SELECT '500 ... 2000' AS Description, 500 AS min, 2000 AS max
UNION ALL
SELECT '2000 ... 10000' AS Description, 2000 AS min, 10000 AS max
UNION ALL
SELECT '10000 ... 50000' AS Description, 10000 AS min, 50000 AS max
UNION ALL
SELECT '50000 ... 200000' AS Description, 50000 AS min, 200000 AS max
UNION ALL
SELECT '> 200000' AS Description, 200000 AS min, 9999999999 AS max
) as Conds ON (uwm.amount*uwm.base_rate) >= min AND (uwm.amount*uwm.base_rate) < Conds.max
WHERE uwm.status = 'execute'
AND uwm.mov_date > '2020-01-07'
AND uwm.mov_date < '2021-06-30'
GROUP BY Conds.Description
If this is going to be a frequent query and the date range is likely to change, then build and maintain a summary table.
Such a table would have (perhaps) one row per day and status. The columns would be counts for each amount range.
Each night, update the table with the previous day's counts.
Then write the query to reach into the summary table; it will be a lot faster.
More: http://mysql.rjweb.org/doc.php/summarytables

MySQL query that returns amount of contacts per day of week in subquery

I'm trying to come up with a query that enables me to select the amount of contacts a employee has had, per day of week.
I came up with the following, but it returns 0,0,0,0,0 for each day and each employee.
SELECT
#emp := A.id,
A.first_name,
(
SELECT
CONCAT_WS(',', mo, tu, we, th, fr)
FROM
(
SELECT
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 0 THEN 1 ELSE 0 END), 0) AS mo,
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 1 THEN 1 ELSE 0 END), 0) AS tu,
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 2 THEN 1 ELSE 0 END), 0) AS we,
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 3 THEN 1 ELSE 0 END), 0) AS th,
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 4 THEN 1 ELSE 0 END), 0) AS fr
FROM
`contacts` AS B
WHERE
B.user_id = #emp
AND
YEAR(B.contact_date) = 2018
AND
WEEK(B.contact_date) = 2
) q
) AS call_attempts
FROM
`users` AS A
WHERE
A.deactivated = 0
AND
A.type = 1
ORDER BY
A.first_name
Fiddle: http://sqlfiddle.com/#!9/4f682c/7

Combining multiple queries of single view in one query

I am struggling with multiple queries to combine in one query, all these are retrieving from single view for a same date range for all queries i.e.
SELECT business_id_fk,business_name,
IFNULL(count(orderid_customer),0) AS total,
IFNULL(sum(CASE WHEN order_status IN ('CRD') THEN 1 ELSE 0 END), 0) AS crude,
IFNULL(sum(CASE WHEN order_status IN ('UNA') THEN 1 ELSE 0 END), 0) AS unassigned,
IFNULL(sum(CASE WHEN order_status IN ('DEL' , 'MCP' , 'CMP') THEN 1 ELSE 0 END), 0) AS delivered,
IFNULL(sum(CASE WHEN order_status IN ('CNL') THEN 1 ELSE 0 END), 0) AS cancelled,
IFNULL(sum(CASE WHEN order_status IN ( 'CAP' , 'CAD' , 'RSP' , 'RSD') THEN 1 ELSE 0 END), 0) AS postponed
FROM view_orders where order_datetime between '2017-10-01 00:00:00' and '2017-10-05 23:59:59' and parent_id IS NULL
AND business_id_fk is not null GROUP BY business_id_fk ORDER BY total DESC;
The above query is to get business wise count
SELECT business_id_fk,business_name,
IFNULL(count(orderid_customer),0) AS total,
IFNULL(sum(CASE WHEN order_status IN ('CRD') THEN 1 ELSE 0 END), 0) AS crude,
IFNULL(sum(CASE WHEN order_status IN ('UNA') THEN 1 ELSE 0 END), 0) AS unassigned,
IFNULL(sum(CASE WHEN order_status IN ('DEL' , 'MCP' , 'CMP') THEN 1 ELSE 0 END), 0) AS delivered,
IFNULL(sum(CASE WHEN order_status IN ('CNL') THEN 1 ELSE 0 END), 0) AS cancelled,
IFNULL(sum(CASE WHEN order_status IN ( 'CAP' , 'CAD' , 'RSP' , 'RSD') THEN 1 ELSE 0 END), 0) AS postponed,
IFNULL(SUM(total), 0) AS 'Estimated_Revenue',
IFNULL(SUM(CASE WHEN order_status IN ('DEL' , 'MCP', 'CMP') THEN total ELSE 0 END), 0) AS 'Generated_Revenue'
FROM view_orders
WHERE order_datetime between '2017-10-01 00:00:00' and '2017-10-05 23:59:59'
AND parent_id IS NULL
AND business_id_fk is null
ORDER BY total DESC;
This is to get the count of business_id_fk having null values
select ((SELECT ifnull(count(*),0) as 'total' FROM view_orders where (sla_del_datetime > delivery_datetime) and order_datetime between '2017-10-01 00:00:00' and '2017-10-05 23:59:59' and parent_id is null group by business_id_fk) / (SELECT ifnull(count(*),0) as 'total' FROM view_orders where order_status in('DEL','MCP','CMP') order_datetime between '2017-10-01 00:00:00' and '2017-10-05 23:59:59' and and parent_id is null group by business_id_fk)*100) as 'sla_adherence';
This query is to get sla_adherence of each business wise and non business
select ((SELECT ifnull(count(*),0) as 'total' FROM view_orders where order_status in('DEL','MCP','CMP') order_datetime between '2017-10-01 00:00:00' and '2017-10-05 23:59:59' and and parent_id is null group by business_id_fk) / (SELECT ifnull(count(*),0) as 'total' FROM view_orders where order_datetime between '2017-10-01 00:00:00' and '2017-10-05 23:59:59' and parent_id is null group by business_id_fk)*100) as 'strike_rate';
This query is to get strike_rate of each business wise and non business
I want the result like
business_id_fk||business_name||total||crude||unassigned||delivered||cancelled||postponed||Estimated_Revenue||Generated_Revenue||sla_adherence||strike_rate
1||abc||10||1||..|..|..|..|..|..|..|..|..|x.xx|x.xx
.
.
.
null(non business)||null||..|..|. . . . . . |x.xx|x.xx
each business wise rows for all the above fields and for non business.
Thank you in advance.
One first query is multi-row, the second seems to be a single value. So if those assumptions are right you could try a cross join:
SELECT
business_id_fk
, business_name
, IFNULL(count(orderid_customer),0) AS total
, IFNULL(sum(CASE WHEN order_status IN ('CRD') THEN 1 ELSE 0 END), 0) AS crude
, IFNULL(sum(CASE WHEN order_status IN ('UNA') THEN 1 ELSE 0 END), 0) AS unassigned
, IFNULL(sum(CASE WHEN order_status IN ('DEL' , 'MCP' , 'CMP') THEN 1 ELSE 0 END), 0) AS delivered
, IFNULL(sum(CASE WHEN order_status IN ('CNL') THEN 1 ELSE 0 END), 0) AS cancelled
, IFNULL(sum(CASE WHEN order_status IN ( 'CAP' , 'CAD' , 'RSP' , 'RSD') THEN 1 ELSE 0 END), 0) AS postponed
, cj.sla_adherence
FROM view_orders
CROSS JOIN (
SELECT (
(SELECT ifnull(count(*),0) FROM view_orders where (sla_del_datetime > delivery_datetime) and parent_id is null )
/
(SELECT ifnull(count(*),0) FROM view_orders where order_status in('DEL','MCP','CMP') and parent_id is null )*100.0
) as 'sla_adherence'
) cj
WHERE order_datetime between '2017-08-01 00:00:00' and '2017-10-01 23:59:59'
GROUP BY business_id_fk, business_name, cj.sla_adherence
ORDER BY total DESC
;

How can I make this SQL query more elegant?

This is my MySQL query for getting count values...
SELECT 1 AS id,
'2016' AS Year,
MAX( IF( Month = '01', Count, 0 ) ) AS 'VAL01',
MAX( IF( Month = '02', Count, 0 ) ) AS 'VAL02',
MAX( IF( Month = '03', Count, 0 ) ) AS 'VAL03',
MAX( IF( Month = '04', Count, 0 ) ) AS 'VAL04',
MAX( IF( Month = '05', Count, 0 ) ) AS 'VAL05',
MAX( IF( Month = '06', Count, 0 ) ) AS 'VAL06',
MAX( IF( Month = '07', Count, 0 ) ) AS 'VAL07',
MAX( IF( Month = '08', Count, 0 ) ) AS 'VAL08',
MAX( IF( Month = '09', Count, 0 ) ) AS 'VAL09',
MAX( IF( Month = '10', Count, 0 ) ) AS 'VAL10',
MAX( IF( Month = '11', Count, 0 ) ) AS 'VAL11',
MAX( IF( Month = '12', Count, 0 ) ) AS 'VAL12',
SUM( Count ) AS Total
FROM ( SELECT DATE_FORMAT( created_at, '%m' ) AS Month,
COUNT( 1 ) AS Count
FROM reservations
WHERE DATE_FORMAT( created_at, '%Y' ) = '2016'
GROUP BY DATE_FORMAT( created_at, '%m' )
) AS T1
UNION
SELECT 2 AS id,
'2017' AS Year,
MAX( IF( Month = '01', Count, 0 ) ) AS 'VAL01',
MAX( IF( Month = '02', Count, 0 ) ) AS 'VAL02',
MAX( IF( Month = '03', Count, 0 ) ) AS 'VAL03',
MAX( IF( Month = '04', Count, 0 ) ) AS 'VAL04',
MAX( IF( Month = '05', Count, 0 ) ) AS 'VAL05',
MAX( IF( Month = '06', Count, 0 ) ) AS 'VAL06',
MAX( IF( Month = '07', Count, 0 ) ) AS 'VAL07',
MAX( IF( Month = '08', Count, 0 ) ) AS 'VAL08',
MAX( IF( Month = '09', Count, 0 ) ) AS 'VAL09',
MAX( IF( Month = '10', Count, 0 ) ) AS 'VAL10',
MAX( IF( Month = '11', Count, 0 ) ) AS 'VAL11',
MAX( IF( Month = '12', Count, 0 ) ) AS 'VAL12',
SUM( Count ) AS Total
FROM ( SELECT DATE_FORMAT( created_at, '%m' ) AS Month,
COUNT( 1 ) AS Count
FROM reservations
WHERE DATE_FORMAT( created_at, '%Y' ) = '2017'
GROUP BY DATE_FORMAT( created_at, '%m' )
) AS T2
It returns (for example)...
+----+------+-------+-------+-------+-------+-------+-------+-----+-------+-------+
| id | Year | VAL01 | VAL02 | VAL03 | VAL04 | VAL05 | VAL06 | ... | VAL12 | Total |
+----+------+-------+-------+-------+-------+-------+-------+-----+-------+-------+
| 1 | 2016 | 0 | 0 | 150 | 190 | 200 | 220 | ... | 160 | 1242 |
+----+------+-------+-------+-------+-------+-------+-------+-----+-------+-------+
| 2 | 2017 | 300 | 300 | 600 | 600 | 700 | 0 | ... | 0 | 2500 |
+----+------+-------+-------+-------+-------+-------+-------+-----+-------+-------+
My query has many problems. It can't use the year 2018 and it should use UNION again and again.
How can I make my SQL query more beautiful?
Try this
select
date_format(created_at,'%Y') as Year,
sum(case when date_format(created_at,'%m')='01' then 1 else 0 end) as val01,
sum(case when date_format(created_at,'%m')='02' then 1 else 0 end) as val02,
sum(case when date_format(created_at,'%m')='03' then 1 else 0 end) as val03,
sum(case when date_format(created_at,'%m')='04' then 1 else 0 end) as val04,
sum(case when date_format(created_at,'%m')='05' then 1 else 0 end) as val05,
sum(case when date_format(created_at,'%m')='06' then 1 else 0 end) as val06,
sum(case when date_format(created_at,'%m')='07' then 1 else 0 end) as val07,
sum(case when date_format(created_at,'%m')='08' then 1 else 0 end) as val08,
sum(case when date_format(created_at,'%m')='09' then 1 else 0 end) as val09,
sum(case when date_format(created_at,'%m')='10' then 1 else 0 end) as val10,
sum(case when date_format(created_at,'%m')='11' then 1 else 0 end) as val11,
sum(case when date_format(created_at,'%m')='12' then 1 else 0 end) as val12,
count(*) as total
from reservations
group by date_format(created_at,'%Y')
You can try with below query
SELECT YEAR,SUM(VAL01) VAL02,SUM(VAL02) VAL02,SUM(VAL03) VAL3
FROM
(
SELECT date_format(created_at,'%Y') YEAR,
CASE WHEN date_format(created_at,'%m')=1 THEN 1 ELSE 0 END AS VAL01,
CASE WHEN date_format(created_at,'%m')=2 THEN 1 ELSE 0 END AS VAL02,
CASE WHEN date_format(created_at,'%m')=3 THEN 1 ELSE 0 END AS VAL03
FROM reservations
)t
GROUP BY YEAR
Hope this will helps.
If this had been Oracle, you could have used Function based index on column Created_at and using the same function (EXTRACT in this case) in your query:
CREATE INDEX IDX1 ON RESERVATIONS (EXTRACT(YEAR FROM CREATED_AT))
Since, this is MySQL, try using this as alternative. Make sure after creating the index, it is getting used by verifying the Query plan.
You could try this query
SELECT id,
Year,
SUM(CASE WHEN Month='01' THEN MonthCount ELSE 0 END) AS 'VAL01',
SUM(CASE WHEN Month='02' THEN MonthCount ELSE 0 END) AS 'VAL02',
SUM(CASE WHEN Month='03' THEN MonthCount ELSE 0 END) AS 'VAL03',
SUM(CASE WHEN Month='04' THEN MonthCount ELSE 0 END) AS 'VAL04',
SUM(CASE WHEN Month='05' THEN MonthCount ELSE 0 END) AS 'VAL05',
SUM(CASE WHEN Month='06' THEN MonthCount ELSE 0 END) AS 'VAL06',
SUM(CASE WHEN Month='07' THEN MonthCount ELSE 0 END) AS 'VAL07',
SUM(CASE WHEN Month='08' THEN MonthCount ELSE 0 END) AS 'VAL08',
SUM(CASE WHEN Month='09' THEN MonthCount ELSE 0 END) AS 'VAL09',
SUM(CASE WHEN Month='10' THEN MonthCount ELSE 0 END) AS 'VAL10',
SUM(CASE WHEN Month='11' THEN MonthCount ELSE 0 END) AS 'VAL11',
SUM(CASE WHEN Month='12' THEN MonthCount ELSE 0 END) AS 'VAL12',
SUM(MonthCount) AS Total
FROM (
SELECT
CASE
WHEN Date_format(created_at, '%Y') = '2016' THEN 1
WHEN Date_format(created_at, '%Y') = '2017' THEN 2
WHEN Date_format(created_at, '%Y') = '2018' THEN 3
END AS id,
Date_format(created_at, '%Y') AS Year,
Date_format(created_at, '%m') AS Month,
COUNT(1) AS MonthCount
FROM reservations
WHERE Date_format(created_at, '%Y') IN ('2016', '2017', '2018')
GROUP BY Date_format(created_at, '%Y-%m')) AS ByMonth
GROUP BY id, Year

SQL subquery in query

I have a table with payment:
worker_id, amount, payed, date
Table workers:
id, name, lname
I need to write SQL that will give me name, lname and sum for jun, july, august, september.
Name | Lname | Sum_JUN | Sum_JULY | Sum_AUG | Sum_SEP
I'm trying with subqueries but can't do it. Can you help me?
I created SQL (example). I will replace dates in PHP.
select w.name, w.lname,
sum(case when p.payed_date between '2014-06-01' and '2014-06-31' then p.amount else 0 end) `sum_june`,
sum(case when p.payed_date between '2014-07-01' and '2014-07-31' then p.amount else 0 end) `sum_july`,
sum(case when p.payed_date between '2014-08-01' and '2014-08-31' then p.amount else 0 end) `sum_august`,
sum(case when p.payed_date between '2014-09-01' and '2014-09-31' then p.amount else 0 end) `sum_september`,
sum(case when p.payed_date between '2014-10-01' and '2014-10-31' then p.amount else 0 end) `sum_november`
from worker w
left join worker_sum p on(w.id = p.worker_id)
group by w.id
You can use conditional aggregation for your desired sum,But this will give you the sum for months from all years exist in your table
select w.*,
sum(case when month(p.date) = 6 then p.amount else 0 end) `sum_june`,
sum(case when month(p.date) = 7 then p.amount else 0 end) `sum_july`,
sum(case when month(p.date) = 8 then p.amount else 0 end) `sum_august`,
sum(case when month(p.date) = 9 then p.amount else 0 end) `sum_september`
from workers w
left join payment p on(w.id = p.worker_id)
group by w.id