Mysql Pivot表,用于每周工作日的出勤率

时间:2016-12-07 18:04:12

标签: mysql sql pivot-table mysql-workbench

对于日期间隔,我想显示学生记录的每个工作日的出勤率,记录在三个表[出勤率,学生,人物]中。 表的模式(相关字段):

Attendance Table
--------------------- 
Attendance_Identifier 
Student_Identifier 
Classroom_Identifier 
Attendance_Datetime 
Attendance_Value 
...
Student
------------------
Student_Identifier
Person_Identifier
Classroom_Identifier
...

Person
-----------------
Person_Identifier
Frist_Name
Last_Name
Gender
...

预期报告输出:

Gender    Student     Mon     Tue     Wed     Thu     Fri     WeeklyTotal
------------------------------------------------------------------------
Male     Ab Stain     2/10    3/12    1/9     1/10    0/10    7/51
Male     Pre Senter   10/10   12/12   9/9     9/10    10/10   50/51
...
Female    Al Ways     10/10   12/12   9/9     10/10   10/10   51/51
Female    Not Often   5/10    5/12    4/9     4/10    5/10    23/51
...

我还有一个函数可以从日期间隔得到特定日期的计数,比如说日期间隔@s,@ e的总周一,只需:select get_weekday(@s,@e,0).

所以我的存储过程查询是:

set @s = '2016-01-01';
set @e = '2016-12-07';
SELECT 
concat(p.Frist_Name, ' ',p.Last_Name) as Student, p.Gender
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Mon' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,0)) ELSE NULL END) AS Mon
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Tue' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,1)) ELSE NULL END) AS Tue
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Wed' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,2)) ELSE NULL END) AS Wed
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Thu' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,3)) ELSE NULL END) AS Thu
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Fri' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,4)) ELSE NULL END) AS Fri
    , SUM(COUNT(Attendance_Value)) as WeeklyTotal
FROM Attendance a JOIN Student s ON s.Student_Identifier=a.Student_Identifier 
JOIN Person p ON p.Person_Identifier=s.Person_Identifier 
WHERE date(Attendance_Datetime) BETWEEN @s AND @e AND a.Classroom_Identifier = '363'
AND (Attendance_Value = 'Present' OR Attendance_Value = 'Late') AND (p.Gender = 'Male' OR p.Gender = 'Female') 
AND DATE_FORMAT(Attendance_Datetime, '%a') !='Sat' AND DATE_FORMAT(Attendance_Datetime, '%a')!='Sun' 
GROUP BY p.Gender, Student, WeeklyTotal ORDER BY p.Gender, Student;

即使对代码进行了许多调整,每次都会出现以下组函数错误。

Error Code: 1111. Invalid use of group function

修改

基于@Solarflare的第一个建议(我不知道如何尝试第二个建议),我将查询改进为:

SELECT 
concat(p.Frist_Name, ' ',p.Last_Name) as Student, p.Gender
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Mon' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,0) ) AS Mon
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Tue' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,1) ) AS Tue
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Wed' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,2) ) AS Wed
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Thu' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,3) ) AS Thu
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Fri' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,4) ) AS Fri
    , COUNT(Attendance_Value) as WeeklyTotal
FROM Attendance a JOIN Student s ON s.Student_Identifier=a.Student_Identifier 
JOIN Person p ON p.Person_Identifier=s.Person_Identifier 
WHERE date(Attendance_Datetime) BETWEEN @s AND @e AND a.Classroom_Identifier = '363'
AND (Attendance_Value = 'Present' OR Attendance_Value = 'Late') AND (p.Gender = 'Male' OR p.Gender = 'Female') 
AND DATE_FORMAT(Attendance_Datetime, '%a') !='Sat' AND DATE_FORMAT(Attendance_Datetime, '%a')!='Sun' 
GROUP BY Student,Gender,DATE_FORMAT(Attendance_Datetime, '%a') ORDER BY p.Gender, Student,Mon DESC;

,结果如下:

enter image description here

1 个答案:

答案 0 :(得分:1)

只有一些小的东西可以让它发挥作用,试试这个:

SELECT 
  concat(p.Frist_Name, ' ',p.Last_Name) as Student, p.Gender
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 0
     then 1 END) as char), '/', get_weekday(@s,@e,0)) as Mon
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 1
     then 1 END) as char), '/', get_weekday(@s,@e,1)) as Tue
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 2
     then 1 END) as char), '/', get_weekday(@s,@e,2)) as Wed
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 3
     then 1 END) as char), '/', get_weekday(@s,@e,3)) as Thu
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 4
     then 1 END) as char), '/', get_weekday(@s,@e,4)) as Fri
  ,COUNT(Attendance_Value) as WeeklyTotal
FROM Attendance a 
JOIN Student s ON s.Student_Identifier=a.Student_Identifier 
JOIN Person p ON p.Person_Identifier=s.Person_Identifier 
WHERE date(Attendance_Datetime) BETWEEN @s AND @e 
  AND a.Classroom_Identifier = '363'
  AND (Attendance_Value = 'Present' OR Attendance_Value = 'Late') 
  AND (p.Gender = 'Male' OR p.Gender = 'Female') 
  AND weekday(Attendance_Datetime) not in (5,6)
GROUP BY Student, Gender ORDER BY p.Gender, Student, Mon DESC;

透视图使用case完成,它会在日期具有正确的工作日时计算。否则,该值为null(不是0),只有它没有计数(else null未被写入)。