如何在mysql查询中使用交叉表或者枢轴来动态获取月份名称?

时间:2017-07-05 14:02:18

标签: mysql

我的表名为user_plan_dtl,其中包含userid,plan description和contact date列。我想根据计划描述每个月的用户数量。并且应该仅在给定的日期范围内选择月份。 我在mysql中有数据库。

下面是表user_plan_dtl

userid        contactdate  plandesc
USR001           March       ICMA
USR003           March       ICMA
USR004           April       FTDA
USR005           April       FTDA
USR006           April       FTDA
USR007           April       ICMA
USR008           April       ICMA
USR009           May         FTDA
USR002           May         FTDA
USR001           May         ICMA

我希望输出如下:

 Count    March  April  May
 Total     2      5      3
 FTDA      0      3      2
 ICMA      2      2      1

我已尝试使用以下查询,但我将获得所有月份的输出。

select  d.Plandesc as AssignedUsers, max(d.January) as January,max(d.February) as February,max(d.March) as March,
max(d.April) as April ,max(d.May)as May,max(d.June)as June,
max(d.July) as July,max(d.August)as August,max(d.September) as September,
max(d.October)as October,max(d.November) as November ,max(d.December)as December from
(Select Plandesc,  
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='January' THEN userid END )) AS January,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='February' THEN userid END )) AS February,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='March' THEN userid END )) AS March,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='April' THEN userid END )) AS April,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='May' THEN userid END )) AS May,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='June' THEN userid END )) AS June,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='July' THEN userid END )) AS July,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='August' THEN userid END )) AS August,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='September' THEN userid END )) AS September,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='October' THEN userid END )) AS October,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='November' THEN userid END )) AS November,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='December' THEN userid END )) AS December
from user_plan_dtl 
where Plandesc in ('FTDA','ICMA')   
and DATE_FORMAT(contactdate, '%Y-%m-%d') >= '2017-01-01' and DATE_FORMAT(contactdate, '%Y-%m-%d') <= '2017-07-05'
group by  MONTHNAME(contactdate),Plandesc
union all
Select 'Total' as Plandesc,  
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='January' THEN userid END )) AS January,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='February' THEN userid END )) AS February,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='March' THEN userid END )) AS March,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='April' THEN userid END )) AS April,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='May' THEN userid END )) AS May,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='June' THEN userid END )) AS June,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='July' THEN userid END )) AS July,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='August' THEN userid END )) AS August,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='September' THEN userid END )) AS September,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='October' THEN userid END )) AS October,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='November' THEN userid END )) AS November,
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)='December' THEN userid END )) AS December
from user_plan_dtl 
where Plandesc in ('FTDA','ICMA')   
and DATE_FORMAT(contactdate, '%Y-%m-%d') >= '2017-01-01' and DATE_FORMAT(contactdate, '%Y-%m-%d') <= '2017-07-05'
group by  MONTHNAME(contactdate)
) as d group by d.Plandesc order by case when d.Plandesc = 'Total' then 0 else 1 end,d.Plandesc

任何人都可以为我提供解决方案吗?提前谢谢。

2 个答案:

答案 0 :(得分:2)

使用CONCATGROUP_CONCAT构建复杂查询。

set @sql=NULL;
select group_concat(distinct concat(
  ' COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)="',c_month,
     '" THEN userid END )) AS "',c_month,'"') separator ',') 
  from (select distinct contactdate as c_month from user_plan_dtl) t into @sql;
select @sql;

(请注意,我已将您在此处发布的数据中的contactdate用作一个月,而不是日期)

这将在变量@sql中为您提供一个字符串:

COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)="March" THEN userid END ))
    AS "March",
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)="April" THEN userid END ))
    AS "April",
COUNT(DISTINCT(CASE WHEN MONTHNAME(contactdate)="May" THEN userid END ))
    AS "May"

然后你可以操纵这个字符串

set @sql=concat('SELECT ',@sql);
select @sql;

等等。 (提示:为整个语句创建另一个变量,并将其与@sql连接起来)。最后,您必须准备并执行此sql语句:

PREPARE stmnt from @sql;
EXECUTE stmnt;
DEALLOCATE stmnt;

答案 1 :(得分:1)

我想出了这个解决方案,设置变量并使用预处理语句:

DROP TABLE IF EXISTS user_plan_temp;

SET @JanTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='January' );
SET @FebTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='February');
SET @MarTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='March');
SET @AprTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='April');
SET @MayTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='May');
SET @JunTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='June');
SET @JulTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='July');
SET @AugTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='August');
SET @SepTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='September');
SET @OctTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='October');
SET @NovTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='November');
SET @DecTotal = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc IN ('FTDA','ICMA') AND MONTHNAME(contactdate)='December');

SET @SQLq = 'CREATE TEMPORARY TABLE user_plan_temp AS (SELECT "Total" AS Count '; 
SET @SQLq = CONCAT(@SQLq, IF(@JanTotal > 0, ', @JanTotal AS January',''));
SET @SQLq = CONCAT(@SQLq, IF(@FebTotal > 0, ', @FebTotal AS February',''));
SET @SQLq = CONCAT(@SQLq, IF(@MarTotal > 0, ', @MarTotal AS March',''));
SET @SQLq = CONCAT(@SQLq, IF(@AprTotal > 0, ', @AprTotal AS April',''));
SET @SQLq = CONCAT(@SQLq, IF(@MayTotal > 0, ', @MayTotal AS May',''));
SET @SQLq = CONCAT(@SQLq, IF(@JunTotal > 0, ', @JunTotal AS June',''));
SET @SQLq = CONCAT(@SQLq, IF(@JulTotal > 0, ', @JulTotal AS July',''));
SET @SQLq = CONCAT(@SQLq, IF(@AugTotal > 0, ', @AugTotal AS August',''));
SET @SQLq = CONCAT(@SQLq, IF(@SepTotal > 0, ', @SepTotal AS September',''));
SET @SQLq = CONCAT(@SQLq, IF(@OctTotal > 0, ', @OctTotal AS October',''));
SET @SQLq = CONCAT(@SQLq, IF(@NovTotal > 0, ', @NovTotal AS November',''));
SET @SQLq = CONCAT(@SQLq, IF(@DecTotal > 0, ', @DecTotal AS December',''));
SET @SQLq = CONCAT(@SQLq, ')');
PREPARE stmt1 FROM @SQLq; 
EXECUTE stmt1; 
DEALLOCATE PREPARE stmt1; 
-- SELECT * FROM user_plan_temp;

SET @SQLq2 = 'INSERT INTO user_plan_temp VALUES("FTDA" '; 
SET @JanFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='January' );
SET @SQLq2 = CONCAT(@SQLq2, IF(@JanTotal > 0, ', @JanFTDA',''));
SET @FebFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='February');
SET @SQLq2 = CONCAT(@SQLq2, IF(@FebTotal > 0, ', @FebFTDA',''));
SET @MarFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='March');
SET @SQLq2 = CONCAT(@SQLq2, IF(@MarTotal > 0, ', @MarFTDA',''));
SET @AprFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='April');
SET @SQLq2 = CONCAT(@SQLq2, IF(@AprTotal > 0, ', @AprFTDA',''));
SET @MayFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='May');
SET @SQLq2 = CONCAT(@SQLq2, IF(@MayTotal > 0, ', @MayFTDA',''));
SET @JunFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='June');
SET @SQLq2 = CONCAT(@SQLq2, IF(@JunTotal > 0, ', @JunFTDA',''));
SET @JulFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='July');
SET @SQLq2 = CONCAT(@SQLq2, IF(@JulTotal > 0, ', @JulFTDA',''));
SET @AugFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='August');
SET @SQLq2 = CONCAT(@SQLq2, IF(@AugTotal > 0, ', @AugFTDA',''));
SET @SepFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='September');
SET @SQLq2 = CONCAT(@SQLq2, IF(@SepTotal > 0, ', @SepFTDA',''));
SET @OctFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='October');
SET @SQLq2 = CONCAT(@SQLq2, IF(@OctTotal > 0, ', @OctFTDA',''));
SET @NovFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='November');
SET @SQLq2 = CONCAT(@SQLq2, IF(@NovTotal > 0, ', @NovFTDA',''));
SET @DecFTDA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'FTDA' AND MONTHNAME(contactdate)='December');
SET @SQLq2 = CONCAT(@SQLq2, IF(@DecTotal > 0, ', @DecFTDA',''));
SET @SQLq2 = CONCAT(@SQLq2, ')');
-- SELECT @SQLq2;
PREPARE stmt2 FROM @SQLq2; 
EXECUTE stmt2; 
DEALLOCATE PREPARE stmt2; 

SET @SQLq3 = 'INSERT INTO user_plan_temp VALUES("FTDA" '; 
SET @JanICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='January' );
SET @SQLq3 = CONCAT(@SQLq3, IF(@JanTotal > 0, ', @JanICMA',''));
SET @FebICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='February');
SET @SQLq3 = CONCAT(@SQLq3, IF(@FebTotal > 0, ', @FebICMA',''));
SET @MarICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='March');
SET @SQLq3 = CONCAT(@SQLq3, IF(@MarTotal > 0, ', @MarICMA',''));
SET @AprICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='April');
SET @SQLq3 = CONCAT(@SQLq3, IF(@AprTotal > 0, ', @AprICMA',''));
SET @MayICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='May');
SET @SQLq3 = CONCAT(@SQLq3, IF(@MayTotal > 0, ', @MayICMA',''));
SET @JunICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='June');
SET @SQLq3 = CONCAT(@SQLq3, IF(@JunTotal > 0, ', @JunICMA',''));
SET @JulICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='July');
SET @SQLq3 = CONCAT(@SQLq3, IF(@JulTotal > 0, ', @JulICMA',''));
SET @AugICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='August');
SET @SQLq3 = CONCAT(@SQLq3, IF(@AugTotal > 0, ', @AugICMA',''));
SET @SepICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='September');
SET @SQLq3 = CONCAT(@SQLq3, IF(@SepTotal > 0, ', @SepICMA',''));
SET @OctICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='October');
SET @SQLq3 = CONCAT(@SQLq3, IF(@OctTotal > 0, ', @OctICMA',''));
SET @NovICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='November');
SET @SQLq3 = CONCAT(@SQLq3, IF(@NovTotal > 0, ', @NovICMA',''));
SET @DecICMA = (Select COUNT(DISTINCT(userid)) from user_plan_dtl WHERE plandesc = 'ICMA' AND MONTHNAME(contactdate)='December');
SET @SQLq3 = CONCAT(@SQLq3, IF(@DecTotal > 0, ', @DecICMA',''));
SET @SQLq3 = CONCAT(@SQLq3, ')');
PREPARE stmt3 FROM @SQLq3; 
EXECUTE stmt3; 
DEALLOCATE PREPARE stmt3; 

SELECT * FROM user_plan_temp;