SQL grouping: Creating monthly columns with grouped data - mysql

I have the following mySQL query which generates a table listing the individual failure data and groups by the month and frequency of different types of failures.
SELECT (CASE WHEN MONTH(runtable.time) = 1 THEN 'Jan'
WHEN MONTH(runtable.time) = 2 THEN 'FEB'
WHEN MONTH(runtable.time) = 3 THEN 'MAR'
WHEN MONTH(runtable.time) = 4 THEN 'APR'
WHEN MONTH(runtable.time) = 5 THEN 'MAY'
WHEN MONTH(runtable.time) = 6 THEN 'JUN'
WHEN MONTH(runtable.time) = 7 THEN 'JUL'
WHEN MONTH(runtable.time) = 8 THEN 'AUG'
WHEN MONTH(runtable.time) = 9 THEN 'SEP'
WHEN MONTH(runtable.time) = 10 THEN 'OCT'
WHEN MONTH(runtable.time) = 11 THEN 'NOV'
WHEN MONTH(runtable.time) = 12 THEN 'DEC'
ELSE 'Error' END) as date_month, runtable.operation, pareto.failure
FROM runtable
JOIN pareto ON pareto.run_id = runtable.id
WHERE runtable.time BETWEEN '2016-01-01 00:00:00' AND '2016-12-13 23:59:59'
AND runtable.operation IN ('d','hr')
GROUP BY MONTH(runtable.time), pareto.failure
ORDER BY MONTH(runtable.time) desc, n desc;
I would like to be able to have the months as separate columns in in the table along with the total for the year, but am unaware of how to do this. My current issue is the only way I have tried of doing this involves using sum or case for each month but then I am unable to group the count of different failure types together for each month.

The way is exactly what you described: you need to use CASE WHEN and SUM functions to solve this. Take a look at this thread:
how to select 2 table like this
By the way, you have easier ways to describe months without a case function as your example code. Take a look:
MySQL DATE_FORMAT() Function
Something like: select DATE_FORMAT(now(),'%m')
I didn't understand your problem with the error column. Be specify what problems are you run into.
Good luck!

As far as I understand you're looking for the sum(pareto.failues) by month of each operation.
Check it here: http://rextester.com/MTDK27603
SELECT
runtable.operation,
pareto.failure,
COUNT(CASE WHEN MONTH(runtable.time) = 1 THEN 1 else NULL end) as 'Jan',
COUNT(CASE WHEN MONTH(runtable.time) = 2 THEN 1 else NULL end) as 'Feb',
COUNT(CASE WHEN MONTH(runtable.time) = 3 THEN 1 else NULL end) as 'Mar',
COUNT(CASE WHEN MONTH(runtable.time) = 4 THEN 1 else NULL end) as 'Apr',
COUNT(CASE WHEN MONTH(runtable.time) = 5 THEN 1 else NULL end) as 'May',
COUNT(CASE WHEN MONTH(runtable.time) = 6 THEN 1 else NULL end) as 'Jun',
COUNT(CASE WHEN MONTH(runtable.time) = 7 THEN 1 else NULL end) as 'Jul',
COUNT(CASE WHEN MONTH(runtable.time) = 8 THEN 1 else NULL end) as 'Aug',
COUNT(CASE WHEN MONTH(runtable.time) = 9 THEN 1 else NULL end) as 'Sep',
COUNT(CASE WHEN MONTH(runtable.time) = 10 THEN 1 else NULL end) as 'Oct',
COUNT(CASE WHEN MONTH(runtable.time) = 11 THEN 1 else NULL end) as 'Nov',
COUNT(CASE WHEN MONTH(runtable.time) = 12 THEN 1 else NULL end) as 'Dec',
COUNT(pareto.failure) as 'Total year'
FROM
runtable
JOIN pareto
ON pareto.run_id = runtable.id
WHERE
runtable.time BETWEEN '2016-01-01 00:00:00' AND '2016-12-13 23:59:59'
AND runtable.operation IN ('d','hr')
GROUP BY
runtable.operation, pareto.failure
;

Related

Mysql - Payments table by month column

I'm struggling - I have a table payments
Date
Ref
1.1.22
1
1.2.22
2
1.3.22
1
1.4.22
3
1.3.22
2
1.2.22
3
and a table of ref
Name
Ref
jo
1
Steve
2
Chris
3
I'm trying to get my sql to state
Name
Jan
Feb
Mar
Apr
Jo
Paid
Not
Paid
Not
Chris
Not
Paid
Not
Paid
Etc, so far I can but each name has one line for each month, when I want them in one row
`SELECT m.memID,m.Pay_Ref, p.ref,
(case when MONTHNAME(p.DATE) = 'January' then 'Paid' else 'Not' end) as January,
(case when MONTHNAME(p.DATE) = 'February' then 'Paid' else 'Not' end) as February,
(case when MONTHNAME(p.DATE) = 'March' then 'Paid' else 'Not' end) as March,
(case when MONTHNAME(p.DATE) = 'April' then 'Paid' else 'Not' end) as April,
(case when MONTHNAME(p.DATE) = 'May' then 'Paid' else 'Not' end) as May,
(case when MONTHNAME(p.DATE) = 'June' then 'Paid' else 'Not' end) as June,
(case when MONTHNAME(p.DATE) = 'July' then 'Paid' else 'Not' end) as July,
(case when MONTHNAME(p.DATE) = 'August' then 'Paid' else 'Not' end) as August,
(case when MONTHNAME(p.DATE) = 'September' then 'Paid' else 'Not' end) as September,
(case when MONTHNAME(p.DATE) = 'October' then 'Paid' else 'Not' end) as October,
(case when MONTHNAME(p.DATE) = 'November' then 'Paid' else 'Not' end) as November,
(case when MONTHNAME(p.DATE) = 'December' then 'Paid' else 'Not' end) as December
FROM Members AS m
INNER JOIN AllPayments AS p ON m.Pay_Ref = p.ref`

count new users by each months in sql

i am trying to count new users recorded by each month of this year.
like
Need data month wise, which is registerd by month new users
JAn Feb Mar April May ..... Dec
1 2 4 2 5 ..... 1
through created_at date and user Id.
here is user_table
id created_at
1 2020-01-09 22:38:55
2 2020-02-09 22:38:55
3 2020-02-09 22:38:55
4 2020-03-09 22:38:55
5 2020-03-09 22:38:55
6 2020-03-09 22:38:55
7 2020-04-09 22:38:55
8 2020-04-09 22:38:55
9 2020-05-09 22:38:55
i am trying with this query
SELECT ut.id, Month(FROM_UNIXTIME(ut.created_at)), Count(*)
from $userTable ut
where FROM_UNIXTIME(ut.created_at) >= CURDATE() - INTERVAL 1 YEAR
GROUP BY Month(FROM_UNIXTIME(ut.created_at));
You can group by year and sum by month like this:
select YEAR(created_at) as year,
sum(case when Month(created_at) = 1 then 1 else 0 end) AS Jan,
sum(case when Month(created_at) = 2 then 1 else 0 end) AS Feb,
sum(case when Month(created_at) = 3 then 1 else 0 end) AS Mar,
sum(case when Month(created_at) = 4 then 1 else 0 end) AS Apr,
sum(case when Month(created_at) = 5 then 1 else 0 end) AS May,
sum(case when Month(created_at) = 6 then 1 else 0 end) AS Jun,
sum(case when Month(created_at) = 7 then 1 else 0 end) AS Jul,
sum(case when Month(created_at) = 8 then 1 else 0 end) AS Aug,
sum(case when Month(created_at) = 9 then 1 else 0 end) AS Sep,
sum(case when Month(created_at) = 10 then 1 else 0 end) AS Oct,
sum(case when Month(created_at) = 11 then 1 else 0 end) AS Nov,
sum(case when Month(created_at) = 12 then 1 else 0 end) AS Dec from ut group by YEAR(created_at)
all columns that being used in the select that are not an aggregated function need to be grouped, ut.id is not group and in your case should be removed from the select
Try
SELECT Month(FROM_UNIXTIME(ut.created_at)), Count(*) from $userTable ut
where FROM_UNIXTIME(ut.created_at) >= CURDATE() - INTERVAL 1 YEAR
GROUP BY Month(FROM_UNIXTIME(ut.created_at));
If you want to mix data from this year and last year for the past 12 months, you can use:
SELECT SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 1) AS Jan,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 2) AS Feb,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 3) AS Mar,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 4) AS Apr,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 5) AS May,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 6) AS Jun,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 7) AS Jul,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 8) AS Aug,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 9) AS Sep,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 10) AS Oct,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 11) AS Nov,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 12) AS Dec
FROM ut
WHERE FROM_UNIXTIME(ut.created_at) >= CURDATE() - INTERVAL 1 YEAR
Note: This assumes that FROM_UNIXTIME() is a actually necessary. It also uses a convenient MySQL shortcut for conditional aggreation.

Mysql select based on other select

dears i have below query that's gets the count based on cases and it's working fine
select users.firstName,users.lastName,users.id,users.phoneNumber,
count(CASE
WHEN orders.`orderStatus` = 4 THEN 1 ELSE null END) As completed,
count(CASE
WHEN orders.`orderStatus` = 5 THEN 1 ELSE null END) as CustomerCancelled,
count(CASE
WHEN orders.`orderStatus` = 11 THEN 1 ELSE null END) as providerCancelled,
count(`orders`.`createdAt`) as total,
from users,providers,orders
where
`orders`.`providerId` = `providers`.`id`
and
users.id = `providers`.userId
and
`orders`.`createdAt` >= (CURDATE() - INTERVAL 7 DAY)
GROUP BY users.id;
what I need to add is to get the count for CustomerCancelled/total and show it with each record
I tried to divide it like below but not working
select users.firstName,users.lastName,users.id,users.phoneNumber,
count(CASE
WHEN orders.`orderStatus` = 4 THEN 1 ELSE null END) As completed,
count(CASE
WHEN orders.`orderStatus` = 5 THEN 1 ELSE null END) as CustomerCancelled,
count(CASE
WHEN orders.`orderStatus` = 11 THEN 1 ELSE null END) as providerCancelled,
count(`orders`.`createdAt`) as total,
CustomerCancelled/total //// this is what i tried to do
from users,providers,orders
where
`orders`.`providerId` = `providers`.`id`
and
users.id = `providers`.userId
and
`orders`.`createdAt` >= (CURDATE() - INTERVAL 7 DAY)
GROUP BY users.id;
You can't use aliases in the SELECT part of the query. You need to explicitly write out the expression:
select users.firstName,
users.lastName,
users.id,
users.phoneNumber,
COUNT(CASE WHEN orders.`orderStatus` = 4 THEN 1 END) aS completed,
COUNT(CASE WHEN orders.`orderStatus` = 5 THEN 1 END) AS CustomerCancelled,
COUNT(CASE WHEN orders.`orderStatus` = 11 THEN 1 END) AS providerCancelled,
COUNT(`orders`.`createdAt`) AS total,
COUNT(CASE WHEN orders.`orderStatus` = 5 THEN 1 END) / COUNT(`orders`.`createdAt`) AS ratio_cancelled
FROM users
JOIN providers
JOIN orders
WHERE `orders`.`providerId` = `providers`.`id`
AND users.id = `providers`.userId
AND `orders`.`createdAt` >= (CURDATE() - INTERVAL 7 DAY)
GROUP BY users.id;
Note that you don't need an ELSE null in your CASE expressions as that is the default. Also you should write explicit JOIN statements rather than use the deprecated comma style implicit JOIN.

MySQL select by month returns NULL for all months

Using MySQL 5.6 I am trying to select the total inspections for each month in the past 12 months with an output of 0 if there are none. I appear to be missing something here as the output is all NULL. The date_inspected field is just a regular SQL date
From what I understood, the structure should be [conditional statement, output variable, default value] but even the 0 gets ignored in favor of NULL. I am trying to understand what I am doing wrong here.
Table:
Column Type Null
id int(11) No
inspector_id int(11) Yes
company_id int(11) Yes
date_inspected date No
start_time datetime No
end_time datetime No
Query:
SELECT
SUM(IF(MONTH = 'Jan', total, 0)) AS 'Januari',
SUM(IF(MONTH = 'Feb', total, 0)) AS 'Februari',
SUM(IF(MONTH = 'Mar', total, 0)) AS 'Maart',
SUM(IF(MONTH = 'Apr', total, 0)) AS 'April',
SUM(IF(MONTH = 'May', total, 0)) AS 'Mei',
SUM(IF(MONTH = 'Jun', total, 0)) AS 'Juni',
SUM(IF(MONTH = 'Jul', total, 0)) AS 'Juli',
SUM(IF(MONTH = 'Aug', total, 0)) AS 'Augustus',
SUM(IF(MONTH = 'Sep', total, 0)) AS 'September',
SUM(IF(MONTH = 'Oct', total, 0)) AS 'Oktober',
SUM(IF(MONTH = 'Nov', total, 0)) AS 'November',
SUM(IF(MONTH = 'Dec', total, 0)) AS 'December',
SUM(total) AS all_months
FROM (
SELECT MONTH(date_inspected) AS MONTH, COUNT(*) AS total
FROM inspection
WHERE date_inspected BETWEEN NOW() AND Date_add(NOW(), interval - 12 month)
GROUP BY MONTH
) AS SubTable
Output
{ ["Januari"]=> NULL
["Februari"]=> NULL
["Maart"]=> NULL
["April"]=> NULL
["Mei"]=> NULL
["Juni"]=> NULL
["Juli"]=> NULL
["Augustus"]=> NULL
["September"]=> NULL
["Oktober"]=> NULL
["November"]=> NULL
["December"]=> NULL
["all_months"]=> NULL }
Update:
SOLUTION by Gordon Linoff
SELECT
SUM(CASE WHEN MONTH(date_inspected) = 1 THEN 1 ELSE 0 END) AS 'Januari',
SUM(CASE WHEN MONTH(date_inspected) = 2 THEN 1 ELSE 0 END) AS 'Februari',
SUM(CASE WHEN MONTH(date_inspected) = 3 THEN 1 ELSE 0 END) AS 'Maart',
SUM(CASE WHEN MONTH(date_inspected) = 4 THEN 1 ELSE 0 END) AS 'April',
SUM(CASE WHEN MONTH(date_inspected) = 5 THEN 1 ELSE 0 END) AS 'Mei',
SUM(CASE WHEN MONTH(date_inspected) = 6 THEN 1 ELSE 0 END) AS 'Juni',
SUM(CASE WHEN MONTH(date_inspected) = 7 THEN 1 ELSE 0 END) AS 'Juli',
SUM(CASE WHEN MONTH(date_inspected) = 8 THEN 1 ELSE 0 END) AS 'Augustus',
SUM(CASE WHEN MONTH(date_inspected) = 9 THEN 1 ELSE 0 END) AS 'September',
SUM(CASE WHEN MONTH(date_inspected) = 10 THEN 1 ELSE 0 END) AS 'Oktober',
SUM(CASE WHEN MONTH(date_inspected) = 11 THEN 1 ELSE 0 END) AS 'November',
SUM(CASE WHEN MONTH(date_inspected) = 12 THEN 1 ELSE 0 END) AS 'December'
FROM inspection
WHERE date_inspected BETWEEN Date_add(NOW(), interval - 12 month) AND NOW()
As I understand it, we've given the SUM() a conditional CASE statement that if the current record's date_inspected's MONTH is equal to the MySQL constant for that value, return true and add it to the total, else do nothing.
More on MySQL CASE
between must use the smaller value first and not the other way around. Change
BETWEEN NOW() AND Date_add(NOW(), interval - 12 month)
to
BETWEEN Date_add(NOW(), interval - 12 month) and NOW()
And month() returns a number of the month and not the name.
Juergen is correct on one problem in your query. Another is that MONTH() returns a number, not a string.
And, you can further simplify the query. A subquery is not needed:
SELECT SUM(CASE WHEN MONTH(date_inspected) = 1 THEN 1 ELSE 0 END)) AS 'Januari',
SUM(CASE WHEN MONTH(date_inspected) = 2 THEN 1 ELSE 0 END)) AS 'Februari',
. . .
FROM inspection
WHERE date_inspected BETWEEN Date_add(NOW(), interval - 12 month) AND NOW();

Calculate AVG of each Month excluding Months w/zeroes

I have the following working query that sums the length column/values for each month.
SELECT SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 1 THEN (tblcm.Lgth) ELSE 0 END) AS 'Jan',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 2 THEN (tblcm.Lgth) ELSE 0 END) AS 'Feb',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 3 THEN (tblcm.Lgth) ELSE 0 END) AS 'Mar',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 4 THEN (tblcm.Lgth) ELSE 0 END) AS 'Apr',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 5 THEN (tblcm.Lgth) ELSE 0 END) AS 'May',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 6 THEN (tblcm.Lgth) ELSE 0 END) AS 'Jun',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 7 THEN (tblcm.Lgth) ELSE 0 END) AS 'Jul',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 8 THEN (tblcm.Lgth) ELSE 0 END) AS 'Aug',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 9 THEN (tblcm.Lgth) ELSE 0 END) AS 'Sep',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 10 THEN (tblcm.Lgth) ELSE 0 END) AS 'Oct',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 11 THEN (tblcm.Lgth) ELSE 0 END) AS 'Nov',
SUM(CASE WHEN DATE_FORMAT(tblcm.omActCompDate, '%m') = 12 THEN (tblcm.Lgth) ELSE 0 END) AS 'Dec',
SUM(tblcm.Lgth) AS Total
giving me the following:
Jan 13050
Feb 5200
Mar 48450
Apr 34041
May 38000
Jun 0
Jul 0
Aug 0
Sep 0
Oct 0
Nov 0
Dec 0
How can I get the AVG of only the months greater than zero?
I tried: avg(nullif(tblcm.Lgth, 0)) as m_Avg but get 1825
I also tried: avg(case when tblcm.Lgth = 0 then null else tblcm.Lgth end) as m_Avg but also get 1825
I need to get 27748 (which is the SUM of Jan thru May totals, divided by 5 months)
I'm pretty sure that you'll need a subquery to do that. The following assumes that your original query is correct as posted and functions as you said. This is untested, and your probably could have included some more details in your question, so let me now if this doesn't suit your needs.
SELECT AVG(sumLgth) AS avgLgth, SUM(sumLgth) AS totalLgth,
SUM(CASE WHEN theMonth = 1 THEN (tbl.sumLgth) ELSE 0 END) AS 'Jan',
SUM(CASE WHEN theMonth = 2 THEN (tbl.sumLgth) ELSE 0 END) AS 'Feb',
...
FROM (
SELECT MONTH(omActCompDate) AS theMonth, SUM(lgth) AS sumLgth
FROM tblcm
GROUP BY MONTH(omActCompDate)
HAVING sumLgth > 0
) tbl