简体   繁体   中英

GROUP BY and LEFT JOIN with COUNT from same table

Want to count according to year, type and order by month

This is my user table :

id  type  uname      date_created
1    fac   a      2015-12-28 17:11:19
2    cs    b      2015-12-23 19:09:51
3    cs    c      2015-12-23 19:09:21
4    stu   d      2015-12-31 18:12:41
5    fac   e      2015-11-11 00:00:00
6    fac   f      2015-10-07 00:00:00

Expected result:

fac  stu  cs
 1    1    2 // month january
 1    0    0 // month octomber
 1    0    0 // month november

What I tried is:

SELECT count(u1.id) as fac, count(u2.id) as stu, count(u3.id) as cs
FROM user u
left join user u1 ON u1.faculty = 'yes' AND YEAR(u1.date_created) = 2015
left join user u2 ON u2.faculty = 'no' AND YEAR(u2.date_created) = 2015
left join user u3 ON u3.faculty = 'club_student' AND YEAR(u3.date_created) = 2015
GROUP BY MONTH(u.date_created) ORDER BY MONTH(u.date_created)

Giving me wrong result like:

fac  stu  cs
6    6    6 
6    6    6 
24   24   24

What you need is a PIVOT command to transpose rows to columns. Actually, MySQL has no support to this kind of operation, so we need to manually do it with CASE WHEN (see the SQLFiddle ):

select 
  month(date_created) as month,
  count(case when faculty = 'yes' THEN 1 END) as fac,
  count(case when faculty = 'no'  THEN 1 END) as stu,
  count(case when faculty = 'club_student' THEN 1 END) as cs
from user
where 1=1
  and date_created >= STR_TO_DATE('01-01-2015','%d-%m-%Y')
  and date_created <  STR_TO_DATE('01-01-2016','%d-%m-%Y')
group by month(date_created)
order by month(date_created)

Actually, your join syntax doesn't make sense... you are left joining three times to count the id from each of these tables... as of left join, data from these tables will just be returned when there is a join match, returning null in case of no match ... null values are not counted in the COUNT aggregation function, so your join syntax can be reduced to an INNER join syntax. But you don't even need INNER join as you are joining the same tables and you actually don't correlate any column in the FROM table with the JOIN tables.

This way, your defined filters can be reduced to WHERE filters and CASE WHEN filter as I've proposed.

Try count(distinct) :

SELECT count(distinct u1.id) as fac, count(distinct u2.id) as stu,
       count(distinct u3.id) as cs
FROM user u left join
     user u1
     ON u1.faculty = 'yes' AND YEAR(u1.date_created) = 2015 left join
     user u2
     ON u2.faculty = 'no' AND YEAR(u2.date_created) = 2015 left join
     user u3
     ON u3.faculty = 'club_student' AND YEAR(u3.date_created) = 2015
GROUP BY MONTH(u.date_created) ORDER BY MONTH(u.date_created)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM