Mysql GROUP BY和LEFT JOIN具有来自同一表的计数

Mysql GROUP BY和LEFT JOIN具有来自同一表的计数,mysql,count,left-join,self-join,Mysql,Count,Left Join,Self Join,要按年份、类型和订单按月计算吗 这是我的用户表: 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

要按年份、类型和订单按月计算吗

这是我的
用户表

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
预期结果:

fac  stu  cs
 1    1    2 // month january
 1    0    0 // month octomber
 1    0    0 // month november
我尝试的是:

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)
给我错误的结果,比如:

fac  stu  cs
6    6    6 
6    6    6 
24   24   24
尝试计数(不同):

尝试计数(不同):


您需要的是一个
PIVOT
命令来将行转换为列。实际上,MySQL不支持这种操作,所以我们需要在时使用
CASE手动执行(请参见):

选择
月份(创建日期)为月份,
将(教员=‘是’则1结束时的情况)计算为fac,
将(教员=否,则1结束时的情况)计算为stu,
将(教职员工=‘俱乐部学生’的情况下,则以1结尾)计算为cs
来自用户
其中1=1
和创建日期>=截止日期('01-01-2015','%d-%m-%Y')
创建日期<截止日期('01-01-2016','%d-%m-%Y'))
按月分组(创建日期)
按月订购(创建日期)
实际上,您的连接语法没有意义。。。您将加入三次以计算每个表的id。。。从左连接开始,当存在连接匹配时,这些表中的数据将仅返回,如果不匹配,则返回null。。。在
COUNT
聚合函数中不计算空值,因此可以将联接语法简化为
内部
联接语法。但是您甚至不需要
internal
join,因为您正在连接相同的表,并且实际上不需要将
FROM
表中的任何列与
join
表相关联


这样,您定义的过滤器可以简化为
WHERE
过滤器和
CASE WHEN
过滤器,正如我建议的那样。

您需要的是一个
PIVOT
命令来将行转换为列。实际上,MySQL不支持这种操作,所以我们需要在
时使用
CASE手动执行(请参见):

选择
月份(创建日期)为月份,
将(教员=‘是’则1结束时的情况)计算为fac,
将(教员=否,则1结束时的情况)计算为stu,
将(教职员工=‘俱乐部学生’的情况下,则以1结尾)计算为cs
来自用户
其中1=1
和创建日期>=截止日期('01-01-2015','%d-%m-%Y')
创建日期<截止日期('01-01-2016','%d-%m-%Y'))
按月分组(创建日期)
按月订购(创建日期)
实际上,您的连接语法没有意义。。。您将加入三次以计算每个表的id。。。从左连接开始,当存在连接匹配时,这些表中的数据将仅返回,如果不匹配,则返回null。。。在
COUNT
聚合函数中不计算空值,因此可以将联接语法简化为
内部
联接语法。但是您甚至不需要
internal
join,因为您正在连接相同的表,并且实际上不需要将
FROM
表中的任何列与
join
表相关联


通过这种方式,您定义的过滤器可以简化为
WHERE
过滤器和
CASE WHEN
过滤器,正如我所建议的那样。

您不能直接加入表本身,您需要创建虚拟表。根据您给定的期望结果集,您正在寻找一种称为
透视表的东西
。您不能直接连接表本身,您需要创建虚拟表。根据您给定的期望结果集,您正在寻找一种叫做
透视表
fac stu cs 3 1 2 3 1 2 1 2 2 2 1 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2的东西,这救了我的命。谢谢Gordon。
fac stu cs 3 1 2 3 1 2
给出这个输出计数(不同的列名)救了我的命。谢谢你,戈登。
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)
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)